Just to give a context here, I’m a node.JS developer, but I’m on a project that I need to work with Python using Flask framework.
The problem is, when a client request to an endpoint of my rest flask app, I need to emit an event using socket.IO, and get some data from the socket server, then this data is the response of the endpoint. But I didn’t figured out how to send this, because flask needs a “return” statement saying what is the response, and my callback is in another context.
Sample of what I’m trying to do: (There’s some comments explaining)
import socketio import eventlet from flask import Flask, request sio = socketio.Server() app = Flask(__name__) @app.route('/test/<param>') def get(param): def ack(data): print (data) #Should be the response sio.emit('event', param, callback=ack) # Socket server call my ack function #Without a return statement, the endpoint return 500 if __name__ == '__main__': app = socketio.Middleware(sio, app) eventlet.wsgi.server(eventlet.listen(('', 8000)), app)
Maybe, the right question here is: Is this possible?
Advertisement
Answer
I’m going to give you one way to implement what you want specifically, but I believe you have an important design flaw in this, as I explain in a comment above. In the way you have this coded, your socketio.Server()
object will broadcast to all your clients, so will not be able to get a callback. If you want to emit to one client (hopefully not the same one that sent the HTTP request), then you need to add a room=client_sid
argument to the emit. Or, if you are contacting a Socket.IO server, then you need to use a Socket.IO client here, not a server.
In any case, to block your HTTP route until the callback function is invoked, you can use an Event
object. Something like this:
from threading import Event from flask import jsonify @app.route('/test/<param>') def get(param): ev = threading.Event() result = None def ack(data): nonlocal result nonlocal ev result = {'data': data} ev.set() # unblock HTTP route sio.emit('event', param, room=some_client_sid, callback=ack) ev.wait() # blocks until ev.set() is called return jsonify(result)