import asyncio import json import pysqlite3 as sql import sanic app = sanic.Sanic() DB = sql.connect('samp.db') CONNECTIONS = {} def get_backlog(game: str, c=None) -> [(str, str)]: if c is None: c = DB.cursor() c.execute('SELECT c.user, c.content FROM chat c, games g WHERE c.game = g.id AND g.name = ?', [game]) return list(c) def get_game_id(game: str, c=None) -> int: if c is None: c = DB.cursor() c.execute('SELECT id FROM games WHERE name = ?', [game]) return c.fetchone()[0] def add_msg(user: str, content: str, game: str, c=None): if c is None: c = DB.cursor() game_id = get_game_id(game, c) c.execute('INSERT INTO chat (game, user, content) VALUES (?, ?, ?)', [game_id, user, content]) DB.commit() @app.route("/static/") async def static(request, f): return await sanic.response.file('static/{}'.format(f)) @app.route("/") async def index(request): return await sanic.response.file('static/index.html') @app.websocket("/socket") async def socket(request, ws): initial = await ws.recv() config = json.loads(initial) user = config['user'] game = config['game'] sanic.log.logger.info(f'connected websocket for {user} in game {game}') if game not in CONNECTIONS: CONNECTIONS[game] = set() CONNECTIONS[game].add(ws) try: for (author, content) in get_backlog(game): await ws.send(json.dumps({"author": author, "content": content})) async for payload in ws: msg = json.loads(payload) add_msg(user, msg['content'], game) for w in CONNECTIONS[game]: await w.send(json.dumps({"author": user, "content": msg["content"]})) finally: sanic.log.logger.info('removing websocket for {}'.format(config['game'])) CONNECTIONS[config['game']].remove(ws) if __name__ == '__main__': try: app.run() finally: DB.close()