Skip to content

Commit ab33cb7

Browse files
Async versions of enter_room and leave_room should be coroutines (breaking change)
1 parent 8da3c61 commit ab33cb7

File tree

11 files changed

+141
-53
lines changed

11 files changed

+141
-53
lines changed

examples/server/aiohttp/app.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,14 @@ async def my_broadcast_event(sid, message):
3333

3434
@sio.event
3535
async def join(sid, message):
36-
sio.enter_room(sid, message['room'])
36+
await sio.enter_room(sid, message['room'])
3737
await sio.emit('my_response', {'data': 'Entered room: ' + message['room']},
3838
room=sid)
3939

4040

4141
@sio.event
4242
async def leave(sid, message):
43-
sio.leave_room(sid, message['room'])
43+
await sio.leave_room(sid, message['room'])
4444
await sio.emit('my_response', {'data': 'Left room: ' + message['room']},
4545
room=sid)
4646

examples/server/asgi/app.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@ async def test_broadcast_message(sid, message):
3131

3232
@sio.on('join')
3333
async def join(sid, message):
34-
sio.enter_room(sid, message['room'])
34+
await sio.enter_room(sid, message['room'])
3535
await sio.emit('my_response', {'data': 'Entered room: ' + message['room']},
3636
room=sid)
3737

3838

3939
@sio.on('leave')
4040
async def leave(sid, message):
41-
sio.leave_room(sid, message['room'])
41+
await sio.leave_room(sid, message['room'])
4242
await sio.emit('my_response', {'data': 'Left room: ' + message['room']},
4343
room=sid)
4444

examples/server/sanic/app.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,14 @@ async def my_broadcast_event(sid, message):
4040

4141
@sio.event
4242
async def join(sid, message):
43-
sio.enter_room(sid, message['room'])
43+
await sio.enter_room(sid, message['room'])
4444
await sio.emit('my_response', {'data': 'Entered room: ' + message['room']},
4545
room=sid)
4646

4747

4848
@sio.event
4949
async def leave(sid, message):
50-
sio.leave_room(sid, message['room'])
50+
await sio.leave_room(sid, message['room'])
5151
await sio.emit('my_response', {'data': 'Left room: ' + message['room']},
5252
room=sid)
5353

examples/server/tornado/app.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ async def my_broadcast_event(sid, message):
3838

3939
@sio.event
4040
async def join(sid, message):
41-
sio.enter_room(sid, message['room'])
41+
await sio.enter_room(sid, message['room'])
4242
await sio.emit('my_response', {'data': 'Entered room: ' + message['room']},
4343
room=sid)
4444

4545

4646
@sio.event
4747
async def leave(sid, message):
48-
sio.leave_room(sid, message['room'])
48+
await sio.leave_room(sid, message['room'])
4949
await sio.emit('my_response', {'data': 'Left room: ' + message['room']},
5050
room=sid)
5151

src/socketio/asyncio_manager.py

+14
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,20 @@ async def disconnect(self, sid, namespace, **kwargs):
6969
"""
7070
return super().disconnect(sid, namespace, **kwargs)
7171

72+
async def enter_room(self, sid, namespace, room, eio_sid=None):
73+
"""Add a client to a room.
74+
75+
Note: this method is a coroutine.
76+
"""
77+
return super().enter_room(sid, namespace, room, eio_sid=eio_sid)
78+
79+
async def leave_room(self, sid, namespace, room):
80+
"""Remove a client from a room.
81+
82+
Note: this method is a coroutine.
83+
"""
84+
return super().leave_room(sid, namespace, room)
85+
7286
async def close_room(self, room, namespace):
7387
"""Remove all participants from a room.
7488

src/socketio/asyncio_namespace.py

+24
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,30 @@ async def call(self, event, data=None, to=None, sid=None, namespace=None,
8686
timeout=timeout,
8787
ignore_queue=ignore_queue)
8888

89+
async def enter_room(self, sid, room, namespace=None):
90+
"""Enter a room.
91+
92+
The only difference with the :func:`socketio.Server.enter_room` method
93+
is that when the ``namespace`` argument is not given the namespace
94+
associated with the class is used.
95+
96+
Note: this method is a coroutine.
97+
"""
98+
return await self.server.enter_room(
99+
sid, room, namespace=namespace or self.namespace)
100+
101+
async def leave_room(self, sid, room, namespace=None):
102+
"""Leave a room.
103+
104+
The only difference with the :func:`socketio.Server.leave_room` method
105+
is that when the ``namespace`` argument is not given the namespace
106+
associated with the class is used.
107+
108+
Note: this method is a coroutine.
109+
"""
110+
return await self.server.leave_room(
111+
sid, room, namespace=namespace or self.namespace)
112+
89113
async def close_room(self, room, namespace=None):
90114
"""Close a room.
91115

src/socketio/asyncio_server.py

+34
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,40 @@ def event_callback(*args):
275275
else callback_args[0][0] if len(callback_args[0]) == 1 \
276276
else None
277277

278+
async def enter_room(self, sid, room, namespace=None):
279+
"""Enter a room.
280+
281+
This function adds the client to a room. The :func:`emit` and
282+
:func:`send` functions can optionally broadcast events to all the
283+
clients in a room.
284+
285+
:param sid: Session ID of the client.
286+
:param room: Room name. If the room does not exist it is created.
287+
:param namespace: The Socket.IO namespace for the event. If this
288+
argument is omitted the default namespace is used.
289+
290+
Note: this method is a coroutine.
291+
"""
292+
namespace = namespace or '/'
293+
self.logger.info('%s is entering room %s [%s]', sid, room, namespace)
294+
await self.manager.enter_room(sid, namespace, room)
295+
296+
async def leave_room(self, sid, room, namespace=None):
297+
"""Leave a room.
298+
299+
This function removes the client from a room.
300+
301+
:param sid: Session ID of the client.
302+
:param room: Room name.
303+
:param namespace: The Socket.IO namespace for the event. If this
304+
argument is omitted the default namespace is used.
305+
306+
Note: this method is a coroutine.
307+
"""
308+
namespace = namespace or '/'
309+
self.logger.info('%s is leaving room %s [%s]', sid, room, namespace)
310+
await self.manager.leave_room(sid, namespace, room)
311+
278312
async def close_room(self, room, namespace=None):
279313
"""Close a room.
280314

src/socketio/base_manager.py

+14-6
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,11 @@ def connect(self, eio_sid, namespace):
5454
"""Register a client connection to a namespace."""
5555
sid = self.server.eio.generate_id()
5656
try:
57-
self.enter_room(sid, namespace, None, eio_sid=eio_sid)
57+
self.basic_enter_room(sid, namespace, None, eio_sid=eio_sid)
5858
except ValueDuplicationError:
5959
# already connected
6060
return None
61-
self.enter_room(sid, namespace, sid, eio_sid=eio_sid)
61+
self.basic_enter_room(sid, namespace, sid, eio_sid=eio_sid)
6262
return sid
6363

6464
def is_connected(self, sid, namespace):
@@ -106,7 +106,7 @@ def disconnect(self, sid, namespace, **kwargs):
106106
if sid in room:
107107
rooms.append(room_name)
108108
for room in rooms:
109-
self.leave_room(sid, namespace, room)
109+
self.basic_leave_room(sid, namespace, room)
110110
if sid in self.callbacks:
111111
del self.callbacks[sid]
112112
if namespace in self.pending_disconnect and \
@@ -115,7 +115,7 @@ def disconnect(self, sid, namespace, **kwargs):
115115
if len(self.pending_disconnect[namespace]) == 0:
116116
del self.pending_disconnect[namespace]
117117

118-
def enter_room(self, sid, namespace, room, eio_sid=None):
118+
def basic_enter_room(self, sid, namespace, room, eio_sid=None):
119119
"""Add a client to a room."""
120120
if eio_sid is None and namespace not in self.rooms:
121121
raise ValueError('sid is not connected to requested namespace')
@@ -127,7 +127,7 @@ def enter_room(self, sid, namespace, room, eio_sid=None):
127127
eio_sid = self.rooms[namespace][None][sid]
128128
self.rooms[namespace][room][sid] = eio_sid
129129

130-
def leave_room(self, sid, namespace, room):
130+
def basic_leave_room(self, sid, namespace, room):
131131
"""Remove a client from a room."""
132132
try:
133133
del self.rooms[namespace][room][sid]
@@ -138,11 +138,19 @@ def leave_room(self, sid, namespace, room):
138138
except KeyError:
139139
pass
140140

141+
def enter_room(self, sid, namespace, room, eio_sid=None):
142+
"""Add a client to a room."""
143+
self.basic_enter_room(sid, namespace, room, eio_sid=eio_sid)
144+
145+
def leave_room(self, sid, namespace, room):
146+
"""Remove a client from a room."""
147+
self.basic_leave_room(sid, namespace, room)
148+
141149
def close_room(self, room, namespace):
142150
"""Remove all participants from a room."""
143151
try:
144152
for sid, _ in self.get_participants(namespace, room):
145-
self.leave_room(sid, namespace, room)
153+
self.basic_leave_room(sid, namespace, room)
146154
except KeyError:
147155
pass
148156

tests/asyncio/test_asyncio_manager.py

+23-21
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ def test_pre_disconnect(self):
5454
def test_disconnect(self):
5555
sid1 = self.bm.connect('123', '/foo')
5656
sid2 = self.bm.connect('456', '/foo')
57-
self.bm.enter_room(sid1, '/foo', 'bar')
58-
self.bm.enter_room(sid2, '/foo', 'baz')
57+
_run(self.bm.enter_room(sid1, '/foo', 'bar'))
58+
_run(self.bm.enter_room(sid2, '/foo', 'baz'))
5959
_run(self.bm.disconnect(sid1, '/foo'))
6060
assert dict(self.bm.rooms['/foo'][None]) == {sid2: '456'}
6161
assert dict(self.bm.rooms['/foo'][sid2]) == {sid2: '456'}
@@ -97,8 +97,8 @@ def test_disconnect_twice(self):
9797
def test_disconnect_all(self):
9898
sid1 = self.bm.connect('123', '/foo')
9999
sid2 = self.bm.connect('456', '/foo')
100-
self.bm.enter_room(sid1, '/foo', 'bar')
101-
self.bm.enter_room(sid2, '/foo', 'baz')
100+
_run(self.bm.enter_room(sid1, '/foo', 'bar'))
101+
_run(self.bm.enter_room(sid2, '/foo', 'baz'))
102102
_run(self.bm.disconnect(sid1, '/foo'))
103103
_run(self.bm.disconnect(sid2, '/foo'))
104104
assert self.bm.rooms == {}
@@ -173,8 +173,8 @@ def test_get_participants(self):
173173

174174
def test_leave_invalid_room(self):
175175
sid = self.bm.connect('123', '/foo')
176-
self.bm.leave_room(sid, '/foo', 'baz')
177-
self.bm.leave_room(sid, '/bar', 'baz')
176+
_run(self.bm.leave_room(sid, '/foo', 'baz'))
177+
_run(self.bm.leave_room(sid, '/bar', 'baz'))
178178

179179
def test_no_room(self):
180180
rooms = self.bm.get_rooms('123', '/foo')
@@ -184,17 +184,19 @@ def test_close_room(self):
184184
sid = self.bm.connect('123', '/foo')
185185
self.bm.connect('456', '/foo')
186186
self.bm.connect('789', '/foo')
187-
self.bm.enter_room(sid, '/foo', 'bar')
188-
self.bm.enter_room(sid, '/foo', 'bar')
187+
_run(self.bm.enter_room(sid, '/foo', 'bar'))
188+
_run(self.bm.enter_room(sid, '/foo', 'bar'))
189189
_run(self.bm.close_room('bar', '/foo'))
190+
from pprint import pprint
191+
pprint(self.bm.rooms)
190192
assert 'bar' not in self.bm.rooms['/foo']
191193

192194
def test_close_invalid_room(self):
193195
self.bm.close_room('bar', '/foo')
194196

195197
def test_rooms(self):
196198
sid = self.bm.connect('123', '/foo')
197-
self.bm.enter_room(sid, '/foo', 'bar')
199+
_run(self.bm.enter_room(sid, '/foo', 'bar'))
198200
r = self.bm.get_rooms(sid, '/foo')
199201
assert len(r) == 2
200202
assert sid in r
@@ -216,9 +218,9 @@ def test_emit_to_sid(self):
216218

217219
def test_emit_to_room(self):
218220
sid1 = self.bm.connect('123', '/foo')
219-
self.bm.enter_room(sid1, '/foo', 'bar')
221+
_run(self.bm.enter_room(sid1, '/foo', 'bar'))
220222
sid2 = self.bm.connect('456', '/foo')
221-
self.bm.enter_room(sid2, '/foo', 'bar')
223+
_run(self.bm.enter_room(sid2, '/foo', 'bar'))
222224
self.bm.connect('789', '/foo')
223225
_run(
224226
self.bm.emit(
@@ -237,12 +239,12 @@ def test_emit_to_room(self):
237239

238240
def test_emit_to_rooms(self):
239241
sid1 = self.bm.connect('123', '/foo')
240-
self.bm.enter_room(sid1, '/foo', 'bar')
242+
_run(self.bm.enter_room(sid1, '/foo', 'bar'))
241243
sid2 = self.bm.connect('456', '/foo')
242-
self.bm.enter_room(sid2, '/foo', 'bar')
243-
self.bm.enter_room(sid2, '/foo', 'baz')
244+
_run(self.bm.enter_room(sid2, '/foo', 'bar'))
245+
_run(self.bm.enter_room(sid2, '/foo', 'baz'))
244246
sid3 = self.bm.connect('789', '/foo')
245-
self.bm.enter_room(sid3, '/foo', 'baz')
247+
_run(self.bm.enter_room(sid3, '/foo', 'baz'))
246248
_run(
247249
self.bm.emit('my event', {'foo': 'bar'}, namespace='/foo',
248250
room=['bar', 'baz'])
@@ -263,9 +265,9 @@ def test_emit_to_rooms(self):
263265

264266
def test_emit_to_all(self):
265267
sid1 = self.bm.connect('123', '/foo')
266-
self.bm.enter_room(sid1, '/foo', 'bar')
268+
_run(self.bm.enter_room(sid1, '/foo', 'bar'))
267269
sid2 = self.bm.connect('456', '/foo')
268-
self.bm.enter_room(sid2, '/foo', 'bar')
270+
_run(self.bm.enter_room(sid2, '/foo', 'bar'))
269271
self.bm.connect('789', '/foo')
270272
self.bm.connect('abc', '/bar')
271273
_run(self.bm.emit('my event', {'foo': 'bar'}, namespace='/foo'))
@@ -285,9 +287,9 @@ def test_emit_to_all(self):
285287

286288
def test_emit_to_all_skip_one(self):
287289
sid1 = self.bm.connect('123', '/foo')
288-
self.bm.enter_room(sid1, '/foo', 'bar')
290+
_run(self.bm.enter_room(sid1, '/foo', 'bar'))
289291
sid2 = self.bm.connect('456', '/foo')
290-
self.bm.enter_room(sid2, '/foo', 'bar')
292+
_run(self.bm.enter_room(sid2, '/foo', 'bar'))
291293
self.bm.connect('789', '/foo')
292294
self.bm.connect('abc', '/bar')
293295
_run(
@@ -307,9 +309,9 @@ def test_emit_to_all_skip_one(self):
307309

308310
def test_emit_to_all_skip_two(self):
309311
sid1 = self.bm.connect('123', '/foo')
310-
self.bm.enter_room(sid1, '/foo', 'bar')
312+
_run(self.bm.enter_room(sid1, '/foo', 'bar'))
311313
sid2 = self.bm.connect('456', '/foo')
312-
self.bm.enter_room(sid2, '/foo', 'bar')
314+
_run(self.bm.enter_room(sid2, '/foo', 'bar'))
313315
sid3 = self.bm.connect('789', '/foo')
314316
self.bm.connect('abc', '/bar')
315317
_run(

tests/asyncio/test_asyncio_namespace.py

+14-10
Original file line numberDiff line numberDiff line change
@@ -176,25 +176,29 @@ def test_call(self):
176176

177177
def test_enter_room(self):
178178
ns = asyncio_namespace.AsyncNamespace('/foo')
179-
ns._set_server(mock.MagicMock())
180-
ns.enter_room('sid', 'room')
181-
ns.server.enter_room.assert_called_with(
179+
mock_server = mock.MagicMock()
180+
mock_server.enter_room = AsyncMock()
181+
ns._set_server(mock_server)
182+
_run(ns.enter_room('sid', 'room'))
183+
ns.server.enter_room.mock.assert_called_with(
182184
'sid', 'room', namespace='/foo'
183185
)
184-
ns.enter_room('sid', 'room', namespace='/bar')
185-
ns.server.enter_room.assert_called_with(
186+
_run(ns.enter_room('sid', 'room', namespace='/bar'))
187+
ns.server.enter_room.mock.assert_called_with(
186188
'sid', 'room', namespace='/bar'
187189
)
188190

189191
def test_leave_room(self):
190192
ns = asyncio_namespace.AsyncNamespace('/foo')
191-
ns._set_server(mock.MagicMock())
192-
ns.leave_room('sid', 'room')
193-
ns.server.leave_room.assert_called_with(
193+
mock_server = mock.MagicMock()
194+
mock_server.leave_room = AsyncMock()
195+
ns._set_server(mock_server)
196+
_run(ns.leave_room('sid', 'room'))
197+
ns.server.leave_room.mock.assert_called_with(
194198
'sid', 'room', namespace='/foo'
195199
)
196-
ns.leave_room('sid', 'room', namespace='/bar')
197-
ns.server.leave_room.assert_called_with(
200+
_run(ns.leave_room('sid', 'room', namespace='/bar'))
201+
ns.server.leave_room.mock.assert_called_with(
198202
'sid', 'room', namespace='/bar'
199203
)
200204

0 commit comments

Comments
 (0)