Code a bit more readable, protocol standarized a bit, added better name
handling on server
This commit is contained in:
parent
c5a33875b3
commit
f6e6cad1a6
@ -1,53 +0,0 @@
|
|||||||
import sys, os
|
|
||||||
import ConfigParser
|
|
||||||
import argparse
|
|
||||||
|
|
||||||
def stdin_thread(manag):
|
|
||||||
try:
|
|
||||||
fd = sys.stdin.fileno()
|
|
||||||
while True:
|
|
||||||
data = os.read(fd, 1024)
|
|
||||||
if not data:
|
|
||||||
break
|
|
||||||
manag.execute_command(data.rstrip('\n\r'))
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def get_configuration():
|
|
||||||
parser = argparse.ArgumentParser(description='Synchronize multiple players over the web.',
|
|
||||||
epilog='If no options supplied config values will be used')
|
|
||||||
parser.add_argument('host', metavar='host', type=str, nargs='?', help='server\'s address')
|
|
||||||
parser.add_argument('name', metavar='name', type=str, nargs='?', help='desired username')
|
|
||||||
parser.add_argument('args', metavar='opts', type=str, nargs='*', help='player options, if you need to pass options starting with - prepend them with single \'--\' argument')
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
config = ConfigParser.RawConfigParser(allow_no_value=True)
|
|
||||||
config.read(os.path.join(os.path.dirname(__file__), 'syncplay.ini'))
|
|
||||||
try:
|
|
||||||
if(args.host == None):
|
|
||||||
host = config.get('sync', 'host')
|
|
||||||
else:
|
|
||||||
host = args.host
|
|
||||||
if(args.name == None):
|
|
||||||
name = config.get('sync', 'name')
|
|
||||||
else:
|
|
||||||
name = args.name
|
|
||||||
except ConfigParser.NoSectionError:
|
|
||||||
sys.exit("Host or username not specified")
|
|
||||||
|
|
||||||
with open('syncplay.ini', 'wb') as configfile:
|
|
||||||
try:
|
|
||||||
config.set('sync', 'host' ,host)
|
|
||||||
config.set('sync', 'name' ,name)
|
|
||||||
except ConfigParser.NoSectionError:
|
|
||||||
config.add_section('sync')
|
|
||||||
config.set('sync', 'host' ,host)
|
|
||||||
config.set('sync', 'name' ,name)
|
|
||||||
config.write(configfile)
|
|
||||||
|
|
||||||
if ':' in host:
|
|
||||||
host, port = host.split(':', 1)
|
|
||||||
port = int(port)
|
|
||||||
else:
|
|
||||||
port = 8999
|
|
||||||
return host,port,name,args.args
|
|
||||||
@ -1,16 +1,14 @@
|
|||||||
#coding:utf8
|
#coding:utf8
|
||||||
import thread
|
import thread
|
||||||
import sys
|
|
||||||
|
|
||||||
from twisted.internet import reactor
|
from twisted.internet import reactor
|
||||||
from syncplay import client
|
from syncplay import client
|
||||||
from syncplay.players import mpc
|
from syncplay.players import mpc
|
||||||
|
|
||||||
|
from syncplay import utils
|
||||||
import common_functions
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
host, port, name, args = common_functions.get_configuration()
|
host, port, name, args = utils.get_configuration()
|
||||||
manager = client.Manager(host, port, name, lambda m: mpc.run_mpc(m))
|
manager = client.Manager(host, port, name, lambda m: mpc.run_mpc(m))
|
||||||
thread.start_new_thread(common_functions.stdin_thread, (manager,))
|
thread.start_new_thread(utils.stdin_thread, (manager,))
|
||||||
manager.start()
|
manager.start()
|
||||||
|
|||||||
@ -6,13 +6,12 @@ from twisted.internet import reactor
|
|||||||
from syncplay import client
|
from syncplay import client
|
||||||
from syncplay.players import mplayer
|
from syncplay.players import mplayer
|
||||||
|
|
||||||
|
from syncplay import utils
|
||||||
import common_functions
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
host, port, name, args = common_functions.get_configuration()
|
host, port, name, args = utils.get_configuration()
|
||||||
args.extend(('-slave', '-msglevel', 'all=1:global=4'))
|
args.extend(('-slave', '-msglevel', 'all=1:global=4'))
|
||||||
manager = client.Manager(host, port, name, lambda m: mplayer.run_mplayer(m, 'mplayer', args))
|
manager = client.Manager(host, port, name, lambda m: mplayer.run_mplayer(m, 'mplayer', args))
|
||||||
thread.start_new_thread(common_functions.stdin_thread, (manager,))
|
thread.start_new_thread(utils.stdin_thread, (manager,))
|
||||||
manager.start()
|
manager.start()
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,7 @@ class SyncClientProtocol(CommandProtocol):
|
|||||||
def __init__(self, manager):
|
def __init__(self, manager):
|
||||||
CommandProtocol.__init__(self)
|
CommandProtocol.__init__(self)
|
||||||
self.manager = manager
|
self.manager = manager
|
||||||
|
|
||||||
def connectionMade(self):
|
def connectionMade(self):
|
||||||
self.send_message('iam', self.manager.name)
|
self.send_message('iam', self.manager.name)
|
||||||
self.manager.init_protocol(self)
|
self.manager.init_protocol(self)
|
||||||
@ -35,10 +35,13 @@ class SyncClientProtocol(CommandProtocol):
|
|||||||
@arg_count(1)
|
@arg_count(1)
|
||||||
def handle_init_hello(self, args):
|
def handle_init_hello(self, args):
|
||||||
print 'Connected as', args[0]
|
print 'Connected as', args[0]
|
||||||
|
self.manager.name = args[0]
|
||||||
self.change_state('connected')
|
self.change_state('connected')
|
||||||
|
self.send_list()
|
||||||
|
self.manager.schedule_send_status()
|
||||||
|
|
||||||
@arg_count(1, 2)
|
@arg_count(1, 2)
|
||||||
def handle_init_present(self, args):
|
def handle_connected_present(self, args):
|
||||||
if len(args) == 2:
|
if len(args) == 2:
|
||||||
who, what = args
|
who, what = args
|
||||||
else:
|
else:
|
||||||
@ -90,6 +93,8 @@ class SyncClientProtocol(CommandProtocol):
|
|||||||
def handle_connected_left(self, args):
|
def handle_connected_left(self, args):
|
||||||
print '%s left' % args[0]
|
print '%s left' % args[0]
|
||||||
|
|
||||||
|
def send_list(self):
|
||||||
|
self.send_message('list')
|
||||||
|
|
||||||
def send_state(self, counter, ctime, paused, position):
|
def send_state(self, counter, ctime, paused, position):
|
||||||
self.send_message('state', counter, int(ctime*1000), ('paused' if paused else 'playing'), int(position*1000))
|
self.send_message('state', counter, int(ctime*1000), ('paused' if paused else 'playing'), int(position*1000))
|
||||||
@ -102,10 +107,11 @@ class SyncClientProtocol(CommandProtocol):
|
|||||||
|
|
||||||
states = dict(
|
states = dict(
|
||||||
init = dict(
|
init = dict(
|
||||||
present = 'handle_init_present',
|
|
||||||
hello = 'handle_init_hello',
|
hello = 'handle_init_hello',
|
||||||
),
|
),
|
||||||
connected = dict(
|
connected = dict(
|
||||||
|
list = 'handle_connected_list',
|
||||||
|
present = 'handle_connected_present',
|
||||||
state = 'handle_connected_state',
|
state = 'handle_connected_state',
|
||||||
seek = 'handle_connected_seek',
|
seek = 'handle_connected_seek',
|
||||||
ping = 'handle_connected_ping',
|
ping = 'handle_connected_ping',
|
||||||
@ -225,8 +231,6 @@ class Manager(object):
|
|||||||
|
|
||||||
def init_protocol(self, protocol):
|
def init_protocol(self, protocol):
|
||||||
self.protocol = protocol
|
self.protocol = protocol
|
||||||
self.schedule_send_status()
|
|
||||||
self.send_filename()
|
|
||||||
if self.make_player:
|
if self.make_player:
|
||||||
self.make_player(self)
|
self.make_player(self)
|
||||||
self.make_player = None
|
self.make_player = None
|
||||||
@ -278,7 +282,7 @@ class Manager(object):
|
|||||||
if self.protocol and self.player_filename:
|
if self.protocol and self.player_filename:
|
||||||
self.protocol.send_playing(self.player_filename)
|
self.protocol.send_playing(self.player_filename)
|
||||||
|
|
||||||
def exectue_seek_cmd(self, seek_type, minutes, seconds):
|
def __exectue_seek_cmd(self, seek_type, minutes, seconds):
|
||||||
self.player_position_before_last_seek = self.player_position
|
self.player_position_before_last_seek = self.player_position
|
||||||
|
|
||||||
if seek_type == 's':
|
if seek_type == 's':
|
||||||
@ -302,9 +306,16 @@ class Manager(object):
|
|||||||
|
|
||||||
def execute_command(self, data):
|
def execute_command(self, data):
|
||||||
RE_SEEK = re.compile("^(s[+s]?) ?(-?\d+)?([^0-9](\d+))?$")
|
RE_SEEK = re.compile("^(s[+s]?) ?(-?\d+)?([^0-9](\d+))?$")
|
||||||
|
RE_ROOM = re.compile("^room( (\w+))?")
|
||||||
matched_seek = RE_SEEK.match(data)
|
matched_seek = RE_SEEK.match(data)
|
||||||
|
matched_room = RE_ROOM.match(data)
|
||||||
if matched_seek :
|
if matched_seek :
|
||||||
self.exectue_seek_cmd(matched_seek.group(1), matched_seek.group(2), matched_seek.group(4))
|
self.__exectue_seek_cmd(matched_seek.group(1), matched_seek.group(2), matched_seek.group(4))
|
||||||
|
elif matched_room:
|
||||||
|
room = matched_room.group(2)
|
||||||
|
if room == None:
|
||||||
|
room = 'default'
|
||||||
|
self.protocol.send_room(room)
|
||||||
elif data == "r":
|
elif data == "r":
|
||||||
self.counter += 1
|
self.counter += 1
|
||||||
tmp_pos = self.player_position
|
tmp_pos = self.player_position
|
||||||
@ -328,12 +339,12 @@ class Manager(object):
|
|||||||
if old_paused != paused and self.global_paused != paused:
|
if old_paused != paused and self.global_paused != paused:
|
||||||
self.send_status(True)
|
self.send_status(True)
|
||||||
if paused:
|
if paused:
|
||||||
print "You have paused"
|
print '%s paused' % self.name
|
||||||
if(diff > 0):
|
if(diff > 0):
|
||||||
self.player.set_position(self.get_global_position())
|
self.player.set_position(self.get_global_position())
|
||||||
self.ask_player()
|
self.ask_player()
|
||||||
else:
|
else:
|
||||||
print "You have resumed"
|
print '%s resumed' % self.name
|
||||||
|
|
||||||
if not (self.global_paused or self.seek_sent_wait):
|
if not (self.global_paused or self.seek_sent_wait):
|
||||||
if (0.4 if self.player_speed_fix else 0.6) <= diff <= 4:
|
if (0.4 if self.player_speed_fix else 0.6) <= diff <= 4:
|
||||||
|
|||||||
@ -43,13 +43,14 @@ class CommandProtocol(LineReceiver):
|
|||||||
line = line.strip()
|
line = line.strip()
|
||||||
if not line:
|
if not line:
|
||||||
return
|
return
|
||||||
#print '>>>', line
|
|
||||||
args = split_args(line)
|
args = split_args(line)
|
||||||
if not args:
|
if not args:
|
||||||
self.drop_with_error('Malformed line')
|
self.drop_with_error('Malformed line')
|
||||||
return
|
return
|
||||||
command = args.pop(0)
|
command = args.pop(0)
|
||||||
|
if command not in ['ping', 'pong']:
|
||||||
|
print '>>>', line
|
||||||
if command == 'error':
|
if command == 'error':
|
||||||
self.handle_error(args)
|
self.handle_error(args)
|
||||||
return
|
return
|
||||||
@ -61,7 +62,6 @@ class CommandProtocol(LineReceiver):
|
|||||||
if not handler:
|
if not handler:
|
||||||
self.drop_with_error('Unknown command: `%s`' % command)
|
self.drop_with_error('Unknown command: `%s`' % command)
|
||||||
return # TODO log it too
|
return # TODO log it too
|
||||||
|
|
||||||
handler(args)
|
handler(args)
|
||||||
|
|
||||||
def handle_error(self, args):
|
def handle_error(self, args):
|
||||||
@ -74,7 +74,8 @@ class CommandProtocol(LineReceiver):
|
|||||||
|
|
||||||
def send_message(self, *args):
|
def send_message(self, *args):
|
||||||
line = join_args(args)
|
line = join_args(args)
|
||||||
#print '<<<', line
|
if args[0] not in ['ping', 'pong']:
|
||||||
|
print '<<<', line
|
||||||
self.sendLine(line)
|
self.sendLine(line)
|
||||||
|
|
||||||
def drop(self):
|
def drop(self):
|
||||||
@ -143,7 +144,7 @@ class BodyGetter(Protocol):
|
|||||||
if self.length > 0:
|
if self.length > 0:
|
||||||
data = data[:self.length]
|
data = data[:self.length]
|
||||||
self.body.write(data)
|
self.body.write(data)
|
||||||
self.length -= len(length)
|
self.length -= self.body.len #TODO: need fixing! chuj wie jak to działa :D
|
||||||
|
|
||||||
def connectionLost(self, reason):
|
def connectionLost(self, reason):
|
||||||
self.callback(self.body.getvalue())
|
self.callback(self.body.getvalue())
|
||||||
|
|||||||
@ -17,7 +17,6 @@ from .utils import parse_state
|
|||||||
random.seed()
|
random.seed()
|
||||||
|
|
||||||
CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
|
CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
|
||||||
RE_NAME = re.compile('^(.*?)(\d*)$')
|
|
||||||
|
|
||||||
def random_chars():
|
def random_chars():
|
||||||
return ''.join(random.choice(CHARS) for _ in xrange(10))
|
return ''.join(random.choice(CHARS) for _ in xrange(10))
|
||||||
@ -35,13 +34,18 @@ class SyncServerProtocol(CommandProtocol):
|
|||||||
if not len(args) == 1:
|
if not len(args) == 1:
|
||||||
self.drop_with_error('Invalid arguments')
|
self.drop_with_error('Invalid arguments')
|
||||||
return
|
return
|
||||||
name = args[0].strip()
|
name = re.sub('[^\w]','',args[0])
|
||||||
if not args:
|
if not name:
|
||||||
self.drop_with_error('Invalid nickname')
|
self.drop_with_error('Invalid nickname')
|
||||||
return
|
return
|
||||||
self.factory.add_watcher(self, args[0])
|
self.factory.add_watcher(self, name)
|
||||||
self.change_state('connected')
|
self.change_state('connected')
|
||||||
|
|
||||||
|
@arg_count(1)
|
||||||
|
def handle_connected_room(self, args):
|
||||||
|
watcher = self.factory.watchers.get(self)
|
||||||
|
watcher.room = args[0]
|
||||||
|
|
||||||
@arg_count(4)
|
@arg_count(4)
|
||||||
def handle_connected_state(self, args):
|
def handle_connected_state(self, args):
|
||||||
args = parse_state(args)
|
args = parse_state(args)
|
||||||
@ -52,7 +56,12 @@ class SyncServerProtocol(CommandProtocol):
|
|||||||
counter, ctime, paused, position, _ = args
|
counter, ctime, paused, position, _ = args
|
||||||
|
|
||||||
self.factory.update_state(self, counter, ctime, paused, position)
|
self.factory.update_state(self, counter, ctime, paused, position)
|
||||||
|
|
||||||
|
@arg_count(0)
|
||||||
|
def handle_connected_list(self, args):
|
||||||
|
watcher = self.factory.watchers.get(self)
|
||||||
|
self.factory.broadcast(watcher, lambda receiver: self.send_present(receiver.name, receiver.filename))
|
||||||
|
|
||||||
@arg_count(3)
|
@arg_count(3)
|
||||||
def handle_connected_seek(self, args):
|
def handle_connected_seek(self, args):
|
||||||
counter, ctime, position = args
|
counter, ctime, position = args
|
||||||
@ -130,6 +139,8 @@ class SyncServerProtocol(CommandProtocol):
|
|||||||
iam = 'handle_init_iam',
|
iam = 'handle_init_iam',
|
||||||
),
|
),
|
||||||
connected = dict(
|
connected = dict(
|
||||||
|
room = 'handle_connected_room',
|
||||||
|
list = 'handle_connected_list',
|
||||||
state = 'handle_connected_state',
|
state = 'handle_connected_state',
|
||||||
seek = 'handle_connected_seek',
|
seek = 'handle_connected_seek',
|
||||||
pong = 'handle_connected_pong',
|
pong = 'handle_connected_pong',
|
||||||
@ -152,6 +163,7 @@ class WatcherInfo(object):
|
|||||||
self.last_update = None
|
self.last_update = None
|
||||||
self.last_update_sent = None
|
self.last_update_sent = None
|
||||||
|
|
||||||
|
self.room = 'default'
|
||||||
self.ping = None
|
self.ping = None
|
||||||
self.time_offset = 0
|
self.time_offset = 0
|
||||||
self.time_offset_data = []
|
self.time_offset_data = []
|
||||||
@ -176,25 +188,16 @@ class SyncFactory(Factory):
|
|||||||
return SyncServerProtocol(self)
|
return SyncServerProtocol(self)
|
||||||
|
|
||||||
def add_watcher(self, watcher_proto, name):
|
def add_watcher(self, watcher_proto, name):
|
||||||
allnames = (watcher.name.lower() for watcher in self.watchers.itervalues())
|
allnames = []
|
||||||
|
for watcher in self.watchers.itervalues():
|
||||||
|
allnames.append(watcher.name.lower())
|
||||||
while name.lower() in allnames:
|
while name.lower() in allnames:
|
||||||
m = RE_NAME.match(name)
|
name += '_'
|
||||||
name, number = m.group(1), m.group(2)
|
|
||||||
if number:
|
|
||||||
number = str(int(number)+1)
|
|
||||||
else:
|
|
||||||
number = '1'
|
|
||||||
name += number
|
|
||||||
|
|
||||||
watcher = WatcherInfo(watcher_proto, name)
|
watcher = WatcherInfo(watcher_proto, name)
|
||||||
if self.watchers:
|
if self.watchers:
|
||||||
watcher.max_position = min(w.max_position for w in self.watchers.itervalues())
|
watcher.max_position = min(w.max_position for w in self.watchers.itervalues())
|
||||||
self.watchers[watcher_proto] = watcher
|
self.watchers[watcher_proto] = watcher
|
||||||
for receiver in self.watchers.itervalues():
|
|
||||||
if receiver == watcher:
|
|
||||||
continue
|
|
||||||
receiver.watcher_proto.send_joined(name)
|
|
||||||
watcher_proto.send_present(receiver.name, receiver.filename)
|
|
||||||
watcher_proto.send_hello(name)
|
watcher_proto.send_hello(name)
|
||||||
self.send_state_to(watcher)
|
self.send_state_to(watcher)
|
||||||
self.send_ping_to(watcher)
|
self.send_ping_to(watcher)
|
||||||
@ -363,4 +366,15 @@ class SyncFactory(Factory):
|
|||||||
for receiver in self.watchers.itervalues():
|
for receiver in self.watchers.itervalues():
|
||||||
if receiver != watcher:
|
if receiver != watcher:
|
||||||
receiver.watcher_proto.send_playing(watcher.name, filename)
|
receiver.watcher_proto.send_playing(watcher.name, filename)
|
||||||
|
|
||||||
|
def broadcast_room(self, sender, what):
|
||||||
|
for receiver in self.watchers.itervalues():
|
||||||
|
if receiver.room == sender.room and receiver != sender:
|
||||||
|
print receiver.room, sender.room
|
||||||
|
what(receiver)
|
||||||
|
|
||||||
|
def broadcast(self, sender, what):
|
||||||
|
for receiver in self.watchers.itervalues():
|
||||||
|
if receiver != sender:
|
||||||
|
for receiver in self.watchers.itervalues():
|
||||||
|
what(receiver)
|
||||||
|
|||||||
@ -85,3 +85,57 @@ def format_time(value):
|
|||||||
hours, minutes = divmod(minutes, 60)
|
hours, minutes = divmod(minutes, 60)
|
||||||
return '%02d:%02d:%02d.%02d' % (hours, minutes, seconds, mseconds)
|
return '%02d:%02d:%02d.%02d' % (hours, minutes, seconds, mseconds)
|
||||||
|
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import ConfigParser
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
def stdin_thread(manager):
|
||||||
|
try:
|
||||||
|
fd = sys.stdin.fileno()
|
||||||
|
while True:
|
||||||
|
data = os.read(fd, 1024)
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
manager.execute_command(data.rstrip('\n\r'))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_configuration():
|
||||||
|
parser = argparse.ArgumentParser(description='Synchronize multiple players over the web.',
|
||||||
|
epilog='If no options supplied config values will be used')
|
||||||
|
parser.add_argument('host', metavar='host', type=str, nargs='?', help='server\'s address')
|
||||||
|
parser.add_argument('name', metavar='name', type=str, nargs='?', help='desired username')
|
||||||
|
parser.add_argument('args', metavar='opts', type=str, nargs='*', help='player options, if you need to pass options starting with - prepend them with single \'--\' argument')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
config = ConfigParser.RawConfigParser(allow_no_value=True)
|
||||||
|
config.read(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'syncplay.ini'))
|
||||||
|
try:
|
||||||
|
if(args.host == None):
|
||||||
|
host = config.get('sync', 'host')
|
||||||
|
else:
|
||||||
|
host = args.host
|
||||||
|
if(args.name == None):
|
||||||
|
name = config.get('sync', 'name')
|
||||||
|
else:
|
||||||
|
name = args.name
|
||||||
|
except ConfigParser.NoSectionError:
|
||||||
|
sys.exit("Host or username not specified")
|
||||||
|
|
||||||
|
with open(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'syncplay.ini'), 'wb') as configfile:
|
||||||
|
try:
|
||||||
|
config.set('sync', 'host' ,host)
|
||||||
|
config.set('sync', 'name' ,name)
|
||||||
|
except ConfigParser.NoSectionError:
|
||||||
|
config.add_section('sync')
|
||||||
|
config.set('sync', 'host' ,host)
|
||||||
|
config.set('sync', 'name' ,name)
|
||||||
|
config.write(configfile)
|
||||||
|
|
||||||
|
if ':' in host:
|
||||||
|
host, port = host.split(':', 1)
|
||||||
|
port = int(port)
|
||||||
|
else:
|
||||||
|
port = 8999
|
||||||
|
return host,port,name,args.args
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user