async def create_bot_seek(request): user_agent = request.headers.get("User-Agent") username = user_agent[user_agent.find("user:"******"users"] seeks = request.app["seeks"] sockets = request.app["lobbysockets"] bot_player = users[username] log.info("+++ %s created %s seek", bot_player.username, data["variant"]) # Try to create BOT vs BOT game to test TV test_TV = True matching_seek = None if test_TV: for seek in seeks.values(): if (seek.variant == data["variant"] and seek.creator.bot and seek.creator.online and seek.creator.username != username and seek.level > 0): log.debug("MATCHING BOT SEEK %s FOUND!", seek.id) matching_seek = seek break if matching_seek is None: seek = None for existing_seek in seeks.values(): if existing_seek.creator == bot_player and existing_seek.variant == data[ "variant"]: seek = existing_seek break if seek is None: seek = Seek(bot_player, data["variant"], player1=bot_player) seeks[seek.id] = seek bot_player.seeks[seek.id] = seek # inform others await lobby_broadcast(sockets, get_seeks(seeks)) else: games = request.app["games"] response = await join_seek(request.app, bot_player, matching_seek.id) gameId = response["gameId"] game = games[gameId] chall = challenge(seek, gameId) await seek.creator.event_queue.put(chall) seek.creator.game_queues[gameId] = asyncio.Queue() await bot_player.event_queue.put(chall) bot_player.game_queues[gameId] = asyncio.Queue() await seek.creator.event_queue.put(game.game_start) await bot_player.event_queue.put(game.game_start) return web.json_response({"ok": True})
async def clear_seeks(self, sockets, seeks): has_seek = len(self.seeks) > 0 if has_seek: for seek in self.seeks: del seeks[seek] self.seeks.clear() await lobby_broadcast(sockets, get_seeks(seeks))
async def clear_seeks(self, sockets, seeks): has_seek = len(self.seeks) > 0 if has_seek and len(self.lobby_sockets) == 0: for seek in self.seeks: game_id = self.seeks[seek].game_id # preserve invites (seek with game_id)! if game_id is None: del seeks[seek] self.seeks.clear() await lobby_broadcast(sockets, get_seeks(seeks))
async def clear_seeks(self, force=False): has_seek = len(self.seeks) > 0 if has_seek and (len(self.lobby_sockets) == 0 or force): seeks = self.app["seeks"] sockets = self.app["lobbysockets"] for seek in self.seeks: game_id = self.seeks[seek].game_id # preserve invites (seek with game_id)! if game_id is None: del seeks[seek] self.seeks.clear() await lobby_broadcast(sockets, get_seeks(seeks))
async def fishnet_acquire(request): data = await request.json() fm = request.app["fishnet_monitor"] fv = request.app["fishnet_versions"] key = data["fishnet"]["apikey"] version = data["fishnet"]["version"] en = data["stockfish"]["name"] worker = FISHNET_KEYS[key] fv[worker] = "%s %s" % (version, en) if key not in FISHNET_KEYS: return web.Response(status=404) if key not in request.app["workers"]: request.app["workers"].add(key) fm[worker].append("%s %s %s" % (datetime.utcnow(), "-", "joined")) request.app["users"]["Fairy-Stockfish"].bot_online = True if not request.app["users"]["Fairy-Stockfish"].seeks: ai = request.app["users"]["Fairy-Stockfish"] seeks = request.app["seeks"] sockets = request.app["websockets"] for variant in VARIANTS: variant960 = variant.endswith("960") variant_name = variant[:-3] if variant960 else variant seek = Seek(ai, variant_name, color="r", base=5, inc=3, level=6, chess960=variant960) seeks[seek.id] = seek ai.seeks[seek.id] = seek await lobby_broadcast(sockets, get_seeks(seeks)) response = await get_work(request, data) return response
async def lobby_socket_handler(request): users = request.app["users"] sockets = request.app["lobbysockets"] seeks = request.app["seeks"] ws = WebSocketResponse(heartbeat=3.0, receive_timeout=10.0) 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 is not None and session_user in users else None if (user is not None) and (not user.enabled): await ws.close() session.invalidate() raise web.HTTPFound("/") log.debug("-------------------------- NEW lobby WEBSOCKET by %s" % user) try: async for msg in ws: if msg.type == aiohttp.WSMsgType.TEXT: 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"] == "get_seeks": response = get_seeks(seeks) await ws.send_json(response) elif data["type"] == "create_ai_challenge": no = await is_playing(request, user, ws) if no: continue 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, fen=data["fen"], color=data["color"], base=data["minutes"], inc=data["increment"], byoyomi_period=data["byoyomiPeriod"], level=data["level"], rated=data["rated"], chess960=data["chess960"], alternate_start=data["alternateStart"]) # 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) if response["type"] != "error": gameId = response["gameId"] engine.game_queues[gameId] = asyncio.Queue() await engine.event_queue.put( challenge(seek, response)) elif data["type"] == "create_seek": no = await is_playing(request, user, ws) if no: continue print("create_seek", data) create_seek(seeks, user, data, ws) await lobby_broadcast(sockets, get_seeks(seeks)) if data.get("target"): queue = users[data["target"]].notify_queue if queue is not None: await queue.put( json.dumps({"notify": "new_challenge"})) 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": no = await is_playing(request, user, ws) if no: continue 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.bot: gameId = response["gameId"] seek.user.game_queues[gameId] = asyncio.Queue() await seek.user.event_queue.put( challenge(seek, response)) else: await seek.ws.send_json(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( request.app, username=data["username"], anon=data["username"].startswith( "Anon-")) users[user.username] = user response = { "type": "lobbychat", "user": "", "message": "%s joined the lobby" % session_user } else: if session_user in users: user = users[session_user] else: user = User( request.app, username=data["username"], anon=data["username"].startswith( "Anon-")) users[user.username] = 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( request.app, username=data["username"], anon=data["username"].startswith("Anon-")) users[user.username] = user response = { "type": "lobbychat", "user": "", "message": "%s rejoined the lobby" % session_user } await lobby_broadcast(sockets, response) # update websocket user.lobby_sockets.add(ws) sockets[user.username] = user.lobby_sockets 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) # send game count response = { "type": "g_cnt", "cnt": request.app["g_cnt"] } await ws.send_json(response) # send user count response = { "type": "u_cnt", "cnt": online_count(users) } if len(user.game_sockets) == 0: await lobby_broadcast(sockets, response) else: await ws.send_json(response) 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"] == "logout": await ws.close() elif data["type"] == "disconnect": # Used only to test socket disconnection... await ws.close(code=1009) elif msg.type == aiohttp.WSMsgType.CLOSED: log.debug( "--- Lobby websocket %s msg.type == aiohttp.WSMsgType.CLOSED" % id(ws)) break elif msg.type == aiohttp.WSMsgType.ERROR: log.error( "--- Lobby ws %s msg.type == aiohttp.WSMsgType.ERROR" % id(ws)) break else: log.debug("--- Lobby ws other msg.type %s %s" % (msg.type, msg)) except concurrent.futures._base.CancelledError: # client disconnected pass except Exception as e: log.error("!!! Lobby ws exception occured: %s" % type(e)) finally: log.debug("---fianlly: await ws.close()") await ws.close() if user is not None: if ws in user.lobby_sockets: user.lobby_sockets.remove(ws) # online user counter will be updated in quit_lobby also! if len(user.lobby_sockets) == 0: if user.username in sockets: del sockets[user.username] # not connected to lobby socket and not connected to game socket if len(user.game_sockets) == 0: response = {"type": "u_cnt", "cnt": online_count(users)} await lobby_broadcast(sockets, response) response = { "type": "lobbychat", "user": "", "message": "%s left the lobby" % user.username } await lobby_broadcast(sockets, response) await user.clear_seeks(sockets, seeks) return ws
async def create_bot_seek(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["lobbysockets"] bot_player = users[username] log.info("+++ %s created %s seek", bot_player.username, data["variant"]) # Try to create BOT vs BOT game to test TV test_TV = True matching_seek = None if test_TV: for seek in seeks.values(): if seek.variant == data[ "variant"] and seek.user.bot and seek.user.online and seek.user.username != username and seek.level > 0: log.debug("MATCHING BOT SEEK %s FOUND!", seek.id) matching_seek = seek break if matching_seek is None: seek = None for existing_seek in seeks.values(): if existing_seek.user == bot_player and existing_seek.variant == data[ "variant"]: seek = existing_seek break if seek is None: seek = Seek(bot_player, data["variant"]) seeks[seek.id] = seek bot_player.seeks[seek.id] = seek # inform others await lobby_broadcast(sockets, get_seeks(seeks)) else: games = request.app["games"] response = await new_game(request.app, bot_player, matching_seek.id) gameId = response["gameId"] game = games[gameId] chall = challenge(seek, gameId) await seek.user.event_queue.put(chall) seek.user.game_queues[gameId] = asyncio.Queue() await bot_player.event_queue.put(chall) bot_player.game_queues[gameId] = asyncio.Queue() await seek.user.event_queue.put(game.game_start) await bot_player.event_queue.put(game.game_start) return web.json_response({"ok": True})
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["lobbysockets"] 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(request.app, 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.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)) # 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: bot_player.event_queue.task_done() except ValueError: log.error( "task_done() called more times than there were items placed in the queue in bot_api.py event_stream()" ) 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
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 is not None and session_user in users 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"], data["handicap"]) # 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)) if data.get("target"): queue = users[data["target"]].notify_queue if queue is not None: await queue.put( json.dumps({"notify": "new_challenge"})) 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( request.app, username=data["username"], anon=data["username"].startswith( "Anon-")) users[user.username] = user response = { "type": "lobbychat", "user": "", "message": "%s joined the lobby" % session_user } else: if session_user in users: user = users[session_user] else: user = User( request.app, username=data["username"], anon=data["username"].startswith( "Anon-")) users[user.username] = 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( request.app, username=data["username"], anon=data["username"].startswith("Anon-")) 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) loop = asyncio.get_event_loop() lobby_ping_task = loop.create_task( user.pinger(sockets, seeks, users, games)) request.app["tasks"].add(lobby_ping_task) # send game count response = { "type": "g_cnt", "cnt": request.app["g_cnt"] } await ws.send_json(response) # send user count if len(user.game_sockets) == 0: # not connected to any game socket but connected to lobby socket request.app["u_cnt"] += 1 response = { "type": "u_cnt", "cnt": request.app["u_cnt"] } await lobby_broadcast(sockets, response) else: response = { "type": "u_cnt", "cnt": request.app["u_cnt"] } await ws.send_json(response) 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"] == "logout": await ws.close() 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) # online user counter will be updated in quit_lobby also! await user.quit_lobby(sockets, disconnect=False) return ws
async def lobby_socket_handler(request): users = request.app["users"] sockets = request.app["lobbysockets"] seeks = request.app["seeks"] db = request.app["db"] invites = request.app["invites"] twitch = request.app["twitch"] youtube = request.app["youtube"] lobbychat = request.app["lobbychat"] ws = MyWebSocketResponse(heartbeat=3.0, receive_timeout=10.0) ws_ready = ws.can_prepare(request) if not ws_ready.ok: return 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 is not None and session_user in users else None if (user is not None) and (not user.enabled): await ws.close() session.invalidate() return web.HTTPFound("/") log.debug("-------------------------- NEW lobby WEBSOCKET by %s", user) try: async for msg in ws: if msg.type == aiohttp.WSMsgType.TEXT: 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"] == "get_seeks": response = get_seeks(seeks) await ws.send_json(response) elif data["type"] == "create_ai_challenge": no = await is_playing(request, user, ws) if no: continue variant = data["variant"] engine = users.get("Fairy-Stockfish") if data["rm"] or (engine is None) or (not engine.online): # TODO: message that engine is offline, but Random-Mover BOT will play instead engine = users.get("Random-Mover") seek = Seek( user, variant, fen=data["fen"], color=data["color"], base=data["minutes"], inc=data["increment"], byoyomi_period=data["byoyomiPeriod"], level=0 if data["rm"] else data["level"], player1=user, rated=False, chess960=data["chess960"], alternate_start=data["alternateStart"], ) # print("SEEK", user, variant, data["fen"], data["color"], data["minutes"], data["increment"], data["level"], False, data["chess960"]) seeks[seek.id] = seek response = await join_seek(request.app, engine, seek.id) await ws.send_json(response) if response["type"] != "error": gameId = response["gameId"] engine.game_queues[gameId] = asyncio.Queue() await engine.event_queue.put( challenge(seek, response)) elif data["type"] == "create_seek": no = await is_playing(request, user, ws) if no: continue print("create_seek", data) seek = await create_seek(db, invites, seeks, user, data, ws) await lobby_broadcast(sockets, get_seeks(seeks)) await discord_message(request.app, "create_seek", seek.discord_msg) elif data["type"] == "create_invite": no = await is_playing(request, user, ws) if no: continue print("create_invite", data) seek = await create_seek(db, invites, seeks, user, data, ws) response = { "type": "invite_created", "gameId": seek.game_id } await ws.send_json(response) elif data["type"] == "create_host": no = user.username not in TOURNAMENT_DIRECTORS if no: continue print("create_host", data) seek = await create_seek(db, invites, seeks, user, data, ws, True) response = { "type": "host_created", "gameId": seek.game_id } await ws.send_json(response) elif data["type"] == "delete_seek": try: seek = seeks[data["seekID"]] if seek.game_id is not None: # delete game invite del invites[seek.game_id] del seeks[data["seekID"]] del user.seeks[data["seekID"]] except KeyError: # Seek was already deleted pass await lobby_broadcast(sockets, get_seeks(seeks)) elif data["type"] == "accept_seek": no = await is_playing(request, user, ws) if no: continue if data["seekID"] not in seeks: continue seek = seeks[data["seekID"]] # print("accept_seek", seek.as_json) response = await join_seek(request.app, user, data["seekID"]) await ws.send_json(response) if seek.creator.bot: gameId = response["gameId"] seek.creator.game_queues[gameId] = asyncio.Queue() await seek.creator.event_queue.put( challenge(seek, response)) else: if seek.ws is None: remove_seek(seeks, seek) await lobby_broadcast(sockets, get_seeks(seeks)) else: await seek.ws.send_json(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( request.app, username=data["username"], anon=data["username"].startswith( "Anon-"), ) users[user.username] = user else: if session_user in users: user = users[session_user] else: user = User( request.app, username=data["username"], anon=data["username"].startswith( "Anon-"), ) users[user.username] = 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( request.app, username=data["username"], anon=data["username"].startswith("Anon-"), ) users[user.username] = user # update websocket user.lobby_sockets.add(ws) user.update_online() sockets[user.username] = user.lobby_sockets response = { "type": "lobby_user_connected", "username": user.username, } await ws.send_json(response) response = { "type": "fullchat", "lines": list(lobbychat) } await ws.send_json(response) # send game count response = { "type": "g_cnt", "cnt": request.app["g_cnt"][0] } await ws.send_json(response) # send user count response = { "type": "u_cnt", "cnt": online_count(users) } if len(user.game_sockets) == 0: await lobby_broadcast(sockets, response) else: await ws.send_json(response) spotlights = tournament_spotlights( request.app["tournaments"]) if len(spotlights) > 0: await ws.send_json({ "type": "spotlights", "items": spotlights }) streams = twitch.live_streams + youtube.live_streams if len(streams) > 0: await ws.send_json({ "type": "streams", "items": streams }) elif data["type"] == "lobbychat": if user.username.startswith("Anon-"): continue message = data["message"] response = None if user.username in ADMINS: if message.startswith("/silence"): response = silence(message, lobbychat, users) # silence message was already added to lobbychat in silence() elif message.startswith("/stream"): parts = message.split() if len(parts) >= 3: if parts[1] == "add": if len(parts) >= 5: youtube.add( parts[2], parts[3], parts[4]) elif len(parts) >= 4: youtube.add(parts[2], parts[3]) else: youtube.add(parts[2]) elif parts[1] == "remove": youtube.remove(parts[2]) await broadcast_streams(request.app) elif message == "/state": server_state(request.app) else: response = chat_response( "lobbychat", user.username, data["message"]) lobbychat.append(response) elif user.anon and user.username != "Discord-Relay": pass else: if user.silence == 0: response = chat_response( "lobbychat", user.username, data["message"]) lobbychat.append(response) if response is not None: await lobby_broadcast(sockets, response) elif data["type"] == "logout": await ws.close() elif data["type"] == "disconnect": # Used only to test socket disconnection... await ws.close(code=1009) elif msg.type == aiohttp.WSMsgType.CLOSED: log.debug( "--- Lobby websocket %s msg.type == aiohttp.WSMsgType.CLOSED", id(ws), ) break elif msg.type == aiohttp.WSMsgType.ERROR: log.error( "--- Lobby ws %s msg.type == aiohttp.WSMsgType.ERROR", id(ws)) break else: log.debug("--- Lobby ws other msg.type %s %s", msg.type, msg) except OSError: # disconnected pass except Exception: log.exception( "ERROR: Exception in lobby_socket_handler() owned by %s ", session_user) finally: log.debug("--- wsl.py fianlly: await ws.close() %s", session_user) await ws.close() if user is not None: if ws in user.lobby_sockets: user.lobby_sockets.remove(ws) user.update_online() # online user counter will be updated in quit_lobby also! if len(user.lobby_sockets) == 0: if user.username in sockets: del sockets[user.username] # not connected to lobby socket and not connected to game socket if len(user.game_sockets) == 0: response = {"type": "u_cnt", "cnt": online_count(users)} await lobby_broadcast(sockets, response) # response = {"type": "lobbychat", "user": "", "message": "%s left the lobby" % user.username} # await lobby_broadcast(sockets, response) await user.clear_seeks() return ws
async def lobby_socket_handler(request): users = request.app["users"] sockets = request.app["lobbysockets"] seeks = request.app["seeks"] db = request.app["db"] invites = request.app["invites"] ws = MyWebSocketResponse(heartbeat=3.0, receive_timeout=10.0) ws_ready = ws.can_prepare(request) if not ws_ready.ok: return 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 is not None and session_user in users else None if (user is not None) and (not user.enabled): await ws.close() session.invalidate() return web.HTTPFound("/") log.debug("-------------------------- NEW lobby WEBSOCKET by %s", user) try: async for msg in ws: if msg.type == aiohttp.WSMsgType.TEXT: 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"] == "get_seeks": response = get_seeks(seeks) await ws.send_json(response) elif data["type"] == "create_ai_challenge": no = await is_playing(request, user, ws) if no: continue 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, fen=data["fen"], color=data["color"], base=data["minutes"], inc=data["increment"], byoyomi_period=data["byoyomiPeriod"], level=data["level"], rated=data["rated"], chess960=data["chess960"], alternate_start=data["alternateStart"]) # 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) if response["type"] != "error": gameId = response["gameId"] engine.game_queues[gameId] = asyncio.Queue() await engine.event_queue.put( challenge(seek, response)) elif data["type"] == "create_seek": no = await is_playing(request, user, ws) if no: continue print("create_seek", data) seek = await create_seek(db, invites, seeks, user, data, ws) await lobby_broadcast(sockets, get_seeks(seeks)) if data.get("target"): queue = users[data["target"]].notify_queue if queue is not None: await queue.put( json.dumps({"notify": "new_challenge"})) # Send msg to discord-relay BOT try: for dr_ws in sockets["Discord-Relay"]: await dr_ws.send_json({ "type": "create_seek", "message": seek.discord_msg }) break except (KeyError, ConnectionResetError): # BOT disconnected log.error("--- Discord-Relay disconnected!") elif data["type"] == "create_invite": no = await is_playing(request, user, ws) if no: continue print("create_invite", data) seek = await create_seek(db, invites, seeks, user, data, ws) response = get_seeks(seeks) await ws.send_json(response) response = { "type": "invite_created", "gameId": seek.game_id } await ws.send_json(response) elif data["type"] == "delete_seek": try: seek = seeks[data["seekID"]] if seek.game_id is not None: # delete game invite del invites[seek.game_id] del seeks[data["seekID"]] del user.seeks[data["seekID"]] except KeyError: # Seek was already deleted pass await lobby_broadcast(sockets, get_seeks(seeks)) elif data["type"] == "accept_seek": no = await is_playing(request, user, ws) if no: continue 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.bot: gameId = response["gameId"] seek.user.game_queues[gameId] = asyncio.Queue() await seek.user.event_queue.put( challenge(seek, response)) else: await seek.ws.send_json(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( request.app, username=data["username"], anon=data["username"].startswith( "Anon-")) users[user.username] = user # response = {"type": "lobbychat", "user": "", "message": "%s joined the lobby" % session_user} else: if session_user in users: user = users[session_user] else: user = User( request.app, username=data["username"], anon=data["username"].startswith( "Anon-")) users[user.username] = 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( request.app, username=data["username"], anon=data["username"].startswith("Anon-")) users[user.username] = user # response = {"type": "lobbychat", "user": "", "message": "%s rejoined the lobby" % session_user} # await lobby_broadcast(sockets, response) # update websocket user.lobby_sockets.add(ws) user.update_online() sockets[user.username] = user.lobby_sockets 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) # send game count response = { "type": "g_cnt", "cnt": request.app["g_cnt"] } await ws.send_json(response) # send user count response = { "type": "u_cnt", "cnt": online_count(users) } if len(user.game_sockets) == 0: await lobby_broadcast(sockets, response) else: await ws.send_json(response) elif data["type"] == "lobbychat": message = data["message"] response = None if user.username in ADMINS: if message.startswith("/silence"): spammer = data["message"].split()[-1] if spammer in users: users[spammer].set_silence() response = { "type": "lobbychat", "user": "", "message": "%s was timed out 10 minutes for spamming the chat." % spammer } elif message == "/growth": server_growth() elif message == "/state": server_state(request.app) else: response = { "type": "lobbychat", "user": user.username, "message": data["message"] } elif user.anon and user.username != "Discord-Relay": pass else: if user.silence == 0: response = { "type": "lobbychat", "user": user.username, "message": data["message"] } if response is not None: await lobby_broadcast(sockets, response) request.app["chat"].append(response) elif data["type"] == "logout": await ws.close() elif data["type"] == "disconnect": # Used only to test socket disconnection... await ws.close(code=1009) elif msg.type == aiohttp.WSMsgType.CLOSED: log.debug( "--- Lobby websocket %s msg.type == aiohttp.WSMsgType.CLOSED", id(ws)) break elif msg.type == aiohttp.WSMsgType.ERROR: log.error( "--- Lobby ws %s msg.type == aiohttp.WSMsgType.ERROR", id(ws)) break else: log.debug("--- Lobby ws other msg.type %s %s", msg.type, msg) except OSError: # disconnected pass except Exception: log.exception( "ERROR: Exception in lobby_socket_handler() owned by %s ", session_user) finally: log.debug("--- wsl.py fianlly: await ws.close() %s", session_user) await ws.close() if user is not None: if ws in user.lobby_sockets: user.lobby_sockets.remove(ws) user.update_online() # online user counter will be updated in quit_lobby also! if len(user.lobby_sockets) == 0: if user.username in sockets: del sockets[user.username] # not connected to lobby socket and not connected to game socket if len(user.game_sockets) == 0: response = {"type": "u_cnt", "cnt": online_count(users)} await lobby_broadcast(sockets, response) # response = {"type": "lobbychat", "user": "", "message": "%s left the lobby" % user.username} # await lobby_broadcast(sockets, response) await user.clear_seeks(sockets, seeks) return ws