| #!/usr/bin/env python3 | |
| import argparse | |
| import asyncio | |
| import logging | |
| import os | |
| import sys | |
| import time | |
| import websockets.server as ws_server | |
| from websockets.exceptions import ConnectionClosedError | |
| log = logging.getLogger(__name__) | |
| logging.basicConfig( | |
| format="[%(asctime)s] %(message)s", | |
| level=logging.DEBUG, | |
| ) | |
| async def echo(websocket): | |
| try: | |
| async for message in websocket: | |
| try: | |
| log.info(f'got request {message}') | |
| except Exception as e: | |
| log.error(f'error {e} getting path from {message}') | |
| await websocket.send(message) | |
| except ConnectionClosedError: | |
| pass | |
| async def on_async_conn(conn): | |
| rpath = str(conn.path) | |
| pcomps = rpath[1:].split('/') | |
| if len(pcomps) == 0: | |
| pcomps = ['echo'] # default handler | |
| log.info(f'connection for {pcomps}') | |
| if pcomps[0] == 'echo': | |
| log.info(f'/echo endpoint') | |
| for message in await conn.recv(): | |
| await conn.send(message) | |
| elif pcomps[0] == 'text': | |
| await conn.send('hello!') | |
| elif pcomps[0] == 'file': | |
| if len(pcomps) < 2: | |
| conn.close(code=4999, reason='unknown file') | |
| return | |
| fpath = os.path.join('../', pcomps[1]) | |
| if not os.path.exists(fpath): | |
| conn.close(code=4999, reason='file not found') | |
| return | |
| bufsize = 0 | |
| if len(pcomps) > 2: | |
| bufsize = int(pcomps[2]) | |
| if bufsize <= 0: | |
| bufsize = 16*1024 | |
| delay_ms = 0 | |
| if len(pcomps) > 3: | |
| delay_ms = int(pcomps[3]) | |
| n = 1 | |
| if len(pcomps) > 4: | |
| n = int(pcomps[4]) | |
| for _ in range(n): | |
| with open(fpath, 'r+b') as fd: | |
| while True: | |
| buf = fd.read(bufsize) | |
| if buf is None or len(buf) == 0: | |
| break | |
| await conn.send(buf) | |
| if delay_ms > 0: | |
| time.sleep(delay_ms/1000) | |
| else: | |
| log.info(f'unknown endpoint: {rpath}') | |
| await conn.close(code=4999, reason='path unknown') | |
| await conn.close(code=1000, reason='') | |
| async def run_server(port): | |
| log.info(f'starting server on port {port}') | |
| async with ws_server.serve(ws_handler=on_async_conn, | |
| host="localhost", port=port): | |
| await asyncio.Future() | |
| async def main(): | |
| parser = argparse.ArgumentParser(prog='scorecard', | |
| description="Run a websocket echo server.") | |
| parser.add_argument("--port", type=int, | |
| default=0, help="port to listen on") | |
| args = parser.parse_args() | |
| if args.port == 0: | |
| sys.stderr.write('need --port\n') | |
| sys.exit(1) | |
| logging.basicConfig( | |
| format="%(asctime)s %(message)s", | |
| level=logging.DEBUG, | |
| ) | |
| await run_server(args.port) | |
| if __name__ == "__main__": | |
| asyncio.run(main()) |