python-socketio 5.16.0__py3-none-any.whl → 5.16.2__py3-none-any.whl

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-socketio
3
- Version: 5.16.0
3
+ Version: 5.16.2
4
4
  Summary: Socket.IO server and client for Python
5
5
  Author-email: Miguel Grinberg <miguel.grinberg@gmail.com>
6
6
  License: MIT
@@ -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.11.0
17
+ Requires-Dist: python-engineio>=4.13.2
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"
@@ -24,6 +24,7 @@ Provides-Extra: dev
24
24
  Requires-Dist: tox; extra == "dev"
25
25
  Provides-Extra: docs
26
26
  Requires-Dist: sphinx; extra == "docs"
27
+ Requires-Dist: furo; extra == "docs"
27
28
  Dynamic: license-file
28
29
 
29
30
  python-socketio
@@ -0,0 +1,36 @@
1
+ python_socketio-5.16.2.dist-info/licenses/LICENSE,sha256=yel9Pbwfu82094CLKCzWRtuIev9PUxP-a76NTDFAWpw,1082
2
+ socketio/__init__.py,sha256=DXxtwPIqHFIqV4BGTgJ86OvCXD6Mth3PxBYhFoJ1_7g,1269
3
+ socketio/admin.py,sha256=Ag0fz2QRVq5mprjkBe9txNjGPvQEpBai6-VJ-rJsxmA,16260
4
+ socketio/asgi.py,sha256=NaJtYhOswVVcwHU0zcMM5H5TrSzXq9K-CAYaeSNTZRY,2192
5
+ socketio/async_admin.py,sha256=4DFriPI3lwjgV80a81x1tndmQcRuYJGIu0wwkNS9ayY,16471
6
+ socketio/async_aiopika_manager.py,sha256=X3PQrPMpJdu0yF8EoqvjB7lTb1wyAe4-EI1ToSuHiaA,5892
7
+ socketio/async_client.py,sha256=Xa9R2LJz6enF94TbfzPl7m2BMikLcqZl6AAZDyIHlZo,28124
8
+ socketio/async_manager.py,sha256=G7TLqCDVozbHt0ODG3jU09h1ku6ahk87_Sz4Cm5tL90,4518
9
+ socketio/async_namespace.py,sha256=BxSUs_iQzPHFo6JyoRZm2Yy0uRyizvS2PMCIzsVzk_o,12043
10
+ socketio/async_pubsub_manager.py,sha256=UwU_i_cDvJ4vRzB6RnefEFuWKoiL35WgXHR0y2-CXas,12474
11
+ socketio/async_redis_manager.py,sha256=S_S09BCeyr8N_Ma6ickbDuKESvPaKSYTSXAjd73OMPo,7848
12
+ socketio/async_server.py,sha256=nU-QMFiTk1i2WrLaxiUGJuHmfFnXPvpxHhMFcqC2JuM,36968
13
+ socketio/async_simple_client.py,sha256=eZUgU9fz7c9lXhsbm4Ln95dinM9zxT3Ps2sML4HtT6Y,9016
14
+ socketio/base_client.py,sha256=LJzYynrxPuId7xbHAWiTPFlEAROQCLi8cOmiIDuc1Lk,11673
15
+ socketio/base_manager.py,sha256=w4JZrUSpQ8Unsy0ZwQmEEXwvSzeCGT3AfR0ma0Tmczo,6116
16
+ socketio/base_namespace.py,sha256=mXECdZZ7jPLphU9yH4U4yOayqjMh6OyWgZ71mOJzl5A,970
17
+ socketio/base_server.py,sha256=JtHtmxFjtclcdORg7FIBoMtMxiaCFnuwulXrpLUSjUE,10637
18
+ socketio/client.py,sha256=ttcjNZ-Qb1yUKjb2Eiylw02wt6ghTXWalfw_y7ODNRo,26355
19
+ socketio/exceptions.py,sha256=c8yKss_oJl-fkL52X_AagyJecL-9Mxlgb5xDRqSz5tA,975
20
+ socketio/kafka_manager.py,sha256=QrgTh94Ft2YmQbJ_uVX9HMotKWZYBfWh6Y66RYrSwtM,3114
21
+ socketio/kombu_manager.py,sha256=EAwW-_L-FCQTWeZjpjE0xqJt5RZSUBdQwU7ASORyaNg,6468
22
+ socketio/manager.py,sha256=RPYPcVBFAjN-fEtLfcsPlk6SOW_SBATvw0Tkq_PkGZw,3861
23
+ socketio/middleware.py,sha256=P8wOgSzy3YKOcRVI-r3KNKsEejBz_f5p2wdV8ZqW12E,1591
24
+ socketio/msgpack_packet.py,sha256=gSLKgYP88QAJ1J8sOmgGFvtRBmNH8QWPtHImWaXIqzs,1765
25
+ socketio/namespace.py,sha256=80y8BN2FFlHK8JKF1TirWvvE4pn9FkGKk14IVFkCLEs,9488
26
+ socketio/packet.py,sha256=N7jEjcqOUg2PPEooCoEglxVxhjRqJF-FZCPyDF-UDKQ,7120
27
+ socketio/pubsub_manager.py,sha256=3xUqRnHiFVf_YI68OWRakJTa2LGHPpyMZNSAQN43GZY,11775
28
+ socketio/redis_manager.py,sha256=_I8n5GJcYWlSnmYZnADDfvn4FP2BMfllHqN4JYuuYeE,8923
29
+ socketio/server.py,sha256=cNDOBJ8u01D0ttZmcrUM0vN-1rT8Z1D_-oMMOnEWGWU,35341
30
+ socketio/simple_client.py,sha256=aSMTRO8LHBAWO2IV9uetL6_zwZgPGR-ts73x_4k3624,8434
31
+ socketio/tornado.py,sha256=R82JCqz-E1ibZAQX708h7FX3sguCHQ1OLYpnMag-LY8,295
32
+ socketio/zmq_manager.py,sha256=PkY5aP7-JesCJjumRht90pf3dqLGZV1WrGZ5lA8jQ-Y,4232
33
+ python_socketio-5.16.2.dist-info/METADATA,sha256=HQPRrjFBGlBfPidsgpLOckqXI6rW4OhwoO5gIydq9Gs,3281
34
+ python_socketio-5.16.2.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
35
+ python_socketio-5.16.2.dist-info/top_level.txt,sha256=xWd-HVUanhys_VzQQTRTRZBX8W448ayFytYf1Zffivs,9
36
+ python_socketio-5.16.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (82.0.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
socketio/admin.py CHANGED
@@ -194,6 +194,8 @@ class InstrumentedServer:
194
194
  if self.stats_task: # pragma: no branch
195
195
  self.stop_stats_event.set()
196
196
  self.stats_task.join()
197
+ self.stop_stats_event.clear()
198
+ self.stats_task = None
197
199
 
198
200
  def _trigger_event(self, event, namespace, *args):
199
201
  t = time.time()
@@ -206,6 +208,9 @@ class InstrumentedServer:
206
208
  serialized_socket,
207
209
  datetime.fromtimestamp(t, timezone.utc).isoformat(),
208
210
  ), namespace=self.admin_namespace)
211
+ if not self.sio.eio._get_socket(eio_sid).upgraded:
212
+ self.sio.start_background_task(
213
+ self._check_for_upgrade, eio_sid, sid, namespace)
209
214
  elif event == 'disconnect':
210
215
  del self.sio.manager._timestamps[sid]
211
216
  reason = args[1]
@@ -283,6 +288,7 @@ class InstrumentedServer:
283
288
  def _handle_eio_connect(self, eio_sid, environ):
284
289
  if self.stop_stats_event is None:
285
290
  self.stop_stats_event = self.sio.eio.create_event()
291
+ if self.stats_task is None:
286
292
  self.stats_task = self.sio.start_background_task(
287
293
  self._emit_server_stats)
288
294
 
socketio/async_admin.py CHANGED
@@ -157,9 +157,6 @@ class InstrumentedAsyncServer:
157
157
  namespace=self.admin_namespace)
158
158
 
159
159
  self.sio.start_background_task(config, sid)
160
- self.stop_stats_event = self.sio.eio.create_event()
161
- self.stats_task = self.sio.start_background_task(
162
- self._emit_server_stats)
163
160
 
164
161
  async def admin_emit(self, _, namespace, room_filter, event, *data):
165
162
  await self.sio.emit(event, data, to=room_filter, namespace=namespace)
@@ -183,6 +180,8 @@ class InstrumentedAsyncServer:
183
180
  if self.stats_task: # pragma: no branch
184
181
  self.stop_stats_event.set()
185
182
  await asyncio.gather(self.stats_task)
183
+ self.stats_task = None
184
+ self.stop_stats_event.clear()
186
185
 
187
186
  async def _trigger_event(self, event, namespace, *args):
188
187
  t = time.time()
@@ -195,6 +194,9 @@ class InstrumentedAsyncServer:
195
194
  serialized_socket,
196
195
  datetime.fromtimestamp(t, timezone.utc).isoformat(),
197
196
  ), namespace=self.admin_namespace)
197
+ if not self.sio.eio._get_socket(eio_sid).upgraded:
198
+ self.sio.start_background_task(
199
+ self._check_for_upgrade, eio_sid, sid, namespace)
198
200
  elif event == 'disconnect':
199
201
  del self.sio.manager._timestamps[sid]
200
202
  reason = args[1]
@@ -273,6 +275,7 @@ class InstrumentedAsyncServer:
273
275
  async def _handle_eio_connect(self, eio_sid, environ):
274
276
  if self.stop_stats_event is None:
275
277
  self.stop_stats_event = self.sio.eio.create_event()
278
+ if self.stats_task is None:
276
279
  self.stats_task = self.sio.start_background_task(
277
280
  self._emit_server_stats)
278
281
 
@@ -1,6 +1,5 @@
1
1
  import asyncio
2
2
 
3
- from engineio import json
4
3
  from .async_pubsub_manager import AsyncPubSubManager
5
4
 
6
5
  try:
@@ -32,18 +31,29 @@ class AsyncAioPikaManager(AsyncPubSubManager): # pragma: no cover
32
31
  in rabbitmq
33
32
  :param write_only: If set to ``True``, only initialize to emit events. The
34
33
  default of ``False`` initializes the class for emitting
35
- and receiving.
34
+ and receiving. A write-only instance can be used
35
+ independently of the server to emit to clients from an
36
+ external process.
37
+ :param logger: a custom logger to log it. If not given, the server logger
38
+ is used.
39
+ :param json: An alternative JSON module to use for encoding and decoding
40
+ packets. Custom json modules must have ``dumps`` and ``loads``
41
+ functions that are compatible with the standard library
42
+ versions. This setting is only used when ``write_only`` is set
43
+ to ``True``. Otherwise the JSON module configured in the
44
+ server is used.
36
45
  """
37
46
 
38
47
  name = 'asyncaiopika'
39
48
 
40
49
  def __init__(self, url='amqp://guest:guest@localhost:5672//',
41
- channel='socketio', write_only=False, logger=None):
50
+ channel='socketio', write_only=False, logger=None, json=None):
42
51
  if aio_pika is None:
43
52
  raise RuntimeError('aio_pika package is not installed '
44
53
  '(Run "pip install aio_pika" in your '
45
54
  'virtualenv).')
46
- super().__init__(channel=channel, write_only=write_only, logger=logger)
55
+ super().__init__(channel=channel, write_only=write_only, logger=logger,
56
+ json=json)
47
57
  self.url = url
48
58
  self._lock = asyncio.Lock()
49
59
  self.publisher_connection = None
@@ -82,7 +92,7 @@ class AsyncAioPikaManager(AsyncPubSubManager): # pragma: no cover
82
92
  try:
83
93
  await self.publisher_exchange.publish(
84
94
  aio_pika.Message(
85
- body=json.dumps(data).encode(),
95
+ body=self.json.dumps(data).encode(),
86
96
  delivery_mode=aio_pika.DeliveryMode.PERSISTENT
87
97
  ), routing_key='*',
88
98
  )
socketio/async_client.py CHANGED
@@ -37,10 +37,11 @@ class AsyncClient(base_client.BaseClient):
37
37
  use. To disable logging set to ``False``. The default is
38
38
  ``False``. Note that fatal errors are logged even when
39
39
  ``logger`` is ``False``.
40
- :param json: An alternative json module to use for encoding and decoding
40
+ :param json: An alternative JSON module to use for encoding and decoding
41
41
  packets. Custom json modules must have ``dumps`` and ``loads``
42
42
  functions that are compatible with the standard library
43
- versions.
43
+ versions. This is a process-wide setting, all instantiated
44
+ servers and clients must use the same JSON module.
44
45
  :param handle_sigint: Set to ``True`` to automatically handle disconnection
45
46
  when the process is interrupted, or to ``False`` to
46
47
  leave interrupt handling to the calling application.
@@ -3,8 +3,6 @@ import base64
3
3
  from functools import partial
4
4
  import uuid
5
5
 
6
- from engineio import json
7
-
8
6
  from .async_manager import AsyncManager
9
7
  from .packet import Packet
10
8
 
@@ -22,15 +20,31 @@ class AsyncPubSubManager(AsyncManager):
22
20
 
23
21
  :param channel: The channel name on which the server sends and receives
24
22
  notifications.
23
+ :param write_only: If set to ``True``, only initialize to emit events. The
24
+ default of ``False`` initializes the class for emitting
25
+ and receiving. A write-only instance can be used
26
+ independently of the server to emit to clients from an
27
+ external process.
28
+ :param logger: a custom logger to log it. If not given, the server logger
29
+ is used.
30
+ :param json: An alternative JSON module to use for encoding and decoding
31
+ packets. Custom json modules must have ``dumps`` and ``loads``
32
+ functions that are compatible with the standard library
33
+ versions. This setting is only used when ``write_only`` is set
34
+ to ``True``. Otherwise the JSON module configured in the
35
+ server is used.
25
36
  """
26
37
  name = 'asyncpubsub'
27
38
 
28
- def __init__(self, channel='socketio', write_only=False, logger=None):
39
+ def __init__(self, channel='socketio', write_only=False, logger=None,
40
+ json=None):
29
41
  super().__init__()
30
42
  self.channel = channel
31
43
  self.write_only = write_only
32
44
  self.host_id = uuid.uuid4().hex
33
45
  self.logger = logger
46
+ if json is not None:
47
+ self.json = json
34
48
 
35
49
  def initialize(self):
36
50
  super().initialize()
@@ -221,7 +235,7 @@ class AsyncPubSubManager(AsyncManager):
221
235
  data = message
222
236
  else:
223
237
  try:
224
- data = json.loads(message)
238
+ data = self.json.loads(message)
225
239
  except:
226
240
  pass
227
241
  if data and 'method' in data:
@@ -19,7 +19,6 @@ except ImportError: # pragma: no cover
19
19
  aiovalkey = None
20
20
  ValkeyError = None
21
21
 
22
- from engineio import json
23
22
  from .async_pubsub_manager import AsyncPubSubManager
24
23
  from .redis_manager import parse_redis_sentinel_url
25
24
 
@@ -47,18 +46,29 @@ class AsyncRedisManager(AsyncPubSubManager):
47
46
  notifications. Must be the same in all the servers.
48
47
  :param write_only: If set to ``True``, only initialize to emit events. The
49
48
  default of ``False`` initializes the class for emitting
50
- and receiving.
49
+ and receiving. A write-only instance can be used
50
+ independently of the server to emit to clients from an
51
+ external process.
52
+ :param logger: a custom logger to log it. If not given, the server logger
53
+ is used.
54
+ :param json: An alternative JSON module to use for encoding and decoding
55
+ packets. Custom json modules must have ``dumps`` and ``loads``
56
+ functions that are compatible with the standard library
57
+ versions. This setting is only used when ``write_only`` is set
58
+ to ``True``. Otherwise the JSON module configured in the
59
+ server is used.
51
60
  :param redis_options: additional keyword arguments to be passed to
52
61
  ``Redis.from_url()`` or ``Sentinel()``.
53
62
  """
54
63
  name = 'aioredis'
55
64
 
56
65
  def __init__(self, url='redis://localhost:6379/0', channel='socketio',
57
- write_only=False, logger=None, redis_options=None):
66
+ write_only=False, logger=None, json=None, redis_options=None):
58
67
  if aioredis and \
59
68
  not hasattr(aioredis.Redis, 'from_url'): # pragma: no cover
60
69
  raise RuntimeError('Version 2 of aioredis package is required.')
61
- super().__init__(channel=channel, write_only=write_only, logger=logger)
70
+ super().__init__(channel=channel, write_only=write_only, logger=logger,
71
+ json=json)
62
72
  self.redis_url = url
63
73
  self.redis_options = redis_options or {}
64
74
  self.connected = False
@@ -117,7 +127,7 @@ class AsyncRedisManager(AsyncPubSubManager):
117
127
  if not self.connected:
118
128
  self._redis_connect()
119
129
  return await self.redis.publish(
120
- self.channel, json.dumps(data))
130
+ self.channel, self.json.dumps(data))
121
131
  except error as exc:
122
132
  if retries_left > 0:
123
133
  self._get_logger().error(
socketio/async_server.py CHANGED
@@ -28,10 +28,11 @@ class AsyncServer(base_server.BaseServer):
28
28
  :param logger: To enable logging set to ``True`` or pass a logger object to
29
29
  use. To disable logging set to ``False``. Note that fatal
30
30
  errors are logged even when ``logger`` is ``False``.
31
- :param json: An alternative json module to use for encoding and decoding
31
+ :param json: An alternative JSON module to use for encoding and decoding
32
32
  packets. Custom json modules must have ``dumps`` and ``loads``
33
33
  functions that are compatible with the standard library
34
- versions.
34
+ versions. This is a process-wide setting, all instantiated
35
+ servers and clients must use the same JSON module.
35
36
  :param async_handlers: If set to ``True``, event handlers for a client are
36
37
  executed in separate threads. To run handlers for a
37
38
  client synchronously, set to ``False``. The default
@@ -426,6 +427,8 @@ class AsyncServer(base_server.BaseServer):
426
427
  if delete_it:
427
428
  self.logger.info('Disconnecting %s [%s]', sid, namespace)
428
429
  eio_sid = self.manager.pre_disconnect(sid, namespace=namespace)
430
+ if eio_sid in self._binary_packet:
431
+ del self._binary_packet[eio_sid]
429
432
  await self._send_packet(eio_sid, self.packet_class(
430
433
  packet.DISCONNECT, namespace=namespace))
431
434
  await self._trigger_event('disconnect', namespace, sid,
@@ -701,6 +704,9 @@ class AsyncServer(base_server.BaseServer):
701
704
  pkt.data)
702
705
  elif pkt.packet_type == packet.BINARY_EVENT or \
703
706
  pkt.packet_type == packet.BINARY_ACK:
707
+ if not self.manager.sid_from_eio_sid(eio_sid,
708
+ pkt.namespace or '/'):
709
+ raise ValueError('Unexpected binary packet')
704
710
  self._binary_packet[eio_sid] = pkt
705
711
  elif pkt.packet_type == packet.CONNECT_ERROR:
706
712
  raise ValueError('Unexpected CONNECT_ERROR packet.')
socketio/base_manager.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import itertools
2
2
  import logging
3
+ import json
3
4
 
4
5
  from bidict import bidict, ValueDuplicationError
5
6
 
@@ -14,9 +15,11 @@ class BaseManager:
14
15
  self.eio_to_sid = {}
15
16
  self.callbacks = {}
16
17
  self.pending_disconnect = {}
18
+ self.json = json
17
19
 
18
20
  def set_server(self, server):
19
21
  self.server = server
22
+ self.json = self.server.packet_class.json # use the global JSON module
20
23
 
21
24
  def initialize(self):
22
25
  """Invoked before the first request is received. Subclasses can add
socketio/client.py CHANGED
@@ -39,10 +39,11 @@ class Client(base_client.BaseClient):
39
39
  of the ``encode()`` and ``decode()`` methods can be
40
40
  provided. Client and server must use compatible
41
41
  serializers.
42
- :param json: An alternative json module to use for encoding and decoding
42
+ :param json: An alternative JSON module to use for encoding and decoding
43
43
  packets. Custom json modules must have ``dumps`` and ``loads``
44
44
  functions that are compatible with the standard library
45
- versions.
45
+ versions. This is a process-wide setting, all instantiated
46
+ servers and clients must use the same JSON module.
46
47
  :param handle_sigint: Set to ``True`` to automatically handle disconnection
47
48
  when the process is interrupted, or to ``False`` to
48
49
  leave interrupt handling to the calling application.
socketio/kafka_manager.py CHANGED
@@ -5,7 +5,6 @@ try:
5
5
  except ImportError:
6
6
  kafka = None
7
7
 
8
- from engineio import json
9
8
  from .pubsub_manager import PubSubManager
10
9
 
11
10
  logger = logging.getLogger('socketio')
@@ -32,18 +31,29 @@ class KafkaManager(PubSubManager): # pragma: no cover
32
31
  servers.
33
32
  :param write_only: If set to ``True``, only initialize to emit events. The
34
33
  default of ``False`` initializes the class for emitting
35
- and receiving.
34
+ and receiving. A write-only instance can be used
35
+ independently of the server to emit to clients from an
36
+ external process.
37
+ :param logger: a custom logger to log it. If not given, the server logger
38
+ is used.
39
+ :param json: An alternative JSON module to use for encoding and decoding
40
+ packets. Custom json modules must have ``dumps`` and ``loads``
41
+ functions that are compatible with the standard library
42
+ versions. This setting is only used when ``write_only`` is set
43
+ to ``True``. Otherwise the JSON module configured in the
44
+ server is used.
36
45
  """
37
46
  name = 'kafka'
38
47
 
39
48
  def __init__(self, url='kafka://localhost:9092', channel='socketio',
40
- write_only=False):
49
+ write_only=False, logger=None, json=None):
41
50
  if kafka is None:
42
51
  raise RuntimeError('kafka-python package is not installed '
43
52
  '(Run "pip install kafka-python" in your '
44
53
  'virtualenv).')
45
54
 
46
- super().__init__(channel=channel, write_only=write_only)
55
+ super().__init__(channel=channel, write_only=write_only, logger=logger,
56
+ json=json)
47
57
 
48
58
  urls = [url] if isinstance(url, str) else url
49
59
  self.kafka_urls = [url[8:] if url != 'kafka://' else 'localhost:9092'
@@ -53,7 +63,7 @@ class KafkaManager(PubSubManager): # pragma: no cover
53
63
  bootstrap_servers=self.kafka_urls)
54
64
 
55
65
  def _publish(self, data):
56
- self.producer.send(self.channel, value=json.dumps(data))
66
+ self.producer.send(self.channel, value=self.json.dumps(data))
57
67
  self.producer.flush()
58
68
 
59
69
  def _kafka_listen(self):
socketio/kombu_manager.py CHANGED
@@ -6,7 +6,6 @@ try:
6
6
  except ImportError:
7
7
  kombu = None
8
8
 
9
- from engineio import json
10
9
  from .pubsub_manager import PubSubManager
11
10
 
12
11
 
@@ -34,7 +33,17 @@ class KombuManager(PubSubManager): # pragma: no cover
34
33
  notifications. Must be the same in all the servers.
35
34
  :param write_only: If set to ``True``, only initialize to emit events. The
36
35
  default of ``False`` initializes the class for emitting
37
- and receiving.
36
+ and receiving. A write-only instance can be used
37
+ independently of the server to emit to clients from an
38
+ external process.
39
+ :param logger: a custom logger to log it. If not given, the server logger
40
+ is used.
41
+ :param json: An alternative JSON module to use for encoding and decoding
42
+ packets. Custom json modules must have ``dumps`` and ``loads``
43
+ functions that are compatible with the standard library
44
+ versions. This setting is only used when ``write_only`` is set
45
+ to ``True``. Otherwise the JSON module configured in the
46
+ server is used.
38
47
  :param connection_options: additional keyword arguments to be passed to
39
48
  ``kombu.Connection()``.
40
49
  :param exchange_options: additional keyword arguments to be passed to
@@ -47,14 +56,15 @@ class KombuManager(PubSubManager): # pragma: no cover
47
56
  name = 'kombu'
48
57
 
49
58
  def __init__(self, url='amqp://guest:guest@localhost:5672//',
50
- channel='socketio', write_only=False, logger=None,
59
+ channel='socketio', write_only=False, logger=None, json=None,
51
60
  connection_options=None, exchange_options=None,
52
61
  queue_options=None, producer_options=None):
53
62
  if kombu is None:
54
63
  raise RuntimeError('Kombu package is not installed '
55
64
  '(Run "pip install kombu" in your '
56
65
  'virtualenv).')
57
- super().__init__(channel=channel, write_only=write_only, logger=logger)
66
+ super().__init__(channel=channel, write_only=write_only, logger=logger,
67
+ json=json)
58
68
  self.url = url
59
69
  self.connection_options = connection_options or {}
60
70
  self.exchange_options = exchange_options or {}
@@ -102,7 +112,7 @@ class KombuManager(PubSubManager): # pragma: no cover
102
112
  try:
103
113
  producer_publish = self._producer_publish(
104
114
  self.publisher_connection)
105
- producer_publish(json.dumps(data))
115
+ producer_publish(self.json.dumps(data))
106
116
  break
107
117
  except (OSError, kombu.exceptions.KombuError):
108
118
  if retry:
@@ -2,8 +2,6 @@ import base64
2
2
  from functools import partial
3
3
  import uuid
4
4
 
5
- from engineio import json
6
-
7
5
  from .manager import Manager
8
6
  from .packet import Packet
9
7
 
@@ -21,15 +19,31 @@ class PubSubManager(Manager):
21
19
 
22
20
  :param channel: The channel name on which the server sends and receives
23
21
  notifications.
22
+ :param write_only: If set to ``True``, only initialize to emit events. The
23
+ default of ``False`` initializes the class for emitting
24
+ and receiving. A write-only instance can be used
25
+ independently of the server to emit to clients from an
26
+ external process.
27
+ :param logger: a custom logger to log it. If not given, the server logger
28
+ is used.
29
+ :param json: An alternative JSON module to use for encoding and decoding
30
+ packets. Custom json modules must have ``dumps`` and ``loads``
31
+ functions that are compatible with the standard library
32
+ versions. This setting is only used when ``write_only`` is set
33
+ to ``True``. Otherwise the JSON module configured in the
34
+ server is used.
24
35
  """
25
36
  name = 'pubsub'
26
37
 
27
- def __init__(self, channel='socketio', write_only=False, logger=None):
38
+ def __init__(self, channel='socketio', write_only=False, logger=None,
39
+ json=None):
28
40
  super().__init__()
29
41
  self.channel = channel
30
42
  self.write_only = write_only
31
43
  self.host_id = uuid.uuid4().hex
32
44
  self.logger = logger
45
+ if json is not None:
46
+ self.json = json
33
47
 
34
48
  def initialize(self):
35
49
  super().initialize()
@@ -215,7 +229,7 @@ class PubSubManager(Manager):
215
229
  data = message
216
230
  else:
217
231
  try:
218
- data = json.loads(message)
232
+ data = self.json.loads(message)
219
233
  except:
220
234
  pass
221
235
  if data and 'method' in data:
socketio/redis_manager.py CHANGED
@@ -16,7 +16,6 @@ except ImportError: # pragma: no cover
16
16
  valkey = None
17
17
  ValkeyError = None
18
18
 
19
- from engineio import json
20
19
  from .pubsub_manager import PubSubManager
21
20
 
22
21
  logger = logging.getLogger('socketio')
@@ -72,15 +71,26 @@ class RedisManager(PubSubManager):
72
71
  notifications. Must be the same in all the servers.
73
72
  :param write_only: If set to ``True``, only initialize to emit events. The
74
73
  default of ``False`` initializes the class for emitting
75
- and receiving.
74
+ and receiving. A write-only instance can be used
75
+ independently of the server to emit to clients from an
76
+ external process.
77
+ :param logger: a custom logger to log it. If not given, the server logger
78
+ is used.
79
+ :param json: An alternative JSON module to use for encoding and decoding
80
+ packets. Custom json modules must have ``dumps`` and ``loads``
81
+ functions that are compatible with the standard library
82
+ versions. This setting is only used when ``write_only`` is set
83
+ to ``True``. Otherwise the JSON module configured in the
84
+ server is used.
76
85
  :param redis_options: additional keyword arguments to be passed to
77
86
  ``Redis.from_url()`` or ``Sentinel()``.
78
87
  """
79
88
  name = 'redis'
80
89
 
81
90
  def __init__(self, url='redis://localhost:6379/0', channel='socketio',
82
- write_only=False, logger=None, redis_options=None):
83
- super().__init__(channel=channel, write_only=write_only, logger=logger)
91
+ write_only=False, logger=None, json=None, redis_options=None):
92
+ super().__init__(channel=channel, write_only=write_only, logger=logger,
93
+ json=json)
84
94
  self.redis_url = url
85
95
  self.redis_options = redis_options or {}
86
96
  self.connected = False
@@ -153,7 +163,7 @@ class RedisManager(PubSubManager):
153
163
  try:
154
164
  if not self.connected:
155
165
  self._redis_connect()
156
- return self.redis.publish(self.channel, json.dumps(data))
166
+ return self.redis.publish(self.channel, self.json.dumps(data))
157
167
  except error as exc:
158
168
  if retries_left > 0:
159
169
  logger.error(
socketio/server.py CHANGED
@@ -30,10 +30,11 @@ class Server(base_server.BaseServer):
30
30
  of the ``encode()`` and ``decode()`` methods can be
31
31
  provided. Client and server must use compatible
32
32
  serializers.
33
- :param json: An alternative json module to use for encoding and decoding
33
+ :param json: An alternative JSON module to use for encoding and decoding
34
34
  packets. Custom json modules must have ``dumps`` and ``loads``
35
35
  functions that are compatible with the standard library
36
- versions.
36
+ versions. This is a process-wide setting, all instantiated
37
+ servers and clients must use the same JSON module.
37
38
  :param async_handlers: If set to ``True``, event handlers for a client are
38
39
  executed in separate threads. To run handlers for a
39
40
  client synchronously, set to ``False``. The default
@@ -401,6 +402,8 @@ class Server(base_server.BaseServer):
401
402
  if delete_it:
402
403
  self.logger.info('Disconnecting %s [%s]', sid, namespace)
403
404
  eio_sid = self.manager.pre_disconnect(sid, namespace=namespace)
405
+ if eio_sid in self._binary_packet:
406
+ del self._binary_packet[eio_sid]
404
407
  self._send_packet(eio_sid, self.packet_class(
405
408
  packet.DISCONNECT, namespace=namespace))
406
409
  self._trigger_event('disconnect', namespace, sid,
@@ -662,6 +665,9 @@ class Server(base_server.BaseServer):
662
665
  self._handle_ack(eio_sid, pkt.namespace, pkt.id, pkt.data)
663
666
  elif pkt.packet_type == packet.BINARY_EVENT or \
664
667
  pkt.packet_type == packet.BINARY_ACK:
668
+ if not self.manager.sid_from_eio_sid(eio_sid,
669
+ pkt.namespace or '/'):
670
+ raise ValueError('Unexpected binary packet')
665
671
  self._binary_packet[eio_sid] = pkt
666
672
  elif pkt.packet_type == packet.CONNECT_ERROR:
667
673
  raise ValueError('Unexpected CONNECT_ERROR packet.')
socketio/zmq_manager.py CHANGED
@@ -1,6 +1,5 @@
1
1
  import re
2
2
 
3
- from engineio import json
4
3
  from .pubsub_manager import PubSubManager
5
4
 
6
5
 
@@ -23,7 +22,17 @@ class ZmqManager(PubSubManager): # pragma: no cover
23
22
  notifications. Must be the same in all the servers.
24
23
  :param write_only: If set to ``True``, only initialize to emit events. The
25
24
  default of ``False`` initializes the class for emitting
26
- and receiving.
25
+ and receiving. A write-only instance can be used
26
+ independently of the server to emit to clients from an
27
+ external process.
28
+ :param logger: a custom logger to log it. If not given, the server logger
29
+ is used.
30
+ :param json: An alternative JSON module to use for encoding and decoding
31
+ packets. Custom json modules must have ``dumps`` and ``loads``
32
+ functions that are compatible with the standard library
33
+ versions. This setting is only used when ``write_only`` is set
34
+ to ``True``. Otherwise the JSON module configured in the
35
+ server is used.
27
36
 
28
37
  A zmq message broker must be running for the zmq_manager to work.
29
38
  you can write your own or adapt one from the following simple broker
@@ -42,10 +51,8 @@ class ZmqManager(PubSubManager): # pragma: no cover
42
51
  """
43
52
  name = 'zmq'
44
53
 
45
- def __init__(self, url='zmq+tcp://localhost:5555+5556',
46
- channel='socketio',
47
- write_only=False,
48
- logger=None):
54
+ def __init__(self, url='zmq+tcp://localhost:5555+5556', channel='socketio',
55
+ write_only=False, logger=None, json=None):
49
56
  try:
50
57
  from eventlet.green import zmq
51
58
  except ImportError:
@@ -57,7 +64,8 @@ class ZmqManager(PubSubManager): # pragma: no cover
57
64
  if not (url.startswith('zmq+tcp://') and r.search(url)):
58
65
  raise RuntimeError('unexpected connection string: ' + url)
59
66
 
60
- super().__init__(channel=channel, write_only=write_only, logger=logger)
67
+ super().__init__(channel=channel, write_only=write_only, logger=logger,
68
+ json=json)
61
69
  url = url.replace('zmq+', '')
62
70
  (sink_url, sub_port) = url.split('+')
63
71
  sink_port = sink_url.split(':')[-1]
@@ -75,7 +83,7 @@ class ZmqManager(PubSubManager): # pragma: no cover
75
83
  self.channel = channel
76
84
 
77
85
  def _publish(self, data):
78
- packed_data = json.dumps(
86
+ packed_data = self.json.dumps(
79
87
  {
80
88
  'type': 'message',
81
89
  'channel': self.channel,
@@ -94,7 +102,7 @@ class ZmqManager(PubSubManager): # pragma: no cover
94
102
  for message in self.zmq_listen():
95
103
  if isinstance(message, bytes):
96
104
  try:
97
- message = json.loads(message)
105
+ message = self.json.loads(message)
98
106
  except Exception:
99
107
  pass
100
108
  if isinstance(message, dict) and \
@@ -1,36 +0,0 @@
1
- python_socketio-5.16.0.dist-info/licenses/LICENSE,sha256=yel9Pbwfu82094CLKCzWRtuIev9PUxP-a76NTDFAWpw,1082
2
- socketio/__init__.py,sha256=DXxtwPIqHFIqV4BGTgJ86OvCXD6Mth3PxBYhFoJ1_7g,1269
3
- socketio/admin.py,sha256=pfZ7ZtcZ9-aeaFZkOR4mFhsNPcy9WjZs4_5Os6xc9tA,15966
4
- socketio/asgi.py,sha256=NaJtYhOswVVcwHU0zcMM5H5TrSzXq9K-CAYaeSNTZRY,2192
5
- socketio/async_admin.py,sha256=mrZVtP8P48LyoTvzuSWpzLHwGEgE_gqRzDSqBrz6ju4,16332
6
- socketio/async_aiopika_manager.py,sha256=ehfnIFOJYseejaqs-xKQY3fJd8b59ZggL4SpprA3zCI,5190
7
- socketio/async_client.py,sha256=MCDqMutZEah-xgEPlc8RNz49QouL1U5pt7VMf9TaKs8,28007
8
- socketio/async_manager.py,sha256=G7TLqCDVozbHt0ODG3jU09h1ku6ahk87_Sz4Cm5tL90,4518
9
- socketio/async_namespace.py,sha256=BxSUs_iQzPHFo6JyoRZm2Yy0uRyizvS2PMCIzsVzk_o,12043
10
- socketio/async_pubsub_manager.py,sha256=xTbipuD_we05rUqc4loDrWVyBNaR1ykGoCj4jcyD6Q8,11538
11
- socketio/async_redis_manager.py,sha256=aTwDIpDgZFiFp5PIN3F__zQCXzO52KuT3tI9P_Ur5S4,7146
12
- socketio/async_server.py,sha256=lMW6ZYhtMeiDdgVVnT-Elu46PrKuK5QAXLvpM3SnLZE,36552
13
- socketio/async_simple_client.py,sha256=eZUgU9fz7c9lXhsbm4Ln95dinM9zxT3Ps2sML4HtT6Y,9016
14
- socketio/base_client.py,sha256=LJzYynrxPuId7xbHAWiTPFlEAROQCLi8cOmiIDuc1Lk,11673
15
- socketio/base_manager.py,sha256=H5RHxmiP7n2RmgkkPsJ7WocXu3AA2xjL9C2j28q-x1s,5999
16
- socketio/base_namespace.py,sha256=mXECdZZ7jPLphU9yH4U4yOayqjMh6OyWgZ71mOJzl5A,970
17
- socketio/base_server.py,sha256=JtHtmxFjtclcdORg7FIBoMtMxiaCFnuwulXrpLUSjUE,10637
18
- socketio/client.py,sha256=bZvdIX35wKLlxkjOtsXyfyReI6eyjfHaVRDV4QNY_Mg,26238
19
- socketio/exceptions.py,sha256=c8yKss_oJl-fkL52X_AagyJecL-9Mxlgb5xDRqSz5tA,975
20
- socketio/kafka_manager.py,sha256=RGwh0cphbvOgXxy8Bw5dXtuI443R3y9eNptGwWoQXxA,2384
21
- socketio/kombu_manager.py,sha256=Exfa4C02KTQV0RnZpm1-Mw0j6ugLzeTpoYMOzZUr3kc,5766
22
- socketio/manager.py,sha256=RPYPcVBFAjN-fEtLfcsPlk6SOW_SBATvw0Tkq_PkGZw,3861
23
- socketio/middleware.py,sha256=P8wOgSzy3YKOcRVI-r3KNKsEejBz_f5p2wdV8ZqW12E,1591
24
- socketio/msgpack_packet.py,sha256=gSLKgYP88QAJ1J8sOmgGFvtRBmNH8QWPtHImWaXIqzs,1765
25
- socketio/namespace.py,sha256=80y8BN2FFlHK8JKF1TirWvvE4pn9FkGKk14IVFkCLEs,9488
26
- socketio/packet.py,sha256=N7jEjcqOUg2PPEooCoEglxVxhjRqJF-FZCPyDF-UDKQ,7120
27
- socketio/pubsub_manager.py,sha256=B26V6L94xqfJfKSRKXWHKPYT5JLiDmlk4CaN_3mFr6c,10839
28
- socketio/redis_manager.py,sha256=Cc0FzFunSgA_Uvn2cNDn_-5FILssaGj9MY46ZGff3mg,8221
29
- socketio/server.py,sha256=GySsIsfyFo_FsODf3mbH_Xbyj3OV_jviOwaG9AkDQAM,34925
30
- socketio/simple_client.py,sha256=aSMTRO8LHBAWO2IV9uetL6_zwZgPGR-ts73x_4k3624,8434
31
- socketio/tornado.py,sha256=R82JCqz-E1ibZAQX708h7FX3sguCHQ1OLYpnMag-LY8,295
32
- socketio/zmq_manager.py,sha256=Dkm0atNtIUl7LRAmxH2rcmAtVsjR3zjL_wQ9CsjF3tE,3559
33
- python_socketio-5.16.0.dist-info/METADATA,sha256=YpjsFq90gIlKU8t0KDdWap9VDK5Klx_3VtyyuMjMmbw,3244
34
- python_socketio-5.16.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
35
- python_socketio-5.16.0.dist-info/top_level.txt,sha256=xWd-HVUanhys_VzQQTRTRZBX8W448ayFytYf1Zffivs,9
36
- python_socketio-5.16.0.dist-info/RECORD,,