You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

93 lines
3.3 KiB
Python

#!/usr/bin/env python3
import sys, os, asyncio, json, argparse
import aiohttp, aiohttp_jinja2, jinja2
from aiohttp import web
# from urllib.parse import urlparse, unquote as urlunquote, quote as urlquote
async def index (request):
ws = web.WebSocketResponse()
ws_ready = ws.can_prepare(request)
if not ws_ready.ok:
return aiohttp_jinja2.render_template(request.app['template'], request, {})
await ws.prepare(request)
# print('index.Websocket connection ready')
connections = request.app['websockets']
connections.append(ws)
await ws.send_str(json.dumps({'src': 'connect', 'connections': len(connections)}))
print ("{} active connections".format(len(connections)))
# incoming messages
async for msg in ws:
print ("index.got msg")
if msg.type == aiohttp.WSMsgType.TEXT:
print(msg.data)
if msg.data == 'close':
await ws.close()
# else:
# await ws.send_str(msg.data + '/answer')
# if the connection closes, the above loop simply finishes
# and we arrive here
connections.remove(ws)
print ("{} active connections".format(len(connections)))
return ws
# The following is a fusion of:
# https://stackoverflow.com/questions/31510190/aysncio-cannot-read-stdin-on-windows#36785819
# https://docs.aiohttp.org/en/stable/web_advanced.html#background-tasks
async def listen_to_stdin(app):
loop = asyncio.get_event_loop()
try:
while True:
line = await loop.run_in_executor(None, sys.stdin.readline)
for ws in app['websockets']:
await ws.send_str(json.dumps({'src': 'stdin', 'line': line.rstrip()}))
except asyncio.CancelledError:
pass
finally:
pass
async def start_background_tasks(app):
app['stdin_listener'] = asyncio.create_task(listen_to_stdin(app))
async def cleanup_background_tasks(app):
app['stdin_listener'].cancel()
await app['stdin_listener']
def main ():
ap = argparse.ArgumentParser("make & serve")
ap.add_argument("--host", default="localhost")
ap.add_argument("--port", type=int, default=8080)
ap.add_argument("--static", nargs=2, default=None, action="append")
ap.add_argument("--template", default="pipeserver.html", help="Template for web page to serve")
args = ap.parse_args()
# On Windows, the default event loop is SelectorEventLoop which does not support run_in_executor. ProactorEventLoop should be used instead.
if sys.platform == 'win32':
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)
app = web.Application()
app['websockets'] = []
template_path, app['template'] = os.path.split(args.template)
jinja_env = aiohttp_jinja2.setup(
app, loader=jinja2.FileSystemLoader(template_path))
# jinja_env.filters['datetimeformat'] = format_datetime
# setup routes
app.add_routes([web.get('/', index)])
if args.static:
for name, path in args.static:
print ("Adding static route {0} -> {1}".format(name, path))
app.router.add_static(name, path)
app.on_startup.append(start_background_tasks)
app.on_cleanup.append(cleanup_background_tasks)
web.run_app(app, host=args.host, port=args.port)
if __name__ == "__main__":
main()