miguelgrinberg / flask-sock

Modern WebSocket support for Flask.
MIT License
274 stars 24 forks source link

Possibility to ws.send from another Flask route #19

Closed danohn closed 2 years ago

danohn commented 2 years ago

Hi Miguel, I have a Flask route which accepts a POST request with a parameters. Given one of the parameters is 'hello', is it possible to ws.send this 'hello' string to one of the connected ws clients? My app is purely server to client messages. Thanks!

miguelgrinberg commented 2 years ago

@danohn Yes, I don't see why not. The ws object wraps a network socket, anything you send on it will go to the other end. Your application will have to have a way to find the correct ws object for the client you want to address though.

danohn commented 2 years ago

Thanks @miguelgrinberg I'll try that out and share the results here

danohn commented 2 years ago

Hi @miguelgrinberg , I'm clearly not doing something right or not understanding the code, apologies! Here is my Flask app:

from flask import Flask, render_template, request
from flask_sock import Sock

app = Flask(__name__)
sock = Sock(app)

@app.route('/publish', methods=['POST'])
def publish_route():
    message = request.form['message']
    sock.send(message)
    return f'Message sent: {message}'

@app.route('/')
def index():
    return render_template('index.html')

@sock.route('/echo')
def echo(sock):
    while True:
        data = sock.receive()
        sock.send(data)

if __name__ == '__main__':
    app.run(debug=True)

What I am trying to achieve is when someone sends a POST request to /publish, I extract the message from the POST form and then I want to send that message to the JS client which has already connected to the server on the /echo route.

danohn commented 2 years ago

By the way, with the above code, my index.html is identical to your example.

miguelgrinberg commented 2 years ago

This is partly my fault, because the example code in which you based this was confusing, in that it used the sock variable name for two completely different purposes. I apologize for that, I have now removed this ambiguity from the code.

The WebSocket route now looks like this:

@sock.route('/echo')
def echo(ws):
    while True:
        data = ws.receive()
        ws.send(data)

So hopefully it is now more clear what you need to do. The ws variable that you need to use to send something to your client is a local variable of the WebSocket route, and there are actually multiple ones, one for each active client. Your application needs to use some sort of data structure (maybe a global dictionary or list) to keep track of these variables somewhere your route can find them.

I mentioned this in my previous reply:

Your application will have to have a way to find the correct ws object for the client you want to address though.

danohn commented 2 years ago

Thanks @miguelgrinberg , it looks like flask-socketio might be a better project for my use case. Appreciate the help :)

danohn commented 2 years ago

Hi @miguelgrinberg ,

I just wanted to provide a quick update. I ended up implementing this with your Flask-SocketIO library. Here is the code I am using:

from flask import Flask, request, render_template
from flask_socketio import SocketIO

app = Flask(__name__)

socketio = SocketIO(app)

@app.route("/publish", methods=["POST"])
def publish_route():
    msg = request.form["msg"]
    socketio.emit('my_topic', msg)
    return f"Message sent: {msg}"

@app.route("/", methods=['GET'])
def index_route():
    return render_template("index.html")

if __name__ == "__main__":
    socketio.run(app)

Just out of interest, would the same have been possible with Flask-Sock?