How to implement server push in Flask framework? How to implement server push in Flask framework? python python

How to implement server push in Flask framework?


Have a look at Server-Sent Events. Server-Sent Events is abrowser API that lets you keep open a socket to your server, subscribing to astream of updates. For more Information read Alex MacCaw (Author ofJuggernaut) post on why he kills juggernaut and why the simplerServer-Sent Events are in manny cases the better tool for the job thanWebsockets.

The protocol is really easy. Just add the mimetype text/event-stream to yourresponse. The browser will keep the connection open and listen for updates. An Eventsent from the server is a line of text starting with data: and a following newline.

data: this is a simple message<blank line>

If you want to exchange structured data, just dump your data as json and send the json over the wire.

An advantage is that you can use SSE in Flask without the need for an extraServer. There is a simple chat application example on github whichuses redis as a pub/sub backend.

def event_stream():    pubsub = red.pubsub()    pubsub.subscribe('chat')    for message in pubsub.listen():        print message        yield 'data: %s\n\n' % message['data']@app.route('/post', methods=['POST'])def post():    message = flask.request.form['message']    user = flask.session.get('user', 'anonymous')    now = datetime.datetime.now().replace(microsecond=0).time()    red.publish('chat', u'[%s] %s: %s' % (now.isoformat(), user, message))@app.route('/stream')def stream():    return flask.Response(event_stream(),                          mimetype="text/event-stream")

You do not need to use gunicron to run theexample app. Just make sure to use threading when running the app, becauseotherwise the SSE connection will block your development server:

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

On the client side you just need a Javascript handler function which will be called when a newmessage is pushed from the server.

var source = new EventSource('/stream');source.onmessage = function (event) {     alert(event.data);};

Server-Sent Events are supported by recent Firefox, Chrome and Safari browsers.Internet Explorer does not yet support Server-Sent Events, but is expected to support them inVersion 10. There are two recommended Polyfills to support older browsers


Redis is overkill: use Server-Sent Events (SSE)

Late to the party (as usual), but IMHO using Redis may be overkill.

As long as you're working in Python+Flask, consider using generator functions as described in this excellent article by Panisuan Joe Chasinga. The gist of it is:

In your client index.html

var targetContainer = document.getElementById("target_div");var eventSource = new EventSource("/stream")  eventSource.onmessage = function(e) {  targetContainer.innerHTML = e.data;};...<div id="target_div">Watch this space...</div>

In your Flask server:

def get_message():    '''this could be any function that blocks until data is ready'''    time.sleep(1.0)    s = time.ctime(time.time())    return s@app.route('/')def root():    return render_template('index.html')@app.route('/stream')def stream():    def eventStream():        while True:            # wait for source data to be available, then push it            yield 'data: {}\n\n'.format(get_message())    return Response(eventStream(), mimetype="text/event-stream")


As a follow-up to @peter-hoffmann's answer, I've written a Flask extension specifically to handle server-sent events. It's called Flask-SSE, and it's available on PyPI. To install it, run:

$ pip install flask-sse

You can use it like this:

from flask import Flaskfrom flask_sse import sseapp = Flask(__name__)app.config["REDIS_URL"] = "redis://localhost"app.register_blueprint(sse, url_prefix='/stream')@app.route('/send')def send_message():    sse.publish({"message": "Hello!"}, type='greeting')    return "Message sent!"

And to connect to the event stream from Javascript, it works like this:

var source = new EventSource("{{ url_for('sse.stream') }}");source.addEventListener('greeting', function(event) {    var data = JSON.parse(event.data);    // do what you want with this data}, false);

Documentation is available on ReadTheDocs. Note that you'll need a running Redis server to handle pub/sub.