diff --git a/socketio/namespace.py b/socketio/namespace.py index c797a14..fa10cf4 100644 --- a/socketio/namespace.py +++ b/socketio/namespace.py @@ -54,20 +54,19 @@ class Namespace(object): 'close_room', 'rooms', 'disconnect'): setattr(self, func_name, get_wrapped_method(func_name)) - def _get_handlers(self): - """Returns a dict of event names and handlers this namespace - provides.""" - handlers = {} + def get_event_handler(self, event_name): + """Returns the event handler for requested event or ``None``.""" for attr_name in dir(self): attr = getattr(self, attr_name) if hasattr(attr, '_event_name'): - event_name = getattr(attr, '_event_name') + _event_name = getattr(attr, '_event_name') elif attr_name.startswith('on_'): - event_name = attr_name[3:] + _event_name = attr_name[3:] else: continue - handlers[event_name] = attr - return handlers + if _event_name == event_name: + return attr + return None @staticmethod def event_name(name): diff --git a/socketio/server.py b/socketio/server.py index 90c407c..bce6aa8 100644 --- a/socketio/server.py +++ b/socketio/server.py @@ -4,6 +4,7 @@ import engineio import six from . import base_manager +from . import namespace as sio_namespace from . import packet @@ -141,6 +142,10 @@ class Server(object): namespace = namespace or '/' def set_handler(handler): + if isinstance(self.handlers.get(namespace), + sio_namespace.Namespace): + raise ValueError('A Namespace object has been registered ' + 'for this namespace.') if namespace not in self.handlers: self.handlers[namespace] = {} self.handlers[namespace][event] = handler @@ -151,8 +156,8 @@ class Server(object): set_handler(handler) def register_namespace(self, name, namespace_class): - """Register all handlers of the given ``namespace_class`` under the - namespace named by ``name``. + """Register the given ``namespace_class`` under the namespace named + by ``name``. :param name: The namespace's name. It can be any string. :param namespace_class: The sub class of ``Namespace`` to register @@ -163,8 +168,7 @@ class Server(object): See documentation of ``Namespace`` class for an example. """ namespace = namespace_class(name, self) - for event, handler in six.iteritems(namespace._get_handlers()): - self.on(event, handler=handler, namespace=name) + self.handlers[name] = namespace return namespace def emit(self, event, data=None, room=None, skip_sid=None, namespace=None, @@ -441,8 +445,14 @@ class Server(object): def _trigger_event(self, event, namespace, *args): """Invoke an application event handler.""" - if namespace in self.handlers and event in self.handlers[namespace]: - return self.handlers[namespace][event](*args) + handler = None + ns = self.handlers.get(namespace) + if isinstance(ns, sio_namespace.Namespace): + handler = ns.get_event_handler(event) + elif isinstance(ns, dict): + handler = ns.get(event) + if handler is not None: + return handler(*args) def _handle_eio_connect(self, sid, environ): """Handle the Engine.IO connection event.""" diff --git a/tests/test_server.py b/tests/test_server.py index 8c10a06..1939cd5 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -48,13 +48,18 @@ class TestServer(unittest.TestCase): def test_register_namespace(self, eio): class NS(namespace.Namespace): - def on_foo(self): + def on_foo(self, sid): self.emit("bar") + @namespace.Namespace.event_name('foo bar') + def abc(self, sid): + self.emit("foo bar") s = server.Server() s.register_namespace('/ns', NS) - self.assertIsNotNone(s.handlers['/ns'].get('foo')) + self.assertIsNotNone(s.handlers['/ns'].get_event_handler('foo')) + self.assertIsNotNone(s.handlers['/ns'].get_event_handler('foo bar')) + self.assertIsNone(s.handlers['/ns'].get_event_handler('abc')) def test_on_bad_event_name(self, eio): s = server.Server()