Skip to content

Commit 49822e6

Browse files
v5 protocol: do not connect the default namespace unless requested explicitly
1 parent 798ab6a commit 49822e6

5 files changed

Lines changed: 53 additions & 54 deletions

File tree

File renamed without changes.

socketio/asyncio_client.py

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -71,16 +71,19 @@ async def connect(self, url, headers={}, transports=None,
7171
are ``'polling'`` and ``'websocket'``. If not
7272
given, the polling transport is connected first,
7373
then an upgrade to websocket is attempted.
74-
:param namespaces: The list of custom namespaces to connect, in
75-
addition to the default namespace. If not given,
76-
the namespace list is obtained from the registered
77-
event handlers.
74+
:param namespaces: The namespaces to connect as a string or list of
75+
strings. If not given, the namespaces that have
76+
registered event handlers are connected.
7877
:param socketio_path: The endpoint where the Socket.IO server is
7978
installed. The default value is appropriate for
8079
most cases.
8180
8281
Note: this method is a coroutine.
8382
83+
Note: The connection mechannism occurs in the background and will
84+
complete at some point after this function returns. The connection
85+
will be established when the ``connect`` event is invoked.
86+
8487
Example usage::
8588
8689
sio = socketio.AsyncClient()
@@ -97,8 +100,7 @@ async def connect(self, url, headers={}, transports=None,
97100
set(self.namespace_handlers.keys()))
98101
elif isinstance(namespaces, six.string_types):
99102
namespaces = [namespaces]
100-
self.connection_namespaces = namespaces
101-
self.namespaces = [n for n in namespaces if n != '/']
103+
self.connection_namespaces = namespaces
102104
try:
103105
await self.eio.connect(url, headers=headers,
104106
transports=transports,
@@ -154,7 +156,7 @@ async def emit(self, event, data=None, namespace=None, callback=None):
154156
Note 2: this method is a coroutine.
155157
"""
156158
namespace = namespace or '/'
157-
if namespace != '/' and namespace not in self.namespaces:
159+
if namespace not in self.namespaces:
158160
raise exceptions.BadNamespaceError(
159161
namespace + ' is not a connected namespace.')
160162
self.logger.info('Emitting event "%s" [%s]', event, namespace)
@@ -248,8 +250,6 @@ async def disconnect(self):
248250
for n in self.namespaces:
249251
await self._send_packet(packet.Packet(packet.DISCONNECT,
250252
namespace=n))
251-
await self._send_packet(packet.Packet(
252-
packet.DISCONNECT, namespace='/'))
253253
self.connected = False
254254
await self.eio.disconnect(abort=True)
255255

@@ -291,30 +291,22 @@ async def _send_packet(self, pkt):
291291
else:
292292
await self.eio.send(encoded_packet)
293293

294-
async def _handle_connect(self, namespace):
294+
async def _handle_connect(self, namespace, data):
295295
namespace = namespace or '/'
296296
self.logger.info('Namespace {} is connected'.format(namespace))
297+
if namespace not in self.namespaces:
298+
self.namespaces[namespace] = (data or {}).get('sid', self.sid)
297299
await self._trigger_event('connect', namespace=namespace)
298-
if namespace == '/':
299-
for n in self.namespaces:
300-
await self._send_packet(packet.Packet(packet.CONNECT,
301-
namespace=n))
302-
elif namespace not in self.namespaces:
303-
self.namespaces.append(namespace)
304300

305301
async def _handle_disconnect(self, namespace):
306302
if not self.connected:
307303
return
308304
namespace = namespace or '/'
309-
if namespace == '/':
310-
for n in self.namespaces:
311-
await self._trigger_event('disconnect', namespace=n)
312-
self.namespaces = []
313305
await self._trigger_event('disconnect', namespace=namespace)
314306
if namespace in self.namespaces:
315-
self.namespaces.remove(namespace)
316-
if namespace == '/':
317-
self.connected = False
307+
del self.namespaces[namespace]
308+
if not self.namespaces:
309+
await self.eio.disconnect(abort=True)
318310

319311
async def _handle_event(self, namespace, id, data):
320312
namespace = namespace or '/'
@@ -422,10 +414,12 @@ async def _handle_reconnect(self):
422414
break
423415
client.reconnecting_clients.remove(self)
424416

425-
def _handle_eio_connect(self):
417+
async def _handle_eio_connect(self):
426418
"""Handle the Engine.IO connection event."""
427419
self.logger.info('Engine.IO connection established')
428420
self.sid = self.eio.sid
421+
for n in self.connection_namespaces:
422+
await self._send_packet(packet.Packet(packet.CONNECT, namespace=n))
429423

430424
async def _handle_eio_message(self, data):
431425
"""Dispatch Engine.IO messages."""
@@ -440,7 +434,7 @@ async def _handle_eio_message(self, data):
440434
else:
441435
pkt = packet.Packet(encoded_packet=data)
442436
if pkt.packet_type == packet.CONNECT:
443-
await self._handle_connect(pkt.namespace)
437+
await self._handle_connect(pkt.namespace, pkt.data)
444438
elif pkt.packet_type == packet.DISCONNECT:
445439
await self._handle_disconnect(pkt.namespace)
446440
elif pkt.packet_type == packet.EVENT:
@@ -462,7 +456,6 @@ async def _handle_eio_disconnect(self):
462456
if self.connected:
463457
for n in self.namespaces:
464458
await self._trigger_event('disconnect', namespace=n)
465-
await self._trigger_event('disconnect', namespace='/')
466459
self.namespaces = []
467460
self.connected = False
468461
self.callbacks = {}

socketio/asyncio_server.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,6 @@ async def _handle_eio_connect(self, sid, environ):
515515
self.manager_initialized = True
516516
self.manager.initialize()
517517
self.environ[sid] = environ
518-
return await self._handle_connect(sid, '/')
519518

520519
async def _handle_eio_message(self, sid, data):
521520
"""Dispatch Engine.IO messages."""

socketio/client.py

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def __init__(self, reconnection=True, reconnection_attempts=0,
124124
self.sid = None
125125

126126
self.connected = False
127-
self.namespaces = []
127+
self.namespaces = {}
128128
self.handlers = {}
129129
self.namespace_handlers = {}
130130
self.callbacks = {}
@@ -242,14 +242,17 @@ def connect(self, url, headers={}, transports=None,
242242
are ``'polling'`` and ``'websocket'``. If not
243243
given, the polling transport is connected first,
244244
then an upgrade to websocket is attempted.
245-
:param namespaces: The list of custom namespaces to connect, in
246-
addition to the default namespace. If not given,
247-
the namespace list is obtained from the registered
248-
event handlers.
245+
:param namespaces: The namespaces to connect as a string or list of
246+
strings. If not given, the namespaces that have
247+
registered event handlers are connected.
249248
:param socketio_path: The endpoint where the Socket.IO server is
250249
installed. The default value is appropriate for
251250
most cases.
252251
252+
Note: The connection mechannism occurs in the background and will
253+
complete at some point after this function returns. The connection
254+
will be established when the ``connect`` event is invoked.
255+
253256
Example usage::
254257
255258
sio = socketio.Client()
@@ -266,8 +269,7 @@ def connect(self, url, headers={}, transports=None,
266269
set(self.namespace_handlers.keys()))
267270
elif isinstance(namespaces, six.string_types):
268271
namespaces = [namespaces]
269-
self.connection_namespaces = namespaces
270-
self.namespaces = [n for n in namespaces if n != '/']
272+
self.connection_namespaces = namespaces
271273
try:
272274
self.eio.connect(url, headers=headers, transports=transports,
273275
engineio_path=socketio_path)
@@ -318,7 +320,7 @@ def emit(self, event, data=None, namespace=None, callback=None):
318320
situation.
319321
"""
320322
namespace = namespace or '/'
321-
if namespace != '/' and namespace not in self.namespaces:
323+
if namespace not in self.namespaces:
322324
raise exceptions.BadNamespaceError(
323325
namespace + ' is not a connected namespace.')
324326
self.logger.info('Emitting event "%s" [%s]', event, namespace)
@@ -402,11 +404,23 @@ def disconnect(self):
402404
# later in _handle_eio_disconnect we invoke the disconnect handler
403405
for n in self.namespaces:
404406
self._send_packet(packet.Packet(packet.DISCONNECT, namespace=n))
405-
self._send_packet(packet.Packet(
406-
packet.DISCONNECT, namespace='/'))
407407
self.connected = False
408408
self.eio.disconnect(abort=True)
409409

410+
def get_sid(self, namespace=None):
411+
"""Return the ``sid`` associated with a connection.
412+
413+
:param namespace: The Socket.IO namespace. If this argument is omitted
414+
the handler is associated with the default
415+
namespace. Note that unlike previous versions, the
416+
current version of the Socket.IO protocol uses
417+
different ``sid`` values per namespace.
418+
419+
This method returns the ``sid`` for the requested namespace as a
420+
string.
421+
"""
422+
return self.namespaces.get(namespace or '/')
423+
410424
def transport(self):
411425
"""Return the name of the transport used by the client.
412426
@@ -460,29 +474,22 @@ def _generate_ack_id(self, namespace, callback):
460474
self.callbacks[namespace][id] = callback
461475
return id
462476

463-
def _handle_connect(self, namespace):
477+
def _handle_connect(self, namespace, data):
464478
namespace = namespace or '/'
465479
self.logger.info('Namespace {} is connected'.format(namespace))
480+
if namespace not in self.namespaces:
481+
self.namespaces[namespace] = (data or {}).get('sid', self.sid)
466482
self._trigger_event('connect', namespace=namespace)
467-
if namespace == '/':
468-
for n in self.namespaces:
469-
self._send_packet(packet.Packet(packet.CONNECT, namespace=n))
470-
elif namespace not in self.namespaces:
471-
self.namespaces.append(namespace)
472483

473484
def _handle_disconnect(self, namespace):
474485
if not self.connected:
475486
return
476487
namespace = namespace or '/'
477-
if namespace == '/':
478-
for n in self.namespaces:
479-
self._trigger_event('disconnect', namespace=n)
480-
self.namespaces = []
481488
self._trigger_event('disconnect', namespace=namespace)
482489
if namespace in self.namespaces:
483-
self.namespaces.remove(namespace)
484-
if namespace == '/':
485-
self.connected = False
490+
del self.namespaces[namespace]
491+
if not self.namespaces:
492+
self.eio.disconnect(abort=True)
486493

487494
def _handle_event(self, namespace, id, data):
488495
namespace = namespace or '/'
@@ -524,7 +531,7 @@ def _handle_error(self, namespace, data):
524531
data = (data,)
525532
self._trigger_event('connect_error', namespace, *data)
526533
if namespace in self.namespaces:
527-
self.namespaces.remove(namespace)
534+
del self.namespaces[namespace]
528535
if namespace == '/':
529536
self.namespaces = []
530537
self.connected = False
@@ -581,6 +588,8 @@ def _handle_eio_connect(self):
581588
"""Handle the Engine.IO connection event."""
582589
self.logger.info('Engine.IO connection established')
583590
self.sid = self.eio.sid
591+
for n in self.connection_namespaces:
592+
self._send_packet(packet.Packet(packet.CONNECT, namespace=n))
584593

585594
def _handle_eio_message(self, data):
586595
"""Dispatch Engine.IO messages."""
@@ -595,7 +604,7 @@ def _handle_eio_message(self, data):
595604
else:
596605
pkt = packet.Packet(encoded_packet=data)
597606
if pkt.packet_type == packet.CONNECT:
598-
self._handle_connect(pkt.namespace)
607+
self._handle_connect(pkt.namespace, pkt.data)
599608
elif pkt.packet_type == packet.DISCONNECT:
600609
self._handle_disconnect(pkt.namespace)
601610
elif pkt.packet_type == packet.EVENT:
@@ -616,7 +625,6 @@ def _handle_eio_disconnect(self):
616625
if self.connected:
617626
for n in self.namespaces:
618627
self._trigger_event('disconnect', namespace=n)
619-
self._trigger_event('disconnect', namespace='/')
620628
self.namespaces = []
621629
self.connected = False
622630
self.callbacks = {}

socketio/server.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,6 @@ def _handle_eio_connect(self, sid, environ):
705705
self.manager_initialized = True
706706
self.manager.initialize()
707707
self.environ[sid] = environ
708-
return self._handle_connect(sid, '/')
709708

710709
def _handle_eio_message(self, sid, data):
711710
"""Dispatch Engine.IO messages."""

0 commit comments

Comments
 (0)