$ pip install falcon
$ python3 app.py
alternatively with Gunicorn (for HTTP/1.1):
$ pip install gunicorn
$ gunicorn app:app
from asyncio import Future, Task, coroutine as async, sleep | |
from random import randint | |
def retrieve(*uris, callback=None): | |
res = Future() | |
responses = [] | |
def conclude(response): | |
responses.append(response) | |
if callback: | |
callback(response) | |
if len(responses) == len(uris): | |
res.set_result(responses) | |
for uri in uris: | |
task = Task(fetch(uri)) | |
task.add_done_callback(lambda task: conclude(task.result())) | |
return res | |
@async | |
def fetch(uri): | |
print("retrieving %s..." % uri) | |
lag = yield from _http() | |
lag = lag * 1000 | |
print("downloaded %s in %d ms" % (uri, lag)) | |
return "[%d ms] %s\n" % (lag, uri) | |
@async | |
def _http(): | |
lag = randint(2, 9) * 0.1 | |
yield from sleep(lag) | |
return lag |
import asyncio | |
import falcon | |
import aggregator | |
from wsgiref import simple_server | |
class Frontpage: | |
def on_get(self, req, res): | |
uris = ("http://example.org/foo", "http://example.org/bar", | |
"http://example.org/baz") | |
res.stream = ResponseStream(res.stream) | |
service_requests = aggregator.retrieve(*uris, | |
callback=res.stream.write) # XXX: race condition? `write` vs. `__iter__` | |
loop = asyncio.get_event_loop() | |
loop.run_until_complete(service_requests) | |
class ResponseStream: | |
def __init__(self, output_stream): | |
self.output_stream = output_stream | |
self.chunks = [] | |
def write(self, chunk): | |
self.chunks.append(chunk) | |
def __iter__(self, *args, **kwargs): | |
while True: | |
try: | |
chunk = self.chunks.pop(0) # XXX: inefficient? | |
yield chunk.encode("utf8") | |
except IndexError: | |
break | |
app = falcon.API() | |
app.add_route("/", Frontpage()) | |
if __name__ == "__main__": | |
server = simple_server.make_server("localhost", 8000, app) | |
server.serve_forever() |