Mercurial > zrpn
changeset 103:616421834e19
updated pygnetic, added discovery server handling
| author | Szymon Wróblewski <bluex0@gmail.com> |
|---|---|
| date | Fri, 07 Sep 2012 02:22:10 +0200 |
| parents | 361178f45eb6 |
| children | 86f4b5469bd8 |
| files | zrpn/discovery_server.py zrpn/main.py zrpn/pygnetic/discovery.py zrpn/pygnetic/message.py zrpn/server.py |
| diffstat | 5 files changed, 115 insertions(+), 27 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/zrpn/discovery_server.py Fri Sep 07 02:22:10 2012 +0200 @@ -0,0 +1,26 @@ +import logging +import pygnetic +from pygnetic.discovery import DiscoveryServer + +_logger = logging.getLogger(__name__) + +if __name__ == '__main__': + import argparse + parser = argparse.ArgumentParser(description='Server discovery service.') + parser.add_argument('-i', '--host', type=str, default='', + help='Server host IP') + parser.add_argument('-p', '--port', type=int, default=5000, + help='Server port') + parser.add_argument('-d', '--debug', action='store_true', + help='Enable debugging') + args = parser.parse_args() + if args.debug: + pygnetic.init(logging_lvl=logging.DEBUG) + else: + pygnetic.init() + _logger.info('Server started (Use Control-C to exit)') + try: + DiscoveryServer(args.host, args.port).serve_forever() + except KeyboardInterrupt: + pass + _logger.info('Exiting')
--- a/zrpn/main.py Thu Sep 06 21:35:41 2012 +0200 +++ b/zrpn/main.py Fri Sep 07 02:22:10 2012 +0200 @@ -43,8 +43,8 @@ class MainMenu(sgc.Menu): - func_dict = lambda self: {"single": self.single, "multi": self.multi, - "exit": sys.exit} + func_dict = lambda self: {"single": self.single, "auto_m": self.auto_m, + "multi": self.multi, "exit": sys.exit} def single(self): self.remove() @@ -60,6 +60,24 @@ ip = str(ip) client.Client(ip, 10000).run() + def auto_m(self): + import pygnetic as net + net.init(True, logging_lvl=logging.DEBUG) + discovery_host = "zrpn.pygame.org" + discovery_host = "localhost" + discovery = net.discovery.DiscoveryClient(discovery_host) + oid = discovery.get_servers() + discovery.update(500) + if discovery.response.oid == oid: + self.remove() + for name, host, port in discovery.response.value.itervalues(): + logging.info("Found %s (%s:%s)", name, host, port) + # TODO: checking for connection timeout + client.Client(host, port).run() + break + else: + logging.info("No server found") + def main(): screen = display.Display() @@ -68,12 +86,16 @@ sgc.Font.set_fonts({"title": data_dir("pincoyablack.otf")}, size=60) - default_host = "zrpn.pygame.org" default_host = "localhost" - menu = MainMenu(menu=("m:Zombies Robots Pirates Ninjas", ("f:single", "Single Player"), - ("w:input_box", "name=ip", "text={}".format(default_host), - "label=Enter IP for multiplayer server(eg. localhost)"), - ("f:multi", "Multiplayer"), ("f:exit", "Quit"))) + menu = MainMenu(menu=( + "m:Zombies Robots Pirates Ninjas", + ("f:single", "Single Player"), + ("f:auto_m", "Auto Multiplayer"), + ("w:input_box", "name=ip", "text={}".format(default_host), + "label=Enter IP for multiplayer server(eg. localhost)"), + ("f:multi", "Multiplayer"), + ("f:exit", "Quit"), + )) menu.screen = screen clock = pygame.time.Clock()
--- a/zrpn/pygnetic/discovery.py Thu Sep 06 21:35:41 2012 +0200 +++ b/zrpn/pygnetic/discovery.py Fri Sep 07 02:22:10 2012 +0200 @@ -12,7 +12,7 @@ message_factory = message.MessageFactory() register = message_factory.register('register', ( - 'oid', 'name', 'host', 'port' + 'oid', 'name', 'port' )) get_servers = message_factory.register('get_servers', ( 'oid', 'current', 'part_size' @@ -21,7 +21,7 @@ 'oid', 'sid' )) response = message_factory.register('response', ( - 'oid', 'value', 'error' + 'oid', 'mid', 'value', 'error' )) @@ -40,7 +40,8 @@ name = message.__class__.__name__ _logger.info('Received %s message from %s', name, self.client_address) ret_val, err = getattr(self, 'net_' + name)(message) - ack_data = message_factory.pack(response(message.oid, ret_val, err)) + mid = message_factory.get_params(message.__class__)[0] + ack_data = message_factory.pack(response(message.oid, mid, ret_val, err)) cnt = socket.sendto(ack_data, self.client_address) _logger.info('Sent response to %s', self.client_address) _logger.debug('Sent %d bytes: %r', cnt, ack_data) @@ -52,7 +53,7 @@ def net_register(self, message): sid = self.server.id_cnt = self.server.id_cnt + 1 - self.server.servers[sid] = [message[1:], 0] + self.server.servers[sid] = [(message.name, self.client_address[0], message.port), 0] return sid, Errors.NO_ERROR def net_get_servers(self, message): @@ -108,37 +109,51 @@ self.address = socket.gethostbyname(host), port self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.response = None - self.callback = None + self.callbacks = {} + self.default_callback = lambda r: None self.oid = 0 - def _send_msg(self, message, *args): + def _send_msg(self, message_cls, *args): oid = self.oid = self.oid + 1 - data = message_factory.pack(message(oid, *args)) + data = message_factory.pack(message_cls(oid, *args)) cnt = self.socket.sendto(data, self.address) self.response = None - name = message.__class__.__name__ - _logger.info('Sent %s message to %s', name, self.address) + _logger.info('Sent %s message to %s', message_cls.__name__, self.address) _logger.debug('Sent %d bytes: %r', cnt, data) return oid def update(self, timeout=0): r = select.select([self.socket], [], [], timeout / 1000.0)[0] + # sending to closed socket puts some data in receive buffer causing + # error while calling recvfrom if len(r) > 0: - data, address = self.socket.recvfrom(self.max_packet_size) + try: + data, address = self.socket.recvfrom(self.max_packet_size) + except Exception as e: + _logger.debug('Error: %s', e) + return if address == self.address: _logger.debug('Received data: %r', data) r = self.response = message_factory.unpack(data) + if r.__class__ != response: + return _logger.info('Received response from %s', address) - if callable(self.callback): - self.callback(r) + self.callbacks.pop(r.oid, self.default_callback)(r) else: _logger.info('Unexpected data from %s', address) def close(self): self.socket.close() - def register(self, name, host, port): - return self._send_msg(register, name, host, port) + def add_callback(self, oid, callback): + if callback is not None and callable(callback): + self.callbacks[oid] = callback + if len(self.callbacks) > 10: + keep = sorted(self.callbacks.iterkeys())[:-10] + self.callbacks = {k: v for k, v in self.callbacks.iter(keep)} + + def register(self, name, port): + return self._send_msg(register, name, port) def ping(self, sid): return self._send_msg(ping, sid)
--- a/zrpn/pygnetic/message.py Thu Sep 06 21:35:41 2012 +0200 +++ b/zrpn/pygnetic/message.py Fri Sep 07 02:22:10 2012 +0200 @@ -115,25 +115,25 @@ """Returns message class with given name. :param name: name of message - :return: message class (namedtuple) + :return: message class (namedtuple) or None if not found """ - return self._message_names[name] + return self._message_names.get(name) def get_by_type(self, type_id): """Returns message class with given type_id. :param type_id: type identifier of message - :return: message class (namedtuple) + :return: message class (namedtuple) or None if not found """ - return self._message_types[type_id] + return self._message_types.get(type_id) def get_params(self, message_cls): """Return tuple containing type_id, and sending keyword arguments :param message_cls: message class created by register - :return: int, dict + :return: int, dict or None if not found """ - return self._message_params[message_cls] + return self._message_params.get(message_cls) def get_hash(self): """Calculate and return hash.
--- a/zrpn/server.py Thu Sep 06 21:35:41 2012 +0200 +++ b/zrpn/server.py Fri Sep 07 02:22:10 2012 +0200 @@ -1,5 +1,6 @@ import time import logging +import threading import pygnetic as net import board import messages @@ -51,11 +52,35 @@ def __init__(self, port): self.server = net.Server(port=port, conn_limit=10) self.server.handler = ClientReceiver + discovery_host = "zrpn.pygame.org" + discovery_host = "localhost" + logging.info('Registering server') + self.dicovery = net.discovery.DiscoveryClient(discovery_host) + oid = self.dicovery.register('no name', self.server.address[1]) + self.dicovery.add_callback(oid, self.enable_discovery) + self.sid = None + self.p_thread = None def run(self): while True: + self.dicovery.update() self.server.update(1000) + def enable_discovery(self, response): + if response: + logging.info('Server registered') + self.dicovery.callback = None + self.sid = response.value + self.p_thread = threading.Thread(target=self.ping) + self.p_thread.daemon = True + self.p_thread.start() + + def ping(self): + while True: + logging.debug('Sending discovery ping') + self.dicovery.ping(self.sid) + time.sleep(30) + def main(): net.init(logging_lvl=logging.DEBUG)
