async def lobby_socket_handler(request): users = request.app["users"] sockets = request.app["websockets"] seeks = request.app["seeks"] games = request.app["games"] ws = MyWebSocketResponse() ws_ready = ws.can_prepare(request) if not ws_ready.ok: raise web.HTTPFound("/") await ws.prepare(request) session = await aiohttp_session.get_session(request) session_user = session.get("user_name") user = users[session_user] if session_user else None lobby_ping_task = None log.debug("-------------------------- NEW lobby WEBSOCKET by %s" % user) async for msg in ws: if msg.type == aiohttp.WSMsgType.TEXT: if type(msg.data) == str: if msg.data == "close": log.debug("Got 'close' msg.") break else: data = json.loads(msg.data) if not data["type"] == "pong": log.debug("Websocket (%s) message: %s" % (id(ws), msg)) if data["type"] == "pong": user.ping_counter -= 1 elif data["type"] == "get_seeks": response = get_seeks(seeks) await ws.send_json(response) elif data["type"] == "create_ai_challenge": variant = data["variant"] engine = users.get("Fairy-Stockfish") if engine is None or not engine.online: # TODO: message that engine is offline, but capture BOT will play instead engine = users.get("Random-Mover") seek = Seek(user, variant, data["fen"], data["color"], data["minutes"], data["increment"], data["level"], data["rated"], data["chess960"]) # print("SEEK", user, variant, data["fen"], data["color"], data["minutes"], data["increment"], data["level"], False, data["chess960"]) seeks[seek.id] = seek response = await new_game(request.app, engine, seek.id) await ws.send_json(response) gameId = response["gameId"] engine.game_queues[gameId] = asyncio.Queue() await engine.event_queue.put(challenge(seek, response)) elif data["type"] == "create_seek": print("create_seek", data) create_seek(seeks, user, data) await lobby_broadcast(sockets, get_seeks(seeks)) elif data["type"] == "delete_seek": del seeks[data["seekID"]] del user.seeks[data["seekID"]] await lobby_broadcast(sockets, get_seeks(seeks)) elif data["type"] == "accept_seek": if data["seekID"] not in seeks: continue seek = seeks[data["seekID"]] print("accept_seek", seek.as_json) response = await new_game(request.app, user, data["seekID"]) await ws.send_json(response) if seek.user.lobby_ws is not None: await seek.user.lobby_ws.send_json(response) if seek.user.bot: gameId = response["gameId"] seek.user.game_queues[gameId] = asyncio.Queue() await seek.user.event_queue.put(challenge(seek, response)) # Inform others, new_game() deleted accepted seek allready. await lobby_broadcast(sockets, get_seeks(seeks)) elif data["type"] == "lobby_user_connected": if session_user is not None: if data["username"] and data["username"] != session_user: log.info("+++ Existing lobby_user %s socket connected as %s." % (session_user, data["username"])) session_user = data["username"] if session_user in users: user = users[session_user] else: user = User(db=request.app["db"], username=data["username"], anon=data["username"].startswith("Anonymous")) users[user.username] = user response = {"type": "lobbychat", "user": "", "message": "%s joined the lobby" % session_user} else: user = users[session_user] response = {"type": "lobbychat", "user": "", "message": "%s joined the lobby" % session_user} else: log.info("+++ Existing lobby_user %s socket reconnected." % data["username"]) session_user = data["username"] if session_user in users: user = users[session_user] else: user = User(db=request.app["db"], username=data["username"], anon=data["username"].startswith("Anonymous")) users[user.username] = user response = {"type": "lobbychat", "user": "", "message": "%s rejoined the lobby" % session_user} user.ping_counter = 0 await lobby_broadcast(sockets, response) # update websocket sockets[user.username] = ws user.lobby_ws = ws response = {"type": "lobby_user_connected", "username": user.username} await ws.send_json(response) response = {"type": "fullchat", "lines": list(request.app["chat"])} await ws.send_json(response, dumps=partial(json.dumps, default=datetime.isoformat)) loop = asyncio.get_event_loop() lobby_ping_task = loop.create_task(user.pinger(sockets, seeks, users, games)) request.app["tasks"].add(lobby_ping_task) elif data["type"] == "lobbychat": response = {"type": "lobbychat", "user": user.username, "message": data["message"]} await lobby_broadcast(sockets, response) request.app["chat"].append(response) elif data["type"] == "disconnect": # Used only to test socket disconnection... await ws.close(code=1009) else: log.debug("type(msg.data) != str %s" % msg) elif msg.type == aiohttp.WSMsgType.ERROR: log.debug("!!! Lobby ws connection closed with exception %s" % ws.exception()) else: log.debug("other msg.type %s %s" % (msg.type, msg)) log.info("--- Lobby Websocket %s closed" % id(ws)) if lobby_ping_task is not None: lobby_ping_task.cancel() if user is not None: await user.clear_seeks(sockets, seeks) await user.quit_lobby(sockets, disconnect=False) return ws
async def event_stream(request): auth = request.headers.get("Authorization") if auth is None: return web.HTTPForbidden() token = auth[auth.find("Bearer") + 7:] if token not in BOT_TOKENS: log.error("BOT account auth with token %s failed" % token) return web.HTTPForbidden() user_agent = request.headers.get("User-Agent") username = user_agent[user_agent.find("user:"******"users"] seeks = request.app["seeks"] sockets = request.app["websockets"] games = request.app["games"] db = request.app["db"] resp = web.StreamResponse() resp.content_type = "text/plain" await resp.prepare(request) if username in users: bot_player = users[username] # After BOT lost connection it may have ongoing games # We notify BOT and he can ask to create new game_streams # to continue those games for gameId in bot_player.game_queues: if gameId in games and games[gameId].status == STARTED: await bot_player.event_queue.put(games[gameId].game_start) else: bot_player = User(bot=True, username=username) users[bot_player.username] = bot_player doc = await db.user.find_one({"_id": username}) if doc is None: result = await db.user.insert_one({ "_id": username, "first_name": None, "last_name": None, "country": None, "title": "BOT", }) print("db insert user result %s" % repr(result.inserted_id)) bot_player.bot_online = True log.info("+++ BOT %s connected" % bot_player.username) loop = asyncio.get_event_loop() pinger_task = loop.create_task( bot_player.pinger(sockets, seeks, users, games)) request.app["tasks"].add(pinger_task) # inform others # TODO: do we need this at all? await lobby_broadcast(sockets, get_seeks(seeks)) # send "challenge" and "gameStart" events from event_queue to the BOT while bot_player.online: answer = await bot_player.event_queue.get() try: if request.protocol.transport.is_closing(): log.error( "BOT %s request.protocol.transport.is_closing() == True ..." % username) break else: await resp.write(answer.encode("utf-8")) await resp.drain() except Exception: log.error("BOT %s event_stream is broken..." % username) break pinger_task.cancel() await bot_player.clear_seeks(sockets, seeks) return resp