Skip to content

Commit

Permalink
Do not invoke reserved events on a catch-all handler (Fixes #814)
Browse files Browse the repository at this point in the history
  • Loading branch information
miguelgrinberg committed Oct 30, 2021
1 parent 60735dd commit 34f34e5
Show file tree
Hide file tree
Showing 8 changed files with 24 additions and 8 deletions.
11 changes: 7 additions & 4 deletions docs/client.rst
Original file line number Diff line number Diff line change
Expand Up @@ -65,20 +65,23 @@ or can also be coroutines::
async def message(data):
print('I received a message!')

If the server includes arguments with an event, those are passed to the
handler function as arguments.

Catch-All Event Handlers
------------------------

A "catch-all" event handler is invoked for any events that do not have an
event handler. You can define a catch-all handler using ``'*'`` as event name::

@sio.on('*')
def catch_all(event, sid, data):
def catch_all(event, data):
pass

Asyncio clients can also use a coroutine::

@sio.on('*')
async def catch_all(event, sid, data):
async def catch_all(event, data):
pass

A catch-all event handler receives the event name as a first argument. The
Expand Down Expand Up @@ -115,8 +118,8 @@ going to attempt to reconnect immediately after invoking the disconnect
handler. As soon as the connection is re-established the connect handler will
be invoked once again.

If the server includes arguments with an event, those are passed to the
handler function as arguments.
The ``connect``, ``connect_error`` and ``disconnect`` events have to be
defined explicitly and are not invoked on a catch-all event handler.

Connecting to a Server
----------------------
Expand Down
3 changes: 3 additions & 0 deletions docs/server.rst
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,9 @@ Asyncio servers can also use a coroutine::
A catch-all event handler receives the event name as a first argument. The
remaining arguments are the same as for a regular event handler.

The ``connect`` and ``disconnect`` events have to be defined explicitly and are
not invoked on a catch-all event handler.

Connect and Disconnect Event Handlers
-------------------------------------

Expand Down
3 changes: 2 additions & 1 deletion src/socketio/asyncio_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,8 @@ async def _trigger_event(self, event, namespace, *args):
handler = None
if event in self.handlers[namespace]:
handler = self.handlers[namespace][event]
elif '*' in self.handlers[namespace]:
elif event not in self.reserved_events and \
'*' in self.handlers[namespace]:
handler = self.handlers[namespace]['*']
args = (event, *args)
if handler:
Expand Down
3 changes: 2 additions & 1 deletion src/socketio/asyncio_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,8 @@ async def _trigger_event(self, event, namespace, *args):
handler = None
if event in self.handlers[namespace]:
handler = self.handlers[namespace][event]
elif '*' in self.handlers[namespace]:
elif event not in self.reserved_events and \
'*' in self.handlers[namespace]:
handler = self.handlers[namespace]['*']
args = (event, *args)
if handler:
Expand Down
5 changes: 4 additions & 1 deletion src/socketio/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ class Client(object):
fatal errors are logged even when
``engineio_logger`` is ``False``.
"""
reserved_events = ['connect', 'connect_error', 'disconnect']

def __init__(self, reconnection=True, reconnection_attempts=0,
reconnection_delay=1, reconnection_delay_max=5,
randomization_factor=0.5, logger=False, serializer='default',
Expand Down Expand Up @@ -625,7 +627,8 @@ def _trigger_event(self, event, namespace, *args):
if namespace in self.handlers:
if event in self.handlers[namespace]:
return self.handlers[namespace][event](*args)
elif '*' in self.handlers[namespace]:
elif event not in self.reserved_events and \
'*' in self.handlers[namespace]:
return self.handlers[namespace]['*'](event, *args)

# or else, forward the event to a namespace handler if one exists
Expand Down
5 changes: 4 additions & 1 deletion src/socketio/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ class Server(object):
fatal errors are logged even when
``engineio_logger`` is ``False``.
"""
reserved_events = ['connect', 'disconnect']

def __init__(self, client_manager=None, logger=False, serializer='default',
json=None, async_handlers=True, always_connect=False,
**kwargs):
Expand Down Expand Up @@ -741,7 +743,8 @@ def _trigger_event(self, event, namespace, *args):
if namespace in self.handlers:
if event in self.handlers[namespace]:
return self.handlers[namespace][event](*args)
elif '*' in self.handlers[namespace]:
elif event not in self.reserved_events and \
'*' in self.handlers[namespace]:
return self.handlers[namespace]['*'](event, *args)

# or else, forward the event to a namespace handler if one exists
Expand Down
1 change: 1 addition & 0 deletions tests/asyncio/test_asyncio_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,7 @@ def test_trigger_event(self):
c.on('*', catchall_handler)
_run(c._trigger_event('foo', '/', 1, '2'))
_run(c._trigger_event('bar', '/', 1, '2', 3))
_run(c._trigger_event('connect', '/')) # should not trigger
handler.assert_called_once_with(1, '2')
catchall_handler.assert_called_once_with('bar', 1, '2', 3)

Expand Down
1 change: 1 addition & 0 deletions tests/common/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,7 @@ def test_trigger_event(self):
c.on('*', catchall_handler)
c._trigger_event('foo', '/', 1, '2')
c._trigger_event('bar', '/', 1, '2', 3)
c._trigger_event('connect', '/') # should not trigger
handler.assert_called_once_with(1, '2')
catchall_handler.assert_called_once_with('bar', 1, '2', 3)

Expand Down

0 comments on commit 34f34e5

Please sign in to comment.