-
-
Notifications
You must be signed in to change notification settings - Fork 150
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
45a7e21
commit e0dc7f1
Showing
17 changed files
with
4,652 additions
and
11 deletions.
There are no files selected for viewing
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
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
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
import asyncio | ||
import sys | ||
from urllib.parse import urlsplit | ||
|
||
try: | ||
import tornado.web | ||
import tornado.websocket | ||
except ImportError: | ||
pass | ||
import six | ||
|
||
|
||
def get_tornado_handler(engineio_server): | ||
class Handler(tornado.websocket.WebSocketHandler): | ||
def __init__(self, *args, **kwargs): | ||
super().__init__(*args, **kwargs) | ||
self.receive_queue = asyncio.Queue() | ||
|
||
async def get(self): | ||
if self.request.headers.get('Upgrade', '').lower() == 'websocket': | ||
super().get() | ||
await engineio_server.handle_request(self) | ||
|
||
async def post(self): | ||
await engineio_server.handle_request(self) | ||
|
||
async def options(self): | ||
await engineio_server.handle_request(self) | ||
|
||
async def on_message(self, message): | ||
await self.receive_queue.put(message) | ||
|
||
async def get_next_message(self): | ||
return await self.receive_queue.get() | ||
|
||
def on_close(self): | ||
self.receive_queue.put_nowait(None) | ||
|
||
return Handler | ||
|
||
|
||
def translate_request(handler): | ||
"""This function takes the arguments passed to the request handler and | ||
uses them to generate a WSGI compatible environ dictionary. | ||
""" | ||
class AwaitablePayload(object): | ||
def __init__(self, payload): | ||
self.payload = payload or b'' | ||
|
||
async def read(self, length=None): | ||
if length is None: | ||
r = self.payload | ||
self.payload = b'' | ||
else: | ||
r = self.payload[:length] | ||
self.payload = self.payload[length:] | ||
return r | ||
|
||
payload = handler.request.body | ||
|
||
uri_parts = urlsplit(handler.request.path) | ||
environ = { | ||
'wsgi.input': AwaitablePayload(payload), | ||
'wsgi.errors': sys.stderr, | ||
'wsgi.version': (1, 0), | ||
'wsgi.async': True, | ||
'wsgi.multithread': False, | ||
'wsgi.multiprocess': False, | ||
'wsgi.run_once': False, | ||
'SERVER_SOFTWARE': 'aiohttp', | ||
'REQUEST_METHOD': handler.request.method, | ||
'QUERY_STRING': handler.request.query or '', | ||
'RAW_URI': handler.request.path, | ||
'SERVER_PROTOCOL': 'HTTP/%s' % handler.request.version, | ||
'REMOTE_ADDR': '127.0.0.1', | ||
'REMOTE_PORT': '0', | ||
'SERVER_NAME': 'aiohttp', | ||
'SERVER_PORT': '0', | ||
'tornado.handler': handler | ||
} | ||
|
||
for hdr_name, hdr_value in handler.request.headers.items(): | ||
hdr_name = hdr_name.upper() | ||
if hdr_name == 'CONTENT-TYPE': | ||
environ['CONTENT_TYPE'] = hdr_value | ||
continue | ||
elif hdr_name == 'CONTENT-LENGTH': | ||
environ['CONTENT_LENGTH'] = hdr_value | ||
continue | ||
|
||
key = 'HTTP_%s' % hdr_name.replace('-', '_') | ||
if key in environ: | ||
hdr_value = '%s,%s' % (environ[key], hdr_value) | ||
|
||
environ[key] = hdr_value | ||
|
||
environ['wsgi.url_scheme'] = environ.get('HTTP_X_FORWARDED_PROTO', 'http') | ||
|
||
path_info = uri_parts.path | ||
|
||
environ['PATH_INFO'] = path_info | ||
environ['SCRIPT_NAME'] = '' | ||
|
||
return environ | ||
|
||
|
||
def make_response(status, headers, payload, environ): | ||
"""This function generates an appropriate response object for this async | ||
mode. | ||
""" | ||
tornado_handler = environ['tornado.handler'] | ||
tornado_handler.set_status(int(status.split()[0])) | ||
for header, value in headers: | ||
tornado_handler.set_header(header, value) | ||
tornado_handler.write(payload) | ||
tornado_handler.finish() | ||
|
||
|
||
class WebSocket(object): # pragma: no cover | ||
""" | ||
This wrapper class provides a tornado WebSocket interface that is | ||
somewhat compatible with eventlet's implementation. | ||
""" | ||
def __init__(self, handler): | ||
self.handler = handler | ||
self.tornado_handler = None | ||
|
||
async def __call__(self, environ): | ||
self.tornado_handler = environ['tornado.handler'] | ||
self.environ = environ | ||
await self.handler(self) | ||
|
||
async def close(self): | ||
self.tornado_handler.close() | ||
|
||
async def send(self, message): | ||
self.tornado_handler.write_message( | ||
message, binary=isinstance(message, bytes)) | ||
|
||
async def wait(self): | ||
msg = await self.tornado_handler.get_next_message() | ||
if not isinstance(msg, six.binary_type) and \ | ||
not isinstance(msg, six.text_type): | ||
raise IOError() | ||
return msg | ||
|
||
|
||
_async = { | ||
'asyncio': True, | ||
'translate_request': translate_request, | ||
'make_response': make_response, | ||
'websocket': sys.modules[__name__], | ||
'websocket_class': 'WebSocket' | ||
} |
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
Engine.IO Examples | ||
================== | ||
|
||
This directory contains example Engine.IO applications that are compatible | ||
with the Tornado framework. These applications require Tornado 5 and Python | ||
3.5 or later. | ||
|
||
simple.py | ||
--------- | ||
|
||
A basic application in which the client sends messages to the server and the | ||
server responds. | ||
|
||
latency.py | ||
---------- | ||
|
||
A port of the latency application included in the official Engine.IO | ||
Javascript server. In this application the client sends *ping* messages to | ||
the server, which are responded by the server with a *pong*. The client | ||
measures the time it takes for each of these exchanges and plots these in real | ||
time to the page. | ||
|
||
This is an ideal application to measure the performance of the different | ||
asynchronous modes supported by the Engine.IO server. | ||
|
||
Running the Examples | ||
-------------------- | ||
|
||
To run these examples, create a virtual environment, install the requirements | ||
and then run:: | ||
|
||
$ python simple.py | ||
|
||
or:: | ||
|
||
$ python latency.py | ||
|
||
You can then access the application from your web browser at | ||
``http://localhost:8888``. |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import os | ||
|
||
import tornado.ioloop | ||
from tornado.options import define, options, parse_command_line | ||
import tornado.web | ||
|
||
import engineio | ||
|
||
define("port", default=8888, help="run on the given port", type=int) | ||
define("debug", default=False, help="run in debug mode") | ||
|
||
eio = engineio.AsyncServer(async_mode='tornado') | ||
|
||
|
||
class MainHandler(tornado.web.RequestHandler): | ||
def get(self): | ||
self.render("latency.html") | ||
|
||
|
||
@eio.on('message') | ||
async def message(sid, data): | ||
await eio.send(sid, 'pong', binary=False) | ||
|
||
|
||
def main(): | ||
parse_command_line() | ||
app = tornado.web.Application( | ||
[ | ||
(r"/", MainHandler), | ||
(r"/engine.io/", engineio.get_tornado_handler(eio)), | ||
], | ||
template_path=os.path.join(os.path.dirname(__file__), "templates"), | ||
static_path=os.path.join(os.path.dirname(__file__), "static"), | ||
debug=options.debug, | ||
) | ||
app.listen(options.port) | ||
tornado.ioloop.IOLoop.current().start() | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
tornado==5.0.2 | ||
python-engineio | ||
six==1.10.0 |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import os | ||
|
||
import tornado.ioloop | ||
from tornado.options import define, options, parse_command_line | ||
import tornado.web | ||
|
||
import engineio | ||
from engineio.async_tornado import get_engineio_handler | ||
|
||
define("port", default=8888, help="run on the given port", type=int) | ||
define("debug", default=False, help="run in debug mode") | ||
|
||
eio = engineio.AsyncServer(async_mode='tornado') | ||
|
||
|
||
class MainHandler(tornado.web.RequestHandler): | ||
def get(self): | ||
self.render("simple.html") | ||
|
||
|
||
@eio.on('connect') | ||
def connect(sid, environ): | ||
print("connect ", sid) | ||
|
||
|
||
@eio.on('message') | ||
async def message(sid, data): | ||
print('message from', sid, data) | ||
await eio.send(sid, 'Thank you for your message!', binary=False) | ||
|
||
|
||
@eio.on('disconnect') | ||
def disconnect(sid): | ||
print('disconnect ', sid) | ||
|
||
|
||
def main(): | ||
parse_command_line() | ||
app = tornado.web.Application( | ||
[ | ||
(r"/", MainHandler), | ||
(r"/engine.io/", engineio.get_tornado_handler(eio)), | ||
], | ||
template_path=os.path.join(os.path.dirname(__file__), "templates"), | ||
static_path=os.path.join(os.path.dirname(__file__), "static"), | ||
debug=options.debug, | ||
) | ||
app.listen(options.port) | ||
tornado.ioloop.IOLoop.current().start() | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
Oops, something went wrong.