Last active
December 13, 2015 19:19
-
-
Save tehasdf/4962109 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from twisted.web.resource import Resource | |
from twisted.web import server | |
from flask import Flask, render_template_string | |
from twisted.web.wsgi import WSGIResource | |
from twisted.internet import reactor | |
from twisted.internet.task import LoopingCall | |
import json | |
INDEX_TEMPLATE = """ | |
<title>Hello world!</title> | |
<script> | |
var es = new EventSource("/es"); | |
var messageDump; | |
es.onerror = function(evt){ | |
mes("Closed!"); | |
}; | |
es.onopen = function(evt){ | |
mes("Open!"); | |
} | |
es.onmessage = function(evt){ | |
var text = JSON.parse(evt.data).data; | |
mes(text); | |
} | |
function mes(text){ | |
var li = document.createElement("li"); | |
li.innerText = text; | |
messageDump.insertBefore(li, messageDump.firstChild); | |
}; | |
document.addEventListener('DOMContentLoaded', function(){ | |
messageDump = document.getElementById("messages"); | |
}, false); | |
</script> | |
<ul id=messages> | |
</ul> | |
""" | |
# the twisted ES part, it just keeps the incoming requests as self.clients | |
class EventSource(Resource): | |
clients = [] | |
def send_event(self, request, event, data): | |
message = json.dumps({"event": event, "data": data}) | |
request.write('data: %s\n\n' % message) | |
def send_to_all(self, event, data): | |
for client in self.clients: | |
self.send_event(client, event, data) | |
def render_GET(self, request): | |
request.setResponseCode(200) | |
request.setHeader('Content-Type', 'text/event-stream') | |
request.notifyFinish().addBoth(self.close_es_request, request=request) | |
self.clients.append(request) | |
self.send_event(request, "hello", "Hello! There are %d clients connected" % len(self.clients)) | |
return server.NOT_DONE_YET | |
def send_old_events(self, request, last_id, count=10): | |
for num, (current_id, event, data) in enumerate(self._sent): | |
if num > count or current_id <= last_id: | |
break | |
self.send_event(request, event, data) | |
def close_es_request(self, error=None, request=None): | |
self.clients.remove(request) | |
# let's just instantiate one global ES resource | |
es_resource = EventSource() | |
# send a heartbeat to all ES clients once in a while just to see if it works | |
heartbeat = LoopingCall(es_resource.send_to_all, event="hearbeat", data="Heartbeat!") | |
heartbeat.start(5) | |
# flask app | |
app = Flask(__name__) | |
@app.route('/') | |
def index(): | |
return render_template_string(INDEX_TEMPLATE) | |
# serving stuff, boilerplate mostly | |
class Root(Resource): | |
def getChild(self, path, request): | |
request.postpath.insert(0, request.prepath.pop(0)) | |
return flaskAppResource | |
flaskAppResource = WSGIResource(reactor, reactor.getThreadPool(), app.wsgi_app) | |
root = Root() # /<anything> -> flask app, with the exception of... | |
root.putChild("es", es_resource) # /es -> EventSource() | |
site = server.Site(root) | |
reactor.listenTCP(5000, site) | |
reactor.run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment