heroku-python / flask-sockets

[DEPRECATED] Alternative: https://github.com/miguelgrinberg/flask-sock
MIT License
1.74k stars 164 forks source link

on_connect and on_close events? #16

Closed onlinespending closed 10 years ago

onlinespending commented 10 years ago

Anyway to respond to a connection made by a new client? I want to build a list of active clients so I can iterate through that list and send the appropriate message to all of them. I'm only doing this for a local web app, so by "clients" I simply mean a different browser window/tab. Currently I'm just using a simple example to test out the behavior before I implement the actual functionality I want. I have a random number generator in its own thread that generates numbers at a rate of one per second. The Websocket handler grabs these numbers from a queue and sends them out on the Websocket. But currently only one client can connect at a time. Hence the need to be able to maintain a list of active connections. What's the best way to do so?

app = Flask(__name__)
sockets = Sockets(app)

myQueue = Queue.Queue(10)

class myThread(threading.Thread):
    def __init__(self, length):
        super(myThread, self).__init__()
        self.length = length

    def run(self):
        for i in range(self.length):
            time.sleep(1)
            myQueue.put({"time": int(time.time()*1000), "data": randrange(100)})

@sockets.route('/stream')
def stream_socket(ws):
    while True:
        #message = ws.receive()
        message = myQueue.get()
        ws.send(json.dumps(message))

@app.route('/')
def test():
    return render_template('main.djhtml')

if __name__ == '__main__':
    thread1 = myThread(30)
    thread1.start()
    server = pywsgi.WSGIServer(('', 5000), app, handler_class=WebSocketHandler)
    server.serve_forever()
onlinespending commented 10 years ago

So just to clarify. Something like the example below does not work, where I save and iterate on each client. It only sends data to one client over Websocket. Even opening up another browser tab to the same local address does not work (fails to connect). I want to avoid using gunicorn, since ultimately like the the example in the previous message I showed above, the data source for the stream will be from a single source (ideally just a separate thread). It'll be fetching realtime data from my stock broker and I can only have one open connection with them at a time. So I can't simply spawn multiple server processes to handle multiple clients, unless I make the realtime stock fetcher its own separate process (which I'm trying to avoid). I'd rather have one thread for the stock data fetcher who's data is then shared to multiple threads that handle the multiple Websocket connections.

from flask import Flask, render_template
from jinja2 import Environment
from flask_sockets import Sockets
from random import randrange
import time
import json
from gevent import pywsgi
from geventwebsocket.handler import WebSocketHandler
import threading
import Queue

app = Flask(__name__)
sockets = Sockets(app)

clients = []

@sockets.route('/stream')
def stream(ws):    
    clients.append(ws)
    while True:
        time.sleep(1)
        for client in clients:
            message = {"time": int(time.time()*1000), "data": randrange(100)}
            client.send(json.dumps(message))

@app.route('/')
def test():
    return render_template('main.djhtml')

if __name__ == '__main__':
    server = pywsgi.WSGIServer(('', 5000), app, handler_class=WebSocketHandler)
    server.serve_forever()
onlinespending commented 10 years ago

I realized right after I posted this that I forgot to replace time.sleep with gevent.sleep. That allowed multiple clients.