class Client(object, LineOnlyReceiver): state = None fields = () def __init__(self, app): self.app = app def connectionMade(self): self.logger = TerminalLogger(self.app) self.sendLine('REGISTER {}'.format(self.__class__.__name__.lower())) def connectionLost(self, reason=ConnectionDone): if reason != ConnectionDone: self.logger.error('Connection lost!') del self.app.port del self.app.factory self.app.state = AppState.offline if hasattr(self.app, 'loop'): self.app.loop.stop() del self.app.loop def lineReceived(self, line): self.logger.log(line) args = line.split() if not self.state: if args[0] == 'REGISTERACK': self.handle_REGISTERACK(args) self.app.loop = LoopingCall(self.loop) self.app.loop.start(1) else: self.handle_unknown(line) else: if args[0] in ('GIVEN', 'TAKEN', 'SET'): getattr(self, 'handle_' + args[0])(args) else: self.handle_unknown(line) def handle_REGISTERACK(self, args): raise NotImplementedError def handle_GIVEN(self, args): raise NotImplementedError def handle_TAKEN(self, args): raise NotImplementedError def handle_SET(self, args): if args[1] in self.fields: setattr(self, args[1], type(getattr(self, args[1]))(args[2])) else: self.logger.error('Field \'{}\' not found!', args[1]) def handle_unknown(self, line): self.logger.warning('Received unhandled message: {}', line) def loop(self): self.sendLine('STATUS {} {}'.format( self.state.name, ' '.join([str(getattr(self, field)) for field in self.fields]) ))
class Server(LineOnlyReceiver): state = None pending = False marks = ['!', 'X', '^', '>', 'v'] def __init__(self, app): self.app = app def connectionMade(self): self.logger = TerminalLogger(self.app) def connectionLost(self, reason=ConnectionDone): self.logger.log('Client disconnected! {}', reason) if self in self.app.clients: self.app.clients.remove(self) def lineReceived(self, line): args = line.split() if not self.state: if args[0] == 'REGISTER': self.handle_REGISTER(args) else: self.handle_unknown(line) else: if args[0] == 'STATUS': self.handle_STATUS(args) else: self.handle_unknown(line) def handle_REGISTER(self, args): if args[1] in ConnectCommand.client_types: self.type = ConnectCommand.client_types[args[1]] self.state = ClientState.registered self.app.clients.append(self) self.sendLine('REGISTERACK OK') self.logger.log('New {} client!', self.type.__class__.__name__) else: self.sendLine('REGISTERACK UNKNOWN_CLIENT_TYPE') self.logger.error('Unknown client type {}!', args[1]) self.transport.loseConnection() def handle_STATUS(self, args): self.state = ClientState[args[1]] self.pending = False for key, field in enumerate(self.type.fields, start=2): setattr(self, field, type(getattr(self.type, field))(args[key])) def handle_unknown(self, line): self.logger.warning('Received unhandled message: {}', line) @staticmethod def loop(app, user_data): clients = ['[{}][{}]{}:{} {}'.format( i, Server.marks[client.state.value], client.type.__name__, client.state.name, ' '.join(['{}:{}'.format(field, str(getattr(client, field))) for field in client.type.fields]) ) for i, client in enumerate(app.clients)] app.header.set_text('\n'.join(clients) if app.clients else '[-][-]No clients') for client_curr, client_next in pairwise(app.clients): if (client_curr.state == ClientState.ready_give) and not client_curr.pending: if client_next: if (client_next.state == ClientState.ready_take) and not client_next.pending: client_curr.sendLine('TAKEN') client_next.sendLine('GIVEN') client_curr.pending = True client_next.pending = True else: client_curr.sendLine('TAKEN') client_curr.pending = True app.loop = app.set_alarm_in(1, Server.loop)