Browse Source

emit events to multiple rooms (Fixes #605)

pull/683/head
Miguel Grinberg 4 years ago
parent
commit
2538df8bcf
No known key found for this signature in database GPG Key ID: 36848B262DF5F06C
  1. 18
      socketio/asyncio_server.py
  2. 11
      socketio/base_manager.py
  3. 18
      socketio/server.py
  4. 8
      tests/asyncio/test_asyncio_pubsub_manager.py
  5. 21
      tests/common/test_base_manager.py
  6. 10
      tests/common/test_pubsub_manager.py

18
socketio/asyncio_server.py

@ -122,10 +122,11 @@ class AsyncServer(server.Server):
multiple arguments, use a tuple where each element is of
one of the types indicated above.
:param to: The recipient of the message. This can be set to the
session ID of a client to address only that client, or to
to any custom room created by the application to address all
the clients in that room, If this argument is omitted the
event is broadcasted to all connected clients.
session ID of a client to address only that client, to any
any custom room created by the application to address all
the clients in that room, or to a list of custom room
names. If this argument is omitted the event is broadcasted
to all connected clients.
:param room: Alias for the ``to`` parameter.
:param skip_sid: The session ID of a client to skip when broadcasting
to a room or to all clients. This can be used to
@ -174,10 +175,11 @@ class AsyncServer(server.Server):
multiple arguments, use a tuple where each element is of
one of the types indicated above.
:param to: The recipient of the message. This can be set to the
session ID of a client to address only that client, or to
to any custom room created by the application to address all
the clients in that room, If this argument is omitted the
event is broadcasted to all connected clients.
session ID of a client to address only that client, to any
any custom room created by the application to address all
the clients in that room, or to a list of custom room
names. If this argument is omitted the event is broadcasted
to all connected clients.
:param room: Alias for the ``to`` parameter.
:param skip_sid: The session ID of a client to skip when broadcasting
to a room or to all clients. This can be used to

11
socketio/base_manager.py

@ -38,7 +38,14 @@ class BaseManager(object):
def get_participants(self, namespace, room):
"""Return an iterable with the active participants in a room."""
for sid, eio_sid in self.rooms[namespace][room]._fwdm.copy().items():
ns = self.rooms[namespace]
if room is None or isinstance(room, str):
participants = ns[room]._fwdm.copy() if room in ns else {}
else:
participants = ns[room[0]]._fwdm.copy() if room[0] in ns else {}
for r in room[1:]:
participants.update(ns[r]._fwdm if r in ns else {})
for sid, eio_sid in participants.items():
yield sid, eio_sid
def connect(self, eio_sid, namespace):
@ -147,7 +154,7 @@ class BaseManager(object):
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]:
if namespace not in self.rooms:
return
if not isinstance(skip_sid, list):
skip_sid = [skip_sid]

18
socketio/server.py

@ -255,10 +255,11 @@ class Server(object):
multiple arguments, use a tuple where each element is of
one of the types indicated above.
:param to: The recipient of the message. This can be set to the
session ID of a client to address only that client, or to
to any custom room created by the application to address all
the clients in that room, If this argument is omitted the
event is broadcasted to all connected clients.
session ID of a client to address only that client, to any
any custom room created by the application to address all
the clients in that room, or to a list of custom room
names. If this argument is omitted the event is broadcasted
to all connected clients.
:param room: Alias for the ``to`` parameter.
:param skip_sid: The session ID of a client to skip when broadcasting
to a room or to all clients. This can be used to
@ -305,10 +306,11 @@ class Server(object):
multiple arguments, use a tuple where each element is of
one of the types indicated above.
:param to: The recipient of the message. This can be set to the
session ID of a client to address only that client, or to
to any custom room created by the application to address all
the clients in that room, If this argument is omitted the
event is broadcasted to all connected clients.
session ID of a client to address only that client, to any
any custom room created by the application to address all
the clients in that room, or to a list of custom room
names. If this argument is omitted the event is broadcasted
to all connected clients.
:param room: Alias for the ``to`` parameter.
:param skip_sid: The session ID of a client to skip when broadcasting
to a room or to all clients. This can be used to

8
tests/asyncio/test_asyncio_pubsub_manager.py

@ -29,7 +29,15 @@ def _run(coro):
@unittest.skipIf(sys.version_info < (3, 5), 'only for Python 3.5+')
class TestAsyncPubSubManager(unittest.TestCase):
def setUp(self):
id = 0
def generate_id():
nonlocal id
id += 1
return str(id)
mock_server = mock.MagicMock()
mock_server.eio.generate_id = generate_id
mock_server._emit_internal = AsyncMock()
mock_server.disconnect = AsyncMock()
self.pm = asyncio_pubsub_manager.AsyncPubSubManager()

21
tests/common/test_base_manager.py

@ -224,6 +224,27 @@ class TestBaseManager(unittest.TestCase):
'456', 'my event', {'foo': 'bar'}, '/foo', None
)
def test_emit_to_rooms(self):
sid1 = self.bm.connect('123', '/foo')
self.bm.enter_room(sid1, '/foo', 'bar')
sid2 = self.bm.connect('456', '/foo')
self.bm.enter_room(sid2, '/foo', 'bar')
self.bm.enter_room(sid2, '/foo', 'baz')
sid3 = self.bm.connect('789', '/foo')
self.bm.enter_room(sid3, '/foo', 'baz')
self.bm.emit('my event', {'foo': 'bar'}, namespace='/foo',
room=['bar', 'baz'])
assert self.bm.server._emit_internal.call_count == 3
self.bm.server._emit_internal.assert_any_call(
'123', 'my event', {'foo': 'bar'}, '/foo', None
)
self.bm.server._emit_internal.assert_any_call(
'456', 'my event', {'foo': 'bar'}, '/foo', None
)
self.bm.server._emit_internal.assert_any_call(
'789', 'my event', {'foo': 'bar'}, '/foo', None
)
def test_emit_to_all(self):
sid1 = self.bm.connect('123', '/foo')
self.bm.enter_room(sid1, '/foo', 'bar')

10
tests/common/test_pubsub_manager.py

@ -9,9 +9,17 @@ from socketio import base_manager
from socketio import pubsub_manager
class TestBaseManager(unittest.TestCase):
class TestPubSubManager(unittest.TestCase):
def setUp(self):
id = 0
def generate_id():
nonlocal id
id += 1
return str(id)
mock_server = mock.MagicMock()
mock_server.eio.generate_id = generate_id
self.pm = pubsub_manager.PubSubManager()
self.pm._publish = mock.MagicMock()
self.pm.set_server(mock_server)

Loading…
Cancel
Save