Code a bit more readable, protocol standarized a bit, added better name

handling on server
This commit is contained in:
Uriziel 2012-06-23 15:30:16 +02:00
parent c5a33875b3
commit f6e6cad1a6
7 changed files with 120 additions and 96 deletions

View File

@ -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

View File

@ -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()

View File

@ -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()

View File

@ -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:

View File

@ -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())

View File

@ -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)

View File

@ -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