70 lines
3.9 KiB
Python
70 lines
3.9 KiB
Python
# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
# ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
# ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
# ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
# ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
# ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
# ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
# ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
# ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
# ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
|
|
from aiohttp import web, WSMsgType
|
|
import perspective
|
|
import asyncio
|
|
|
|
|
|
class PerspectiveAIOHTTPHandler(object):
|
|
"""`PerspectiveAIOHTTPHandler` is a drop-in implementation of Perspective.
|
|
|
|
Use it inside AIOHTTP routing to create a server-side Perspective that is
|
|
ready to receive websocket messages from the front-end `perspective-viewer`.
|
|
|
|
The Perspective client and server will automatically keep the Websocket
|
|
alive without timing out.
|
|
|
|
# Security
|
|
|
|
`PerspectiveAIOHTTPHandler` is a reference integration with no
|
|
authentication, authorization, origin enforcement, or rate limiting,
|
|
and is not safe to expose to untrusted networks — see
|
|
[`SECURITY.md`](https://github.com/perspective-dev/perspective/blob/master/SECURITY.md)
|
|
for the full threat model.
|
|
|
|
# Examples
|
|
|
|
>>> server = Server()
|
|
>>> async def websocket_handler(request):
|
|
... handler = PerspectiveAIOHTTPHandler(perspective_server=server, request=request)
|
|
... await handler.run()
|
|
|
|
>>> app = web.Application()
|
|
>>> app.router.add_get("/websocket", websocket_handler)
|
|
"""
|
|
|
|
def __init__(self, **kwargs):
|
|
self.server = kwargs.pop("perspective_server", perspective.GLOBAL_SERVER)
|
|
self._request = kwargs.pop("request")
|
|
self._executor = kwargs.pop("executor", None)
|
|
self._loop = kwargs.pop("loop", asyncio.get_event_loop())
|
|
super().__init__(**kwargs)
|
|
|
|
async def run(self) -> web.WebSocketResponse:
|
|
def inner(msg):
|
|
self._loop.create_task(self._ws.send_bytes(msg))
|
|
|
|
self.session = self.server.new_session(inner)
|
|
try:
|
|
self._ws = web.WebSocketResponse()
|
|
await self._ws.prepare(self._request)
|
|
async for msg in self._ws:
|
|
if msg.type == WSMsgType.BINARY:
|
|
if self._executor is not None:
|
|
self._executor.submit(self.session.handle_request, msg.data)
|
|
else:
|
|
self.session.handle_request(msg.data)
|
|
finally:
|
|
self.session.close()
|
|
return self._ws
|