Reputation: 1105
I have been playing around with sending server sent events with Flask and Tornado. I took a look at this blog article:
https://s-n.me/blog/2012/10/16/realtime-websites-with-flask/
I decided to try writing my own Flask app to send server sent events as an exercise. Here is the code for my Flask app called sse_server.py:
#! /usr/bin/python
from flask import Flask, request, Response, render_template
from tornado.wsgi import WSGIContainer
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
app = Flask(__name__)
def event_stream():
count = 0
while True:
print 'data: {0}\n\n'.format(count)
yield 'data: {0}\n\n'.format(count)
count += 1
@app.route('/my_event_source')
def sse_request():
return Response(
event_stream(),
mimetype='text/event-stream')
@app.route('/')
def page():
return render_template('index.html')
if __name__ == '__main__':
print "Please open a web browser to http://127.0.0.1:5000."
# Spin up the app
http_server = HTTPServer(WSGIContainer(app))
http_server.listen(5000)
IOLoop.instance().start()
In my templates folder, I have a simple index.html page:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Test</title>
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="//code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
<script type="text/javascript" src="../static/sse_client.js"></script>
</head>
<body>
<h3>Test</h3>
<ul id="output">
</ul>
</body>
</html>
In my static folder, I have a file called sse_client.js:
var queue = [];
var interval = setInterval(function(){addItem()}, 1000);
function addItem(){
if(queue.length > 0){
var item = queue[0];
queue.shift();
$('#output').append(item);
}
}
$(document).ready(
function() {
var sse = new EventSource('/my_event_source');
console.log('blah');
sse.onmessage = function(event) {
console.log('A message has arrived!');
var list_item = '<li>' + event.data + '</li>';
console.log(list_item);
queue.push(list_item);
};
})
Basically, my app's structure is
sse/
sse_server.py
static/
sse_client.js
templates/
index.html
The app displays the index page, but the data is not getting streamed to it. I have no idea what I am doing wrong. I think I need another set of eyes on this. I'm sure it's something really minor and stupid.
Upvotes: 2
Views: 3526
Reputation: 22144
Tornado's WSGIContainer does not support streaming responses from wsgi apps. You can either use Flask with a multi-threaded or greenlet-based wsgi server, or use Tornado's native RequestHandler interface, but not when you're combining Flask and Tornado with WSGIContainer.
Combining Flask and Tornado is usually not a good idea; see https://github.com/mitsuhiko/flask/issues/986
Upvotes: 4
Reputation: 8384
To use the url "../static/sse_client.js"
you need your webserver or your Flask app to serve the static JavaScript file. From the Flask docs:
To generate URLs for static files, use the special 'static' endpoint name:
url_for('static', filename='style.css')
The file has to be stored on the filesystem as static/style.css.
Upvotes: 0