python-socketio 5.11.4__tar.gz → 5.12.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_socketio-5.11.4/src/python_socketio.egg-info → python_socketio-5.12.0}/PKG-INFO +2 -2
- {python_socketio-5.11.4 → python_socketio-5.12.0}/docs/client.rst +18 -5
- {python_socketio-5.11.4 → python_socketio-5.12.0}/docs/server.rst +19 -4
- {python_socketio-5.11.4 → python_socketio-5.12.0}/pyproject.toml +6 -2
- {python_socketio-5.11.4 → python_socketio-5.12.0/src/python_socketio.egg-info}/PKG-INFO +2 -2
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/python_socketio.egg-info/SOURCES.txt +0 -1
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/python_socketio.egg-info/requires.txt +1 -1
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/admin.py +1 -1
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/async_client.py +30 -12
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/async_namespace.py +36 -4
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/async_server.py +26 -9
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/base_client.py +4 -1
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/base_manager.py +1 -2
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/base_namespace.py +1 -1
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/base_server.py +3 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/client.py +22 -9
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/kafka_manager.py +1 -2
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/kombu_manager.py +1 -1
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/namespace.py +16 -2
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/packet.py +1 -1
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/redis_manager.py +1 -2
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/server.py +19 -9
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/zmq_manager.py +1 -1
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/async/test_admin.py +20 -21
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/async/test_client.py +485 -503
- python_socketio-5.12.0/tests/async/test_manager.py +382 -0
- python_socketio-5.12.0/tests/async/test_namespace.py +390 -0
- python_socketio-5.12.0/tests/async/test_pubsub_manager.py +555 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/async/test_server.py +442 -432
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/async/test_simple_client.py +54 -56
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/common/test_admin.py +19 -19
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/common/test_client.py +36 -41
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/common/test_manager.py +3 -4
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/common/test_middleware.py +1 -2
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/common/test_msgpack_packet.py +1 -3
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/common/test_namespace.py +38 -3
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/common/test_packet.py +1 -3
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/common/test_pubsub_manager.py +2 -3
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/common/test_server.py +31 -16
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/common/test_simple_client.py +1 -2
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tox.ini +3 -1
- python_socketio-5.11.4/tests/async/helpers.py +0 -18
- python_socketio-5.11.4/tests/async/test_manager.py +0 -407
- python_socketio-5.11.4/tests/async/test_namespace.py +0 -342
- python_socketio-5.11.4/tests/async/test_pubsub_manager.py +0 -603
- {python_socketio-5.11.4 → python_socketio-5.12.0}/LICENSE +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/MANIFEST.in +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/README.md +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/docs/Makefile +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/docs/_static/README.md +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/docs/_static/custom.css +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/docs/api.rst +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/docs/conf.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/docs/index.rst +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/docs/intro.rst +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/docs/make.bat +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/setup.cfg +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/python_socketio.egg-info/dependency_links.txt +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/python_socketio.egg-info/not-zip-safe +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/python_socketio.egg-info/top_level.txt +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/__init__.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/asgi.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/async_admin.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/async_aiopika_manager.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/async_manager.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/async_pubsub_manager.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/async_redis_manager.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/async_simple_client.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/exceptions.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/manager.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/middleware.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/msgpack_packet.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/pubsub_manager.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/simple_client.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/src/socketio/tornado.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/__init__.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/async/__init__.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/asyncio_web_server.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/common/__init__.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/performance/README.md +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/performance/binary_packet.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/performance/json_packet.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/performance/namespace_packet.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/performance/run.sh +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/performance/server_receive.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/performance/server_send.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/performance/server_send_broadcast.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/performance/text_packet.py +0 -0
- {python_socketio-5.11.4 → python_socketio-5.12.0}/tests/web_server.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-socketio
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.12.0
|
|
4
4
|
Summary: Socket.IO server and client for Python
|
|
5
5
|
Author-email: Miguel Grinberg <miguel.grinberg@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/miguelgrinberg/python-socketio
|
|
@@ -14,7 +14,7 @@ Requires-Python: >=3.8
|
|
|
14
14
|
Description-Content-Type: text/markdown
|
|
15
15
|
License-File: LICENSE
|
|
16
16
|
Requires-Dist: bidict>=0.21.0
|
|
17
|
-
Requires-Dist: python-engineio>=4.
|
|
17
|
+
Requires-Dist: python-engineio>=4.11.0
|
|
18
18
|
Provides-Extra: client
|
|
19
19
|
Requires-Dist: requests>=2.21.0; extra == "client"
|
|
20
20
|
Requires-Dist: websocket-client>=0.54.0; extra == "client"
|
|
@@ -312,8 +312,8 @@ server::
|
|
|
312
312
|
print("The connection failed!")
|
|
313
313
|
|
|
314
314
|
@sio.event
|
|
315
|
-
def disconnect():
|
|
316
|
-
print("I'm disconnected!")
|
|
315
|
+
def disconnect(reason):
|
|
316
|
+
print("I'm disconnected! reason:", reason)
|
|
317
317
|
|
|
318
318
|
The ``connect_error`` handler is invoked when a connection attempt fails. If
|
|
319
319
|
the server provides arguments, these are passed on to the handler. The server
|
|
@@ -325,7 +325,20 @@ server initiated disconnects, or accidental disconnects, for example due to
|
|
|
325
325
|
networking failures. In the case of an accidental disconnection, the client is
|
|
326
326
|
going to attempt to reconnect immediately after invoking the disconnect
|
|
327
327
|
handler. As soon as the connection is re-established the connect handler will
|
|
328
|
-
be invoked once again.
|
|
328
|
+
be invoked once again. The handler receives a ``reason`` argument which
|
|
329
|
+
provides the cause of the disconnection::
|
|
330
|
+
|
|
331
|
+
@sio.event
|
|
332
|
+
def disconnect(reason):
|
|
333
|
+
if reason == sio.reason.CLIENT_DISCONNECT:
|
|
334
|
+
print('the client disconnected')
|
|
335
|
+
elif reason == sio.reason.SERVER_DISCONNECT:
|
|
336
|
+
print('the server disconnected the client')
|
|
337
|
+
else:
|
|
338
|
+
print('disconnect reason:', reason)
|
|
339
|
+
|
|
340
|
+
See the The :attr:`socketio.Client.reason` attribute for a list of possible
|
|
341
|
+
disconnection reasons.
|
|
329
342
|
|
|
330
343
|
The ``connect``, ``connect_error`` and ``disconnect`` events have to be
|
|
331
344
|
defined explicitly and are not invoked on a catch-all event handler.
|
|
@@ -509,7 +522,7 @@ that belong to a namespace can be created as methods of a subclass of
|
|
|
509
522
|
def on_connect(self):
|
|
510
523
|
pass
|
|
511
524
|
|
|
512
|
-
def on_disconnect(self):
|
|
525
|
+
def on_disconnect(self, reason):
|
|
513
526
|
pass
|
|
514
527
|
|
|
515
528
|
def on_my_event(self, data):
|
|
@@ -525,7 +538,7 @@ coroutines if desired::
|
|
|
525
538
|
def on_connect(self):
|
|
526
539
|
pass
|
|
527
540
|
|
|
528
|
-
def on_disconnect(self):
|
|
541
|
+
def on_disconnect(self, reason):
|
|
529
542
|
pass
|
|
530
543
|
|
|
531
544
|
async def on_my_event(self, data):
|
|
@@ -232,8 +232,8 @@ automatically when a client connects or disconnects from the server::
|
|
|
232
232
|
print('connect ', sid)
|
|
233
233
|
|
|
234
234
|
@sio.event
|
|
235
|
-
def disconnect(sid):
|
|
236
|
-
print('disconnect ', sid)
|
|
235
|
+
def disconnect(sid, reason):
|
|
236
|
+
print('disconnect ', sid, reason)
|
|
237
237
|
|
|
238
238
|
The ``connect`` event is an ideal place to perform user authentication, and
|
|
239
239
|
any necessary mapping between user entities in the application and the ``sid``
|
|
@@ -256,6 +256,21 @@ message::
|
|
|
256
256
|
def connect(sid, environ, auth):
|
|
257
257
|
raise ConnectionRefusedError('authentication failed')
|
|
258
258
|
|
|
259
|
+
The disconnect handler receives the ``sid`` assigned to the client and a
|
|
260
|
+
``reason``, which provides the cause of the disconnection::
|
|
261
|
+
|
|
262
|
+
@sio.event
|
|
263
|
+
def disconnect(sid, reason):
|
|
264
|
+
if reason == sio.reason.CLIENT_DISCONNECT:
|
|
265
|
+
print('the client disconnected')
|
|
266
|
+
elif reason == sio.reason.SERVER_DISCONNECT:
|
|
267
|
+
print('the server disconnected the client')
|
|
268
|
+
else:
|
|
269
|
+
print('disconnect reason:', reason)
|
|
270
|
+
|
|
271
|
+
See the The :attr:`socketio.Server.reason` attribute for a list of possible
|
|
272
|
+
disconnection reasons.
|
|
273
|
+
|
|
259
274
|
Catch-All Event Handlers
|
|
260
275
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
261
276
|
|
|
@@ -433,7 +448,7 @@ belong to a namespace can be created as methods in a subclass of
|
|
|
433
448
|
def on_connect(self, sid, environ):
|
|
434
449
|
pass
|
|
435
450
|
|
|
436
|
-
def on_disconnect(self, sid):
|
|
451
|
+
def on_disconnect(self, sid, reason):
|
|
437
452
|
pass
|
|
438
453
|
|
|
439
454
|
def on_my_event(self, sid, data):
|
|
@@ -449,7 +464,7 @@ if desired::
|
|
|
449
464
|
def on_connect(self, sid, environ):
|
|
450
465
|
pass
|
|
451
466
|
|
|
452
|
-
def on_disconnect(self, sid):
|
|
467
|
+
def on_disconnect(self, sid, reason):
|
|
453
468
|
pass
|
|
454
469
|
|
|
455
470
|
async def on_my_event(self, sid, data):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "python-socketio"
|
|
3
|
-
version = "5.
|
|
3
|
+
version = "5.12.0"
|
|
4
4
|
authors = [
|
|
5
5
|
{ name = "Miguel Grinberg", email = "miguel.grinberg@gmail.com" },
|
|
6
6
|
]
|
|
@@ -15,7 +15,7 @@ classifiers = [
|
|
|
15
15
|
requires-python = ">=3.8"
|
|
16
16
|
dependencies = [
|
|
17
17
|
"bidict >= 0.21.0",
|
|
18
|
-
"python-engineio >= 4.
|
|
18
|
+
"python-engineio >= 4.11.0",
|
|
19
19
|
]
|
|
20
20
|
|
|
21
21
|
[project.readme]
|
|
@@ -54,3 +54,7 @@ namespaces = false
|
|
|
54
54
|
[build-system]
|
|
55
55
|
requires = ["setuptools>=61.2"]
|
|
56
56
|
build-backend = "setuptools.build_meta"
|
|
57
|
+
|
|
58
|
+
[tool.pytest.ini_options]
|
|
59
|
+
asyncio_mode = "auto"
|
|
60
|
+
asyncio_default_fixture_loop_scope = "session"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-socketio
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.12.0
|
|
4
4
|
Summary: Socket.IO server and client for Python
|
|
5
5
|
Author-email: Miguel Grinberg <miguel.grinberg@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/miguelgrinberg/python-socketio
|
|
@@ -14,7 +14,7 @@ Requires-Python: >=3.8
|
|
|
14
14
|
Description-Content-Type: text/markdown
|
|
15
15
|
License-File: LICENSE
|
|
16
16
|
Requires-Dist: bidict>=0.21.0
|
|
17
|
-
Requires-Dist: python-engineio>=4.
|
|
17
|
+
Requires-Dist: python-engineio>=4.11.0
|
|
18
18
|
Provides-Extra: client
|
|
19
19
|
Requires-Dist: requests>=2.21.0; extra == "client"
|
|
20
20
|
Requires-Dist: websocket-client>=0.54.0; extra == "client"
|
|
@@ -116,7 +116,7 @@ class AsyncClient(base_client.BaseClient):
|
|
|
116
116
|
Example usage::
|
|
117
117
|
|
|
118
118
|
sio = socketio.AsyncClient()
|
|
119
|
-
sio.connect('http://localhost:5000')
|
|
119
|
+
await sio.connect('http://localhost:5000')
|
|
120
120
|
"""
|
|
121
121
|
if self.connected:
|
|
122
122
|
raise exceptions.ConnectionError('Already connected')
|
|
@@ -189,6 +189,9 @@ class AsyncClient(base_client.BaseClient):
|
|
|
189
189
|
await self.eio.wait()
|
|
190
190
|
await self.sleep(1) # give the reconnect task time to start up
|
|
191
191
|
if not self._reconnect_task:
|
|
192
|
+
if self.eio.state == 'connected': # pragma: no cover
|
|
193
|
+
# connected while sleeping above
|
|
194
|
+
continue
|
|
192
195
|
break
|
|
193
196
|
await self._reconnect_task
|
|
194
197
|
if self.eio.state != 'connected':
|
|
@@ -335,7 +338,6 @@ class AsyncClient(base_client.BaseClient):
|
|
|
335
338
|
await self.disconnect()
|
|
336
339
|
elif self._reconnect_task: # pragma: no branch
|
|
337
340
|
self._reconnect_abort.set()
|
|
338
|
-
print(self._reconnect_task)
|
|
339
341
|
await self._reconnect_task
|
|
340
342
|
|
|
341
343
|
def start_background_task(self, target, *args, **kwargs):
|
|
@@ -386,7 +388,7 @@ class AsyncClient(base_client.BaseClient):
|
|
|
386
388
|
async def _handle_connect(self, namespace, data):
|
|
387
389
|
namespace = namespace or '/'
|
|
388
390
|
if namespace not in self.namespaces:
|
|
389
|
-
self.logger.info('Namespace {} is connected'
|
|
391
|
+
self.logger.info(f'Namespace {namespace} is connected')
|
|
390
392
|
self.namespaces[namespace] = (data or {}).get('sid', self.sid)
|
|
391
393
|
await self._trigger_event('connect', namespace=namespace)
|
|
392
394
|
self._connect_event.set()
|
|
@@ -395,8 +397,9 @@ class AsyncClient(base_client.BaseClient):
|
|
|
395
397
|
if not self.connected:
|
|
396
398
|
return
|
|
397
399
|
namespace = namespace or '/'
|
|
398
|
-
await self._trigger_event('disconnect', namespace
|
|
399
|
-
|
|
400
|
+
await self._trigger_event('disconnect', namespace,
|
|
401
|
+
self.reason.SERVER_DISCONNECT)
|
|
402
|
+
await self._trigger_event('__disconnect_final', namespace)
|
|
400
403
|
if namespace in self.namespaces:
|
|
401
404
|
del self.namespaces[namespace]
|
|
402
405
|
if not self.namespaces:
|
|
@@ -459,11 +462,27 @@ class AsyncClient(base_client.BaseClient):
|
|
|
459
462
|
if handler:
|
|
460
463
|
if asyncio.iscoroutinefunction(handler):
|
|
461
464
|
try:
|
|
462
|
-
|
|
465
|
+
try:
|
|
466
|
+
ret = await handler(*args)
|
|
467
|
+
except TypeError:
|
|
468
|
+
# the legacy disconnect event does not take a reason
|
|
469
|
+
# argument
|
|
470
|
+
if event == 'disconnect':
|
|
471
|
+
ret = await handler(*args[:-1])
|
|
472
|
+
else: # pragma: no cover
|
|
473
|
+
raise
|
|
463
474
|
except asyncio.CancelledError: # pragma: no cover
|
|
464
475
|
ret = None
|
|
465
476
|
else:
|
|
466
|
-
|
|
477
|
+
try:
|
|
478
|
+
ret = handler(*args)
|
|
479
|
+
except TypeError:
|
|
480
|
+
# the legacy disconnect event does not take a reason
|
|
481
|
+
# argument
|
|
482
|
+
if event == 'disconnect':
|
|
483
|
+
ret = handler(*args[:-1])
|
|
484
|
+
else: # pragma: no cover
|
|
485
|
+
raise
|
|
467
486
|
return ret
|
|
468
487
|
|
|
469
488
|
# or else, forward the event to a namepsace handler if one exists
|
|
@@ -563,22 +582,21 @@ class AsyncClient(base_client.BaseClient):
|
|
|
563
582
|
else:
|
|
564
583
|
raise ValueError('Unknown packet type.')
|
|
565
584
|
|
|
566
|
-
async def _handle_eio_disconnect(self):
|
|
585
|
+
async def _handle_eio_disconnect(self, reason):
|
|
567
586
|
"""Handle the Engine.IO disconnection event."""
|
|
568
587
|
self.logger.info('Engine.IO connection dropped')
|
|
569
588
|
will_reconnect = self.reconnection and self.eio.state == 'connected'
|
|
570
589
|
if self.connected:
|
|
571
590
|
for n in self.namespaces:
|
|
572
|
-
await self._trigger_event('disconnect',
|
|
591
|
+
await self._trigger_event('disconnect', n, reason)
|
|
573
592
|
if not will_reconnect:
|
|
574
|
-
await self._trigger_event('__disconnect_final',
|
|
575
|
-
namespace=n)
|
|
593
|
+
await self._trigger_event('__disconnect_final', n)
|
|
576
594
|
self.namespaces = {}
|
|
577
595
|
self.connected = False
|
|
578
596
|
self.callbacks = {}
|
|
579
597
|
self._binary_packet = None
|
|
580
598
|
self.sid = None
|
|
581
|
-
if will_reconnect:
|
|
599
|
+
if will_reconnect and not self._reconnect_task:
|
|
582
600
|
self._reconnect_task = self.start_background_task(
|
|
583
601
|
self._handle_reconnect)
|
|
584
602
|
|
|
@@ -34,11 +34,27 @@ class AsyncNamespace(base_namespace.BaseServerNamespace):
|
|
|
34
34
|
handler = getattr(self, handler_name)
|
|
35
35
|
if asyncio.iscoroutinefunction(handler) is True:
|
|
36
36
|
try:
|
|
37
|
-
|
|
37
|
+
try:
|
|
38
|
+
ret = await handler(*args)
|
|
39
|
+
except TypeError:
|
|
40
|
+
# legacy disconnect events do not have a reason
|
|
41
|
+
# argument
|
|
42
|
+
if event == 'disconnect':
|
|
43
|
+
ret = await handler(*args[:-1])
|
|
44
|
+
else: # pragma: no cover
|
|
45
|
+
raise
|
|
38
46
|
except asyncio.CancelledError: # pragma: no cover
|
|
39
47
|
ret = None
|
|
40
48
|
else:
|
|
41
|
-
|
|
49
|
+
try:
|
|
50
|
+
ret = handler(*args)
|
|
51
|
+
except TypeError:
|
|
52
|
+
# legacy disconnect events do not have a reason
|
|
53
|
+
# argument
|
|
54
|
+
if event == 'disconnect':
|
|
55
|
+
ret = handler(*args[:-1])
|
|
56
|
+
else: # pragma: no cover
|
|
57
|
+
raise
|
|
42
58
|
return ret
|
|
43
59
|
|
|
44
60
|
async def emit(self, event, data=None, to=None, room=None, skip_sid=None,
|
|
@@ -199,11 +215,27 @@ class AsyncClientNamespace(base_namespace.BaseClientNamespace):
|
|
|
199
215
|
handler = getattr(self, handler_name)
|
|
200
216
|
if asyncio.iscoroutinefunction(handler) is True:
|
|
201
217
|
try:
|
|
202
|
-
|
|
218
|
+
try:
|
|
219
|
+
ret = await handler(*args)
|
|
220
|
+
except TypeError:
|
|
221
|
+
# legacy disconnect events do not have a reason
|
|
222
|
+
# argument
|
|
223
|
+
if event == 'disconnect':
|
|
224
|
+
ret = await handler(*args[:-1])
|
|
225
|
+
else: # pragma: no cover
|
|
226
|
+
raise
|
|
203
227
|
except asyncio.CancelledError: # pragma: no cover
|
|
204
228
|
ret = None
|
|
205
229
|
else:
|
|
206
|
-
|
|
230
|
+
try:
|
|
231
|
+
ret = handler(*args)
|
|
232
|
+
except TypeError:
|
|
233
|
+
# legacy disconnect events do not have a reason
|
|
234
|
+
# argument
|
|
235
|
+
if event == 'disconnect':
|
|
236
|
+
ret = handler(*args[:-1])
|
|
237
|
+
else: # pragma: no cover
|
|
238
|
+
raise
|
|
207
239
|
return ret
|
|
208
240
|
|
|
209
241
|
async def emit(self, event, data=None, namespace=None, callback=None):
|
|
@@ -385,7 +385,7 @@ class AsyncServer(base_server.BaseServer):
|
|
|
385
385
|
async with eio.session(sid) as session:
|
|
386
386
|
print('received message from ', session['username'])
|
|
387
387
|
"""
|
|
388
|
-
class _session_context_manager
|
|
388
|
+
class _session_context_manager:
|
|
389
389
|
def __init__(self, server, sid, namespace):
|
|
390
390
|
self.server = server
|
|
391
391
|
self.sid = sid
|
|
@@ -427,7 +427,8 @@ class AsyncServer(base_server.BaseServer):
|
|
|
427
427
|
eio_sid = self.manager.pre_disconnect(sid, namespace=namespace)
|
|
428
428
|
await self._send_packet(eio_sid, self.packet_class(
|
|
429
429
|
packet.DISCONNECT, namespace=namespace))
|
|
430
|
-
await self._trigger_event('disconnect', namespace, sid
|
|
430
|
+
await self._trigger_event('disconnect', namespace, sid,
|
|
431
|
+
self.reason.SERVER_DISCONNECT)
|
|
431
432
|
await self.manager.disconnect(sid, namespace=namespace,
|
|
432
433
|
ignore_queue=True)
|
|
433
434
|
|
|
@@ -575,14 +576,15 @@ class AsyncServer(base_server.BaseServer):
|
|
|
575
576
|
await self._send_packet(eio_sid, self.packet_class(
|
|
576
577
|
packet.CONNECT, {'sid': sid}, namespace=namespace))
|
|
577
578
|
|
|
578
|
-
async def _handle_disconnect(self, eio_sid, namespace):
|
|
579
|
+
async def _handle_disconnect(self, eio_sid, namespace, reason=None):
|
|
579
580
|
"""Handle a client disconnect."""
|
|
580
581
|
namespace = namespace or '/'
|
|
581
582
|
sid = self.manager.sid_from_eio_sid(eio_sid, namespace)
|
|
582
583
|
if not self.manager.is_connected(sid, namespace): # pragma: no cover
|
|
583
584
|
return
|
|
584
585
|
self.manager.pre_disconnect(sid, namespace=namespace)
|
|
585
|
-
await self._trigger_event('disconnect', namespace, sid
|
|
586
|
+
await self._trigger_event('disconnect', namespace, sid,
|
|
587
|
+
reason or self.reason.CLIENT_DISCONNECT)
|
|
586
588
|
await self.manager.disconnect(sid, namespace, ignore_queue=True)
|
|
587
589
|
|
|
588
590
|
async def _handle_event(self, eio_sid, namespace, id, data):
|
|
@@ -634,11 +636,25 @@ class AsyncServer(base_server.BaseServer):
|
|
|
634
636
|
if handler:
|
|
635
637
|
if asyncio.iscoroutinefunction(handler):
|
|
636
638
|
try:
|
|
637
|
-
|
|
639
|
+
try:
|
|
640
|
+
ret = await handler(*args)
|
|
641
|
+
except TypeError:
|
|
642
|
+
# legacy disconnect events use only one argument
|
|
643
|
+
if event == 'disconnect':
|
|
644
|
+
ret = await handler(*args[:-1])
|
|
645
|
+
else: # pragma: no cover
|
|
646
|
+
raise
|
|
638
647
|
except asyncio.CancelledError: # pragma: no cover
|
|
639
648
|
ret = None
|
|
640
649
|
else:
|
|
641
|
-
|
|
650
|
+
try:
|
|
651
|
+
ret = handler(*args)
|
|
652
|
+
except TypeError:
|
|
653
|
+
# legacy disconnect events use only one argument
|
|
654
|
+
if event == 'disconnect':
|
|
655
|
+
ret = handler(*args[:-1])
|
|
656
|
+
else: # pragma: no cover
|
|
657
|
+
raise
|
|
642
658
|
return ret
|
|
643
659
|
# or else, forward the event to a namespace handler if one exists
|
|
644
660
|
handler, args = self._get_namespace_handler(namespace, args)
|
|
@@ -671,7 +687,8 @@ class AsyncServer(base_server.BaseServer):
|
|
|
671
687
|
if pkt.packet_type == packet.CONNECT:
|
|
672
688
|
await self._handle_connect(eio_sid, pkt.namespace, pkt.data)
|
|
673
689
|
elif pkt.packet_type == packet.DISCONNECT:
|
|
674
|
-
await self._handle_disconnect(eio_sid, pkt.namespace
|
|
690
|
+
await self._handle_disconnect(eio_sid, pkt.namespace,
|
|
691
|
+
self.reason.CLIENT_DISCONNECT)
|
|
675
692
|
elif pkt.packet_type == packet.EVENT:
|
|
676
693
|
await self._handle_event(eio_sid, pkt.namespace, pkt.id,
|
|
677
694
|
pkt.data)
|
|
@@ -686,10 +703,10 @@ class AsyncServer(base_server.BaseServer):
|
|
|
686
703
|
else:
|
|
687
704
|
raise ValueError('Unknown packet type.')
|
|
688
705
|
|
|
689
|
-
async def _handle_eio_disconnect(self, eio_sid):
|
|
706
|
+
async def _handle_eio_disconnect(self, eio_sid, reason):
|
|
690
707
|
"""Handle Engine.IO disconnect event."""
|
|
691
708
|
for n in list(self.manager.get_namespaces()).copy():
|
|
692
|
-
await self._handle_disconnect(eio_sid, n)
|
|
709
|
+
await self._handle_disconnect(eio_sid, n, reason)
|
|
693
710
|
if eio_sid in self.environ:
|
|
694
711
|
del self.environ[eio_sid]
|
|
695
712
|
|
|
@@ -3,6 +3,8 @@ import logging
|
|
|
3
3
|
import signal
|
|
4
4
|
import threading
|
|
5
5
|
|
|
6
|
+
import engineio
|
|
7
|
+
|
|
6
8
|
from . import base_namespace
|
|
7
9
|
from . import packet
|
|
8
10
|
|
|
@@ -31,6 +33,7 @@ original_signal_handler = None
|
|
|
31
33
|
class BaseClient:
|
|
32
34
|
reserved_events = ['connect', 'connect_error', 'disconnect',
|
|
33
35
|
'__disconnect_final']
|
|
36
|
+
reason = engineio.Client.reason
|
|
34
37
|
|
|
35
38
|
def __init__(self, reconnection=True, reconnection_attempts=0,
|
|
36
39
|
reconnection_delay=1, reconnection_delay_max=5,
|
|
@@ -285,7 +288,7 @@ class BaseClient:
|
|
|
285
288
|
def _handle_eio_message(self, data): # pragma: no cover
|
|
286
289
|
raise NotImplementedError()
|
|
287
290
|
|
|
288
|
-
def _handle_eio_disconnect(self): # pragma: no cover
|
|
291
|
+
def _handle_eio_disconnect(self, reason): # pragma: no cover
|
|
289
292
|
raise NotImplementedError()
|
|
290
293
|
|
|
291
294
|
def _engineio_client_class(self): # pragma: no cover
|
|
@@ -37,8 +37,7 @@ class BaseManager:
|
|
|
37
37
|
participants.update(ns[r]._fwdm if r in ns else {})
|
|
38
38
|
else:
|
|
39
39
|
participants = ns[room]._fwdm.copy() if room in ns else {}
|
|
40
|
-
|
|
41
|
-
yield sid, eio_sid
|
|
40
|
+
yield from participants.items()
|
|
42
41
|
|
|
43
42
|
def connect(self, eio_sid, namespace):
|
|
44
43
|
"""Register a client connection to a namespace."""
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
|
|
3
|
+
import engineio
|
|
4
|
+
|
|
3
5
|
from . import manager
|
|
4
6
|
from . import base_namespace
|
|
5
7
|
from . import packet
|
|
@@ -9,6 +11,7 @@ default_logger = logging.getLogger('socketio.server')
|
|
|
9
11
|
|
|
10
12
|
class BaseServer:
|
|
11
13
|
reserved_events = ['connect', 'disconnect']
|
|
14
|
+
reason = engineio.Server.reason
|
|
12
15
|
|
|
13
16
|
def __init__(self, client_manager=None, logger=False, serializer='default',
|
|
14
17
|
json=None, async_handlers=True, always_connect=False,
|
|
@@ -180,7 +180,12 @@ class Client(base_client.BaseClient):
|
|
|
180
180
|
self.eio.wait()
|
|
181
181
|
self.sleep(1) # give the reconnect task time to start up
|
|
182
182
|
if not self._reconnect_task:
|
|
183
|
-
|
|
183
|
+
if self.eio.state == 'connected': # pragma: no cover
|
|
184
|
+
# connected while sleeping above
|
|
185
|
+
continue
|
|
186
|
+
else:
|
|
187
|
+
# the reconnect task gave up
|
|
188
|
+
break
|
|
184
189
|
self._reconnect_task.join()
|
|
185
190
|
if self.eio.state != 'connected':
|
|
186
191
|
break
|
|
@@ -363,7 +368,7 @@ class Client(base_client.BaseClient):
|
|
|
363
368
|
def _handle_connect(self, namespace, data):
|
|
364
369
|
namespace = namespace or '/'
|
|
365
370
|
if namespace not in self.namespaces:
|
|
366
|
-
self.logger.info('Namespace {} is connected'
|
|
371
|
+
self.logger.info(f'Namespace {namespace} is connected')
|
|
367
372
|
self.namespaces[namespace] = (data or {}).get('sid', self.sid)
|
|
368
373
|
self._trigger_event('connect', namespace=namespace)
|
|
369
374
|
self._connect_event.set()
|
|
@@ -372,8 +377,9 @@ class Client(base_client.BaseClient):
|
|
|
372
377
|
if not self.connected:
|
|
373
378
|
return
|
|
374
379
|
namespace = namespace or '/'
|
|
375
|
-
self._trigger_event('disconnect', namespace
|
|
376
|
-
|
|
380
|
+
self._trigger_event('disconnect', namespace,
|
|
381
|
+
self.reason.SERVER_DISCONNECT)
|
|
382
|
+
self._trigger_event('__disconnect_final', namespace)
|
|
377
383
|
if namespace in self.namespaces:
|
|
378
384
|
del self.namespaces[namespace]
|
|
379
385
|
if not self.namespaces:
|
|
@@ -431,7 +437,14 @@ class Client(base_client.BaseClient):
|
|
|
431
437
|
# first see if we have an explicit handler for the event
|
|
432
438
|
handler, args = self._get_event_handler(event, namespace, args)
|
|
433
439
|
if handler:
|
|
434
|
-
|
|
440
|
+
try:
|
|
441
|
+
return handler(*args)
|
|
442
|
+
except TypeError:
|
|
443
|
+
# the legacy disconnect event does not take a reason argument
|
|
444
|
+
if event == 'disconnect':
|
|
445
|
+
return handler(*args[:-1])
|
|
446
|
+
else: # pragma: no cover
|
|
447
|
+
raise
|
|
435
448
|
|
|
436
449
|
# or else, forward the event to a namespace handler if one exists
|
|
437
450
|
handler, args = self._get_namespace_handler(namespace, args)
|
|
@@ -520,21 +533,21 @@ class Client(base_client.BaseClient):
|
|
|
520
533
|
else:
|
|
521
534
|
raise ValueError('Unknown packet type.')
|
|
522
535
|
|
|
523
|
-
def _handle_eio_disconnect(self):
|
|
536
|
+
def _handle_eio_disconnect(self, reason):
|
|
524
537
|
"""Handle the Engine.IO disconnection event."""
|
|
525
538
|
self.logger.info('Engine.IO connection dropped')
|
|
526
539
|
will_reconnect = self.reconnection and self.eio.state == 'connected'
|
|
527
540
|
if self.connected:
|
|
528
541
|
for n in self.namespaces:
|
|
529
|
-
self._trigger_event('disconnect',
|
|
542
|
+
self._trigger_event('disconnect', n, reason)
|
|
530
543
|
if not will_reconnect:
|
|
531
|
-
self._trigger_event('__disconnect_final',
|
|
544
|
+
self._trigger_event('__disconnect_final', n)
|
|
532
545
|
self.namespaces = {}
|
|
533
546
|
self.connected = False
|
|
534
547
|
self.callbacks = {}
|
|
535
548
|
self._binary_packet = None
|
|
536
549
|
self.sid = None
|
|
537
|
-
if will_reconnect:
|
|
550
|
+
if will_reconnect and not self._reconnect_task:
|
|
538
551
|
self._reconnect_task = self.start_background_task(
|
|
539
552
|
self._handle_reconnect)
|
|
540
553
|
|
|
@@ -86,7 +86,7 @@ class KombuManager(PubSubManager): # pragma: no cover
|
|
|
86
86
|
return kombu.Exchange(self.channel, **options)
|
|
87
87
|
|
|
88
88
|
def _queue(self):
|
|
89
|
-
queue_name = '
|
|
89
|
+
queue_name = 'python-socketio.' + str(uuid.uuid4())
|
|
90
90
|
options = {'durable': False, 'queue_arguments': {'x-expires': 300000}}
|
|
91
91
|
options.update(self.queue_options)
|
|
92
92
|
return kombu.Queue(queue_name, self._exchange(), **options)
|
|
@@ -23,7 +23,14 @@ class Namespace(base_namespace.BaseServerNamespace):
|
|
|
23
23
|
"""
|
|
24
24
|
handler_name = 'on_' + (event or '')
|
|
25
25
|
if hasattr(self, handler_name):
|
|
26
|
-
|
|
26
|
+
try:
|
|
27
|
+
return getattr(self, handler_name)(*args)
|
|
28
|
+
except TypeError:
|
|
29
|
+
# legacy disconnect events do not have a reason argument
|
|
30
|
+
if event == 'disconnect':
|
|
31
|
+
return getattr(self, handler_name)(*args[:-1])
|
|
32
|
+
else: # pragma: no cover
|
|
33
|
+
raise
|
|
27
34
|
|
|
28
35
|
def emit(self, event, data=None, to=None, room=None, skip_sid=None,
|
|
29
36
|
namespace=None, callback=None, ignore_queue=False):
|
|
@@ -154,7 +161,14 @@ class ClientNamespace(base_namespace.BaseClientNamespace):
|
|
|
154
161
|
"""
|
|
155
162
|
handler_name = 'on_' + (event or '')
|
|
156
163
|
if hasattr(self, handler_name):
|
|
157
|
-
|
|
164
|
+
try:
|
|
165
|
+
return getattr(self, handler_name)(*args)
|
|
166
|
+
except TypeError:
|
|
167
|
+
# legacy disconnect events do not have a reason argument
|
|
168
|
+
if event == 'disconnect':
|
|
169
|
+
return getattr(self, handler_name)(*args[:-1])
|
|
170
|
+
else: # pragma: no cover
|
|
171
|
+
raise
|
|
158
172
|
|
|
159
173
|
def emit(self, event, data=None, namespace=None, callback=None):
|
|
160
174
|
"""Emit a custom event to the server.
|
|
@@ -94,8 +94,7 @@ class RedisManager(PubSubManager): # pragma: no cover
|
|
|
94
94
|
self._redis_connect()
|
|
95
95
|
self.pubsub.subscribe(self.channel)
|
|
96
96
|
retry_sleep = 1
|
|
97
|
-
|
|
98
|
-
yield message
|
|
97
|
+
yield from self.pubsub.listen()
|
|
99
98
|
except redis.exceptions.RedisError:
|
|
100
99
|
logger.error('Cannot receive from redis... '
|
|
101
100
|
'retrying in {} secs'.format(retry_sleep))
|