From 415a0eb9c7d4105d75f569e455b8f293dc6540c4 Mon Sep 17 00:00:00 2001 From: Lenno Nagel Date: Fri, 11 Nov 2016 09:08:56 +0200 Subject: [PATCH 1/6] Fix typo Sokcet -> Socket --- docs/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index f72b15f..56a6aa6 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -313,7 +313,7 @@ pub/sub functionality:: mgr = socketio.RedisManager('redis://') sio = socketio.Server(client_manager=mgr) -If multiple Sokcet.IO servers are connected to a message queue, they +If multiple Socket.IO servers are connected to a message queue, they automatically communicate with each other and manage a combined client list, without any need for additional configuration. To have a process other than a server connect to the queue to emit a message, the same ``KombuManager`` From d09627faff80e78b92a27ec8f8c46a846002e873 Mon Sep 17 00:00:00 2001 From: Miguel Grinberg Date: Fri, 25 Nov 2016 16:42:19 -0800 Subject: [PATCH 2/6] Added clarification regarding class based namespace being singletons Fixes #59 --- docs/index.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 56a6aa6..d71439a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -244,8 +244,14 @@ instance includes versions of several of the methods in the :class:`socketio.Server` class that default to the proper namespace when the ``namespace`` argument is not given. -Note: if an event has a handler in a class-based namespace, and also a -decorator-based function handler, the standalone function handler is invoked. +In the case that an event has a handler in a class-based namespace, and also a +decorator-based function handler, only the standalone function handler is +invoked. + +It is important to note that class-based namespaces are singletons. This means +that a single instance of a namespace class is used for all clients, and +consequently, a namespace instance cannot be used to store client specific +information. Using a Message Queue --------------------- From 6ba131af5cf6238fe4a4a702b38dfec2bb1292f9 Mon Sep 17 00:00:00 2001 From: Miguel Grinberg Date: Fri, 25 Nov 2016 18:29:04 -0800 Subject: [PATCH 3/6] Warn when message queues are used without monkey patching --- socketio/kombu_manager.py | 14 ++++++++++++++ socketio/redis_manager.py | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/socketio/kombu_manager.py b/socketio/kombu_manager.py index 3895e8a..7d97e08 100644 --- a/socketio/kombu_manager.py +++ b/socketio/kombu_manager.py @@ -47,6 +47,20 @@ class KombuManager(PubSubManager): # pragma: no cover self.url = url self.producer = self._producer() + def initialize(self, server): + super(KombuManager, self).initialize(server) + + monkey_patched = True + if server.async_mode == 'eventlet': + from eventlet.patcher import is_monkey_patched + monkey_patched = is_monkey_patched('socket') + elif 'gevent' in server.async_mode: + from gevent.monkey import is_module_patched + monkey_patched = is_module_patched('socket') + if not monkey_patched: + raise RuntimeError('Redis requires a monkey patched socket ' + 'library to work with ' + server.async_mode) + def _connection(self): return kombu.Connection(self.url) diff --git a/socketio/redis_manager.py b/socketio/redis_manager.py index e11ab97..3ed63e5 100644 --- a/socketio/redis_manager.py +++ b/socketio/redis_manager.py @@ -43,6 +43,20 @@ class RedisManager(PubSubManager): # pragma: no cover super(RedisManager, self).__init__(channel=channel, write_only=write_only) + def initialize(self, server): + super(RedisManager, self).initialize(server) + + monkey_patched = True + if server.async_mode == 'eventlet': + from eventlet.patcher import is_monkey_patched + monkey_patched = is_monkey_patched('socket') + elif 'gevent' in server.async_mode: + from gevent.monkey import is_module_patched + monkey_patched = is_module_patched('socket') + if not monkey_patched: + raise RuntimeError('Redis requires a monkey patched socket ' + 'library to work with ' + server.async_mode) + def _publish(self, data): return self.redis.publish(self.channel, pickle.dumps(data)) From 749f8663c48cf100440ba51724542577e46c1b58 Mon Sep 17 00:00:00 2001 From: Miguel Grinberg Date: Fri, 25 Nov 2016 18:53:25 -0800 Subject: [PATCH 4/6] Use a statically allocated logger by default --- socketio/server.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/socketio/server.py b/socketio/server.py index 52e0f37..154aee4 100644 --- a/socketio/server.py +++ b/socketio/server.py @@ -7,6 +7,8 @@ from . import base_manager from . import packet from . import namespace +default_logger = logging.getLogger('socketio') + class Server(object): """A Socket.IO server. @@ -92,7 +94,7 @@ class Server(object): if not isinstance(logger, bool): self.logger = logger else: - self.logger = logging.getLogger('socketio') + self.logger = default_logger if not logging.root.handlers and \ self.logger.level == logging.NOTSET: if logger: From 3eac53261b9d602da8d27c1f9b31f92f86a3b395 Mon Sep 17 00:00:00 2001 From: Miguel Grinberg Date: Fri, 25 Nov 2016 19:33:54 -0800 Subject: [PATCH 5/6] Added "ignore_queue" option to bypass message queue in emits --- socketio/base_manager.py | 2 +- socketio/pubsub_manager.py | 6 +++++- socketio/server.py | 24 ++++++++++++++++++++---- tests/test_pubsub_manager.py | 8 ++++++++ 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/socketio/base_manager.py b/socketio/base_manager.py index 5b98990..198fabc 100644 --- a/socketio/base_manager.py +++ b/socketio/base_manager.py @@ -113,7 +113,7 @@ class BaseManager(object): return r def emit(self, event, data, namespace, room=None, skip_sid=None, - callback=None): + callback=None, **kwargs): """Emit a message to a single client, a room, or all the clients connected to the namespace.""" if namespace not in self.rooms or room not in self.rooms[namespace]: diff --git a/socketio/pubsub_manager.py b/socketio/pubsub_manager.py index 8f34786..5de89b6 100644 --- a/socketio/pubsub_manager.py +++ b/socketio/pubsub_manager.py @@ -37,7 +37,7 @@ class PubSubManager(BaseManager): self.server.logger.info(self.name + ' backend initialized.') def emit(self, event, data, namespace=None, room=None, skip_sid=None, - callback=None): + callback=None, **kwargs): """Emit a message to a single client, a room, or all the clients connected to the namespace. @@ -46,6 +46,10 @@ class PubSubManager(BaseManager): The parameters are the same as in :meth:`.Server.emit`. """ + if kwargs.get('ignore_queue'): + return super(PubSubManager, self).emit( + event, data, namespace=namespace, room=room, skip_sid=skip_sid, + callback=callback) namespace = namespace or '/' if callback is not None: if self.server is None: diff --git a/socketio/server.py b/socketio/server.py index 154aee4..27302d0 100644 --- a/socketio/server.py +++ b/socketio/server.py @@ -177,7 +177,7 @@ class Server(object): namespace_handler def emit(self, event, data=None, room=None, skip_sid=None, namespace=None, - callback=None): + callback=None, **kwargs): """Emit a custom event to one or more connected clients. :param event: The event name. It can be any string. The event names @@ -202,14 +202,22 @@ class Server(object): that will be passed to the function are those provided by the client. Callback functions can only be used when addressing an individual client. + :param ignore_queue: Only used when a message queue is configured. If + set to ``True``, the event is emitted to the + clients directly, without going through the queue. + This is more efficient, but only works when a + single server process is used. It is recommended + to always leave this parameter with its default + value of ``False``. """ namespace = namespace or '/' self.logger.info('emitting event "%s" to %s [%s]', event, room or 'all', namespace) - self.manager.emit(event, data, namespace, room, skip_sid, callback) + self.manager.emit(event, data, namespace, room, skip_sid, callback, + **kwargs) def send(self, data, room=None, skip_sid=None, namespace=None, - callback=None): + callback=None, **kwargs): """Send a message to one or more connected clients. This function emits an event with the name ``'message'``. Use @@ -234,8 +242,16 @@ class Server(object): that will be passed to the function are those provided by the client. Callback functions can only be used when addressing an individual client. + :param ignore_queue: Only used when a message queue is configured. If + set to ``True``, the event is emitted to the + clients directly, without going through the queue. + This is more efficient, but only works when a + single server process is used. It is recommended + to always leave this parameter with its default + value of ``False``. """ - self.emit('message', data, room, skip_sid, namespace, callback) + self.emit('message', data, room, skip_sid, namespace, callback, + **kwargs) def enter_room(self, sid, room, namespace=None): """Enter a room. diff --git a/tests/test_pubsub_manager.py b/tests/test_pubsub_manager.py index d67dc5b..d4cca4f 100644 --- a/tests/test_pubsub_manager.py +++ b/tests/test_pubsub_manager.py @@ -85,6 +85,14 @@ class TestBaseManager(unittest.TestCase): self.assertRaises(ValueError, self.pm.emit, 'foo', 'bar', callback='cb') + def test_emit_with_ignore_queue(self): + self.pm.connect('123', '/') + self.pm.emit('foo', 'bar', room='123', namespace='/', + ignore_queue=True) + self.pm._publish.assert_not_called() + self.pm.server._emit_internal.assert_called_once_with('123', 'foo', + 'bar', '/', None) + def test_close_room(self): self.pm.close_room('foo') self.pm._publish.assert_called_once_with( From 199ed152ce21cf247031391307fa675e61831713 Mon Sep 17 00:00:00 2001 From: Miguel Grinberg Date: Fri, 25 Nov 2016 19:49:41 -0800 Subject: [PATCH 6/6] Release 1.6.1 --- socketio/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/socketio/__init__.py b/socketio/__init__.py index 11b9f6c..305af17 100644 --- a/socketio/__init__.py +++ b/socketio/__init__.py @@ -6,7 +6,7 @@ from .redis_manager import RedisManager from .server import Server from .namespace import Namespace -__version__ = '1.6.0' +__version__ = '1.6.1' __all__ = [__version__, Middleware, Server, BaseManager, PubSubManager, KombuManager, RedisManager, Namespace]