Server-sent events with Python,Twisted and Flask: is this a correct approach for sleeping?
Your example uses twisted only as a wsgi container. As well as any other thread-based wsgi container it allows you to use time.sleep(1)
.
It is the case where allowing twisted to handle /my_event_source
directly might be beneficial. Here's an example from Using server sent events implemented in Python using twisted:
def cycle(echo): # Every second, sent a "ping" event. timestr = datetime.utcnow().isoformat()+"Z" echo("event: ping\n") echo('data: ' + json.dumps(dict(time=timestr))) echo("\n\n") # Send a simple message at random intervals. if random.random() < 0.1: echo("data: This is a message at time {}\n\n".format(timestr))class SSEResource(resource.Resource): def render_GET(self, request): request.setHeader("Content-Type", "text/event-stream") lc = task.LoopingCall(cycle, request.write) lc.start(1) # repeat every second request.notifyFinish().addBoth(lambda _: lc.stop()) return server.NOT_DONE_YET
where the client static/index.html
is from the same source:
<!doctype html><title>Using server-sent events</title><ol id="eventlist">nothing sent yet.</ol><script>if (!!window.EventSource) { var eventList = document.getElementById("eventlist"); var source = new EventSource('/my_event_source'); source.onmessage = function(e) { var newElement = document.createElement("li"); newElement.innerHTML = "message: " + e.data; eventList.appendChild(newElement); } source.addEventListener("ping", function(e) { var newElement = document.createElement("li"); var obj = JSON.parse(e.data); newElement.innerHTML = "ping at " + obj.time; eventList.appendChild(newElement); }, false); source.onerror = function(e) { alert("EventSource failed."); source.close(); };}</script>
You could combine it with your wsgi application:
app = Flask(__name__)@app.route('/')def index(): return redirect(url_for('static', filename='index.html'))if __name__ == "__main__": root = resource.Resource() root.putChild('', wsgi.WSGIResource(reactor, reactor.getThreadPool(), app)) root.putChild('static', static.File("./static")) root.putChild('my_event_source', SSEResource()) reactor.listenTCP(8001, server.Site(root)) reactor.run()
WSGIResource
expects to handle all urls so the routing code needs to be rewritten to support multiple flask handlers.