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
|
||||
import thread
|
||||
import sys
|
||||
|
||||
from twisted.internet import reactor
|
||||
from syncplay import client
|
||||
from syncplay.players import mpc
|
||||
|
||||
|
||||
import common_functions
|
||||
from syncplay import utils
|
||||
|
||||
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))
|
||||
thread.start_new_thread(common_functions.stdin_thread, (manager,))
|
||||
thread.start_new_thread(utils.stdin_thread, (manager,))
|
||||
manager.start()
|
||||
|
||||
@ -6,13 +6,12 @@ from twisted.internet import reactor
|
||||
from syncplay import client
|
||||
from syncplay.players import mplayer
|
||||
|
||||
|
||||
import common_functions
|
||||
from syncplay import utils
|
||||
|
||||
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'))
|
||||
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()
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ class SyncClientProtocol(CommandProtocol):
|
||||
def __init__(self, manager):
|
||||
CommandProtocol.__init__(self)
|
||||
self.manager = manager
|
||||
|
||||
|
||||
def connectionMade(self):
|
||||
self.send_message('iam', self.manager.name)
|
||||
self.manager.init_protocol(self)
|
||||
@ -35,10 +35,13 @@ class SyncClientProtocol(CommandProtocol):
|
||||
@arg_count(1)
|
||||
def handle_init_hello(self, args):
|
||||
print 'Connected as', args[0]
|
||||
self.manager.name = args[0]
|
||||
self.change_state('connected')
|
||||
self.send_list()
|
||||
self.manager.schedule_send_status()
|
||||
|
||||
@arg_count(1, 2)
|
||||
def handle_init_present(self, args):
|
||||
def handle_connected_present(self, args):
|
||||
if len(args) == 2:
|
||||
who, what = args
|
||||
else:
|
||||
@ -90,6 +93,8 @@ class SyncClientProtocol(CommandProtocol):
|
||||
def handle_connected_left(self, args):
|
||||
print '%s left' % args[0]
|
||||
|
||||
def send_list(self):
|
||||
self.send_message('list')
|
||||
|
||||
def send_state(self, counter, ctime, paused, position):
|
||||
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(
|
||||
init = dict(
|
||||
present = 'handle_init_present',
|
||||
hello = 'handle_init_hello',
|
||||
),
|
||||
connected = dict(
|
||||
list = 'handle_connected_list',
|
||||
present = 'handle_connected_present',
|
||||
state = 'handle_connected_state',
|
||||
seek = 'handle_connected_seek',
|
||||
ping = 'handle_connected_ping',
|
||||
@ -225,8 +231,6 @@ class Manager(object):
|
||||
|
||||
def init_protocol(self, protocol):
|
||||
self.protocol = protocol
|
||||
self.schedule_send_status()
|
||||
self.send_filename()
|
||||
if self.make_player:
|
||||
self.make_player(self)
|
||||
self.make_player = None
|
||||
@ -278,7 +282,7 @@ class Manager(object):
|
||||
if self.protocol and 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
|
||||
|
||||
if seek_type == 's':
|
||||
@ -302,9 +306,16 @@ class Manager(object):
|
||||
|
||||
def execute_command(self, data):
|
||||
RE_SEEK = re.compile("^(s[+s]?) ?(-?\d+)?([^0-9](\d+))?$")
|
||||
RE_ROOM = re.compile("^room( (\w+))?")
|
||||
matched_seek = RE_SEEK.match(data)
|
||||
matched_room = RE_ROOM.match(data)
|
||||
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":
|
||||
self.counter += 1
|
||||
tmp_pos = self.player_position
|
||||
@ -328,12 +339,12 @@ class Manager(object):
|
||||
if old_paused != paused and self.global_paused != paused:
|
||||
self.send_status(True)
|
||||
if paused:
|
||||
print "You have paused"
|
||||
print '%s paused' % self.name
|
||||
if(diff > 0):
|
||||
self.player.set_position(self.get_global_position())
|
||||
self.ask_player()
|
||||
else:
|
||||
print "You have resumed"
|
||||
print '%s resumed' % self.name
|
||||
|
||||
if not (self.global_paused or self.seek_sent_wait):
|
||||
if (0.4 if self.player_speed_fix else 0.6) <= diff <= 4:
|
||||
|
||||
@ -43,13 +43,14 @@ class CommandProtocol(LineReceiver):
|
||||
line = line.strip()
|
||||
if not line:
|
||||
return
|
||||
#print '>>>', line
|
||||
|
||||
args = split_args(line)
|
||||
if not args:
|
||||
self.drop_with_error('Malformed line')
|
||||
return
|
||||
command = args.pop(0)
|
||||
|
||||
if command not in ['ping', 'pong']:
|
||||
print '>>>', line
|
||||
if command == 'error':
|
||||
self.handle_error(args)
|
||||
return
|
||||
@ -61,7 +62,6 @@ class CommandProtocol(LineReceiver):
|
||||
if not handler:
|
||||
self.drop_with_error('Unknown command: `%s`' % command)
|
||||
return # TODO log it too
|
||||
|
||||
handler(args)
|
||||
|
||||
def handle_error(self, args):
|
||||
@ -74,7 +74,8 @@ class CommandProtocol(LineReceiver):
|
||||
|
||||
def send_message(self, *args):
|
||||
line = join_args(args)
|
||||
#print '<<<', line
|
||||
if args[0] not in ['ping', 'pong']:
|
||||
print '<<<', line
|
||||
self.sendLine(line)
|
||||
|
||||
def drop(self):
|
||||
@ -143,7 +144,7 @@ class BodyGetter(Protocol):
|
||||
if self.length > 0:
|
||||
data = data[:self.length]
|
||||
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):
|
||||
self.callback(self.body.getvalue())
|
||||
|
||||
@ -17,7 +17,6 @@ from .utils import parse_state
|
||||
random.seed()
|
||||
|
||||
CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
|
||||
RE_NAME = re.compile('^(.*?)(\d*)$')
|
||||
|
||||
def random_chars():
|
||||
return ''.join(random.choice(CHARS) for _ in xrange(10))
|
||||
@ -35,13 +34,18 @@ class SyncServerProtocol(CommandProtocol):
|
||||
if not len(args) == 1:
|
||||
self.drop_with_error('Invalid arguments')
|
||||
return
|
||||
name = args[0].strip()
|
||||
if not args:
|
||||
name = re.sub('[^\w]','',args[0])
|
||||
if not name:
|
||||
self.drop_with_error('Invalid nickname')
|
||||
return
|
||||
self.factory.add_watcher(self, args[0])
|
||||
self.factory.add_watcher(self, name)
|
||||
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)
|
||||
def handle_connected_state(self, args):
|
||||
args = parse_state(args)
|
||||
@ -52,7 +56,12 @@ class SyncServerProtocol(CommandProtocol):
|
||||
counter, ctime, paused, position, _ = args
|
||||
|
||||
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)
|
||||
def handle_connected_seek(self, args):
|
||||
counter, ctime, position = args
|
||||
@ -130,6 +139,8 @@ class SyncServerProtocol(CommandProtocol):
|
||||
iam = 'handle_init_iam',
|
||||
),
|
||||
connected = dict(
|
||||
room = 'handle_connected_room',
|
||||
list = 'handle_connected_list',
|
||||
state = 'handle_connected_state',
|
||||
seek = 'handle_connected_seek',
|
||||
pong = 'handle_connected_pong',
|
||||
@ -152,6 +163,7 @@ class WatcherInfo(object):
|
||||
self.last_update = None
|
||||
self.last_update_sent = None
|
||||
|
||||
self.room = 'default'
|
||||
self.ping = None
|
||||
self.time_offset = 0
|
||||
self.time_offset_data = []
|
||||
@ -176,25 +188,16 @@ class SyncFactory(Factory):
|
||||
return SyncServerProtocol(self)
|
||||
|
||||
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:
|
||||
m = RE_NAME.match(name)
|
||||
name, number = m.group(1), m.group(2)
|
||||
if number:
|
||||
number = str(int(number)+1)
|
||||
else:
|
||||
number = '1'
|
||||
name += number
|
||||
|
||||
name += '_'
|
||||
|
||||
watcher = WatcherInfo(watcher_proto, name)
|
||||
if self.watchers:
|
||||
watcher.max_position = min(w.max_position for w in self.watchers.itervalues())
|
||||
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)
|
||||
self.send_state_to(watcher)
|
||||
self.send_ping_to(watcher)
|
||||
@ -363,4 +366,15 @@ class SyncFactory(Factory):
|
||||
for receiver in self.watchers.itervalues():
|
||||
if receiver != watcher:
|
||||
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)
|
||||
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