Closed mooomooo closed 1 month ago
Monkey patch:
import types
old_geh = socketio.server._get_event_handler
socketio.server.old_geh = socketio.server._get_event_handler
def new_geh(self, event, namespace, *args):
sys.stderr.write(f"XXX e:{event} ns:{namespace}\n")
h, a = self.old_geh(event, namespace, *args)
sys.stderr.write(f">>> h:{h} a:{a}\n")
return h, a
socketio.server._get_event_handler = types.MethodType(new_geh, socketio.server)
stderr output:
XXX e:connect ns:/
>>> h:<function on_connect at 0x7fb810513370> a:(...)
The connect
and disconnect
handlers are not dispatched to catch-all handlers, only user-defined events are.
Hm is that intentional, or can they also be enabled? Without a connect
catch-all, it doesn't seem like dynamic / arbitrary namespaces would be possible, i.e. all allowable namespaces would have to be explicitly assigned to a handler.
That said, something weird is still going on (which is what prompted my other post https://github.com/miguelgrinberg/python-socketio/issues/1334 in the first place): I've pared it down to this minimal server code. If a client connects on the default namespace then sends an "in" event , it gets lost with:
from flask import Flask, render_template, request
from flask_socketio import SocketIO
import sys
app = Flask(__name__)
socketio = SocketIO(app, namespaces="*")
@app.route('/')
def root():
return render_template('index.html')
@socketio.on('connect')
def on_connect(auth):
sys.stderr.write(f"*** IN CONNECT w/ default ns\n")
@socketio.on('in', namespace='*')
def on_in_star(ns, data):
sys.stderr.write(f"--- IN; catchall ns = {ns}, {data}\n")
if __name__ == '__main__':
socketio.run(app, debug=True)
The ns catchall does not get triggered. But if I add a ns-specific handler:
@socketio.on('in', namespace='/')
def on_in(data):
sys.stderr.write(f"/// IN; ns = '/', data = {data}\n")
that one does successfully get triggered.
For completeness, index.html:
<html>
<head>
<script src="/static/js/socket.io.min.js"></script>
</head>
<body>
<script>
const socket = io();
socket.on('connect', function() {
console.log("Connected to server, emitting 'hello' to 'in'");
socket.emit('in', 'hello')
});
</script>
</body>
</html>
So your client is sending an event on a namespace it did not connect to? That does not work, the client must connect to the namespace(s) it wants to use.
(I'll split out the other issue into its own thread.)
How is this different from the situation described in https://github.com/miguelgrinberg/python-socketio/issues/1334, which we agreed that is working correctly?
Yeah we agreed that it should work... but it doesn't. Again, here is a MWE, now all contained in a single file:
from flask import Flask
from flask_socketio import SocketIO
app = Flask(__name__)
socketio = SocketIO(app, namespaces="*", logger=True, engineio_logger=True)
@app.route('/')
def root():
return '''<!DOCTYPE html>
<html>
<head><script src="https://cdn.socket.io/4.7.5/socket.io.min.js"></script></head>
<body><script>
const socket = io();
socket.on('connect', function() {
socket.emit('in', 'hello')
});
</script></body>
</html>
'''
@socketio.on('connect')
def on_connect(auth):
print(f"*** CONNECT; default ns\n")
@socketio.on('in', namespace='*')
def on_in_star(ns, data):
print(f"--- IN; catchall ns = {ns}, {data}\n")
if __name__ == '__main__':
socketio.run(app, debug=True)
If everything was working as intended, we would expect to see both print statements execute, i.e. if we see *** CONNECT; default ns
then we should also see --- IN; catchall ns = /, hello
. But we don't:
8S2llN_8QFMwcWC9AAAA: Sending packet OPEN data {'sid': '8S2llN_8QFMwcWC9AAAA', 'upgrades': ['websocket'], 'pingTimeout': 20000, 'pingInterval': 25000}
127.0.0.1 - - [08/May/2024 02:09:04] "GET /socket.io/?EIO=4&transport=polling&t=OzNTgOA HTTP/1.1" 200 -
8S2llN_8QFMwcWC9AAAA: Received packet MESSAGE data 0
*** CONNECT; default ns
8S2llN_8QFMwcWC9AAAA: Sending packet MESSAGE data 0{"sid":"qhmheUkfz-IN1VcHAAAB"}
127.0.0.1 - - [08/May/2024 02:09:04] "POST /socket.io/?EIO=4&transport=polling&t=OzNTgOR&sid=8S2llN_8QFMwcWC9AAAA HTTP/1.1" 200 -
8S2llN_8QFMwcWC9AAAA: Received request to upgrade to websocket
127.0.0.1 - - [08/May/2024 02:09:04] "GET /socket.io/?EIO=4&transport=polling&t=OzNTgOy&sid=8S2llN_8QFMwcWC9AAAA HTTP/1.1" 200 -
127.0.0.1 - - [08/May/2024 02:09:04] "GET /socket.io/?EIO=4&transport=polling&t=OzNTgOy.0&sid=8S2llN_8QFMwcWC9AAAA HTTP/1.1" 200 -
8S2llN_8QFMwcWC9AAAA: Upgrade to websocket successful
8S2llN_8QFMwcWC9AAAA: Received packet MESSAGE data 2["in","hello"]
received event "in" from qhmheUkfz-IN1VcHAAAB [/]
The received event should get dispatched to the in
handler in the catch-all namespace... but it does not.
Try the main branch of flask-socketio and let me know if that works better.
Note that your catch-all handler should be as follows:
@socketio.on('in', namespace='*')
def on_in_star(data):
print(f"--- IN; catchall ns = {request.namespace}, {data}\n")
In Flask-SocketIO you do not need to add the namespace as an argument, because you always get it in request.namespace
.
Worked! Looks like it's doing everything I expect now, thanks!
@miguelgrinberg Could you make a new release with this commit to save having to pip install from git? Thanks!
Also, there may need to be a similar fix to allow catch-all event handling? I don't think I can successfully do a
@socketio.on('*')
(but I haven't tried very much yet)
I have never spent the time to add catch-all handlers in this package, and there is currently no testing beyond what I added for this fix. Before I can release this as a supported feature I need to do some more work and build tests.
Ah I see; thanks for your diligence!
Please add catch all event handling. And on that subject, Please add dynamic event registering and unregistering at runtime.
Please add dynamic event registering and unregistering at runtime.
Not planning to do this. You can implement this yourself for your application using a class-based namespace (or a catch-all event handler once I add them properly to this package) if this is important to you.
Describe the bug Namespace catch-all handlers don't seem to trigger?
To Reproduce Steps to reproduce the behavior:
socketio = SocketIO(app, namespaces="*", ...)
@socketio.on('connect', namespace='*')
Expected behavior Namespace catch-all handler gets called.
Logs
Additional context
python-socketio
library in requirements.txt :python-socketio >= 5.11.1
to ensure the namespace-catchall functionality is in there_get_event_handler
function insocketio.server
to see what handlers get returned, and that seems to work correctly