Exemple #1
0
async def lobby_socket_handler(request):

    users = request.app["users"]
    sockets = request.app["lobbysockets"]
    seeks = request.app["seeks"]

    ws = MyWebSocketResponse(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
Exemple #2
0
async def round_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

    game_ping_task = None
    game = None
    opp_ws = None

    async def game_pinger():
        """ Prevent Heroku to close inactive ws """
        # TODO: use this to detect disconnected games?
        while not ws.closed:
            await ws.send_json({})
            await asyncio.sleep(5)

    log.debug("-------------------------- NEW round 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)
                    log.debug("Websocket (%s) message: %s" % (id(ws), msg))

                    if data["type"] == "move":
                        log.info("Got USER move %s %s %s" %
                                 (user.username, data["gameId"], data["move"]))
                        move_is_ok = await play_move(games, data)
                        if not move_is_ok:
                            message = "Something went wrong! Server can't accept move %s. Try another one, please!" % data[
                                "move"]
                            chat_response = {
                                "type": "roundchat",
                                "user": "******",
                                "message": message,
                                "room": "player"
                            }
                            await ws.send_json(chat_response)

                        board_response = get_board(games, data, full=False)
                        log.info("   Server send to %s: %s" %
                                 (user.username, board_response["fen"]))
                        await ws.send_json(board_response)

                        game = games[data["gameId"]]
                        if game.status > STARTED and user.bot:
                            await user.game_queues[data["gameId"]
                                                   ].put(game.game_end)

                        opp_name = game.wplayer.username if user.username == game.bplayer.username else game.bplayer.username
                        opp_player = users[opp_name]

                        if opp_player.bot:
                            await opp_player.game_queues[data["gameId"]
                                                         ].put(game.game_state)
                            if game.status > STARTED:
                                await opp_player.game_queues[
                                    data["gameId"]].put(game.game_end)
                        else:
                            try:
                                opp_ws = users[opp_name].game_sockets[
                                    data["gameId"]]
                                log.info("   Server send to %s: %s" %
                                         (opp_name, board_response["fen"]))
                                await opp_ws.send_json(board_response)
                            except KeyError:
                                log.error(
                                    "Failed to send move %s to %s in game %s" %
                                    (data["move"], opp_name, data["gameId"]))

                        await round_broadcast(game,
                                              users,
                                              board_response,
                                              channels=request.app["channels"])

                    elif data["type"] == "ready":
                        game = games[data["gameId"]]
                        opp_name = game.wplayer.username if user.username == game.bplayer.username else game.bplayer.username
                        opp_player = users[opp_name]
                        if opp_player.bot:
                            await opp_player.event_queue.put(game.game_start)
                            response = start(games, data)
                            await ws.send_json(response)
                        else:
                            opp_ok = data["gameId"] in users[
                                opp_name].game_sockets
                            # waiting for opp to be ready also
                            if not opp_ok:
                                loop = asyncio.get_event_loop()
                                end_time = loop.time() + 20.0
                                while True:
                                    if (loop.time() + 1.0) >= end_time:
                                        log.debug(
                                            "Game %s aborted because user %s is not ready."
                                            % (data["gameId"], opp_name))
                                        response = await game.abort()
                                        await ws.send_json(response)
                                        break
                                    await asyncio.sleep(1)
                                    opp_ok = data["gameId"] in users[
                                        opp_name].game_sockets
                                    if opp_ok:
                                        break
                            if opp_ok:
                                opp_ws = users[opp_name].game_sockets[
                                    data["gameId"]]
                                response = start(games, data)
                                await opp_ws.send_json(response)
                                await ws.send_json(response)

                                response = {
                                    "type": "user_present",
                                    "username": opp_name
                                }
                                await ws.send_json(response)

                    elif data["type"] == "board":
                        board_response = get_board(games, data, full=True)
                        log.info("User %s asked board. Server sent: %s" %
                                 (user.username, board_response["fen"]))
                        await ws.send_json(board_response)

                    elif data["type"] == "analysis":
                        game = await load_game(request.app, data["gameId"])

                        # If there is any fishnet client, use it.
                        if len(request.app["workers"]) > 0:
                            work_id = "".join(
                                random.choice(string.ascii_letters +
                                              string.digits) for x in range(6))
                            work = {
                                "work": {
                                    "type": "analysis",
                                    "id": work_id,
                                },
                                # or:
                                # "work": {
                                #   "type": "move",
                                #   "id": "work_id",
                                #   "level": 5 // 1 to 8
                                # },
                                "username": data["username"],
                                "game_id": data["gameId"],  # optional
                                "position": game.board.
                                initial_fen,  # start position (X-FEN)
                                "variant": game.variant,
                                "chess960": game.chess960,
                                "moves": " ".join(game.board.move_stack
                                                  ),  # moves of the game (UCI)
                                "nodes": 500000,  # optional limit
                                #  "skipPositions": [1, 4, 5]  # 0 is the first position
                            }
                            request.app["works"][work_id] = work
                            request.app["fishnet"].put_nowait(
                                (ANALYSIS, work_id))
                        else:
                            engine = users.get("Fairy-Stockfish")

                            if (engine is not None) and engine.online:
                                engine.game_queues[
                                    data["gameId"]] = asyncio.Queue()
                                await engine.event_queue.put(
                                    game.analysis_start(data["username"]))

                        response = {
                            "type": "roundchat",
                            "user": "",
                            "room": "spectator",
                            "message": "Analysis request sent..."
                        }
                        await ws.send_json(response)

                    elif data["type"] == "rematch":
                        game = await load_game(request.app, data["gameId"])

                        if game is None:
                            log.debug("Requseted game %s not found!")
                            response = {
                                "type": "game_not_found",
                                "username": user.username,
                                "gameId": data["gameId"]
                            }
                            await ws.send_json(response)
                            continue

                        opp_name = game.wplayer.username if user.username == game.bplayer.username else game.bplayer.username
                        opp_player = users[opp_name]

                        if opp_player.bot:
                            if opp_player.username == "Random-Mover":
                                engine = users.get("Random-Mover")
                            else:
                                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")

                            color = "w" if game.wplayer.username == opp_name else "b"
                            seek = Seek(user, game.variant, game.initial_fen,
                                        color, game.base, game.inc, game.level,
                                        game.rated, game.chess960)
                            seeks[seek.id] = seek

                            response = await new_game(request.app, engine,
                                                      seek.id)
                            await ws.send_json(response)

                            await engine.event_queue.put(
                                challenge(seek, response))
                            gameId = response["gameId"]
                            engine.game_queues[gameId] = asyncio.Queue()
                        else:
                            opp_ws = users[opp_name].game_sockets[
                                data["gameId"]]
                            if opp_name in game.rematch_offers:
                                color = "w" if game.wplayer.username == opp_name else "b"
                                seek = Seek(user, game.variant,
                                            game.initial_fen, color, game.base,
                                            game.inc, game.level, game.rated,
                                            game.chess960)
                                seeks[seek.id] = seek

                                response = await new_game(
                                    request.app, opp_player, seek.id)
                                await ws.send_json(response)
                                await opp_ws.send_json(response)
                            else:
                                game.rematch_offers.add(user.username)
                                response = {
                                    "type": "offer",
                                    "message": "Rematch offer sent",
                                    "room": "player",
                                    "user": ""
                                }
                                game.messages.append(response)
                                await ws.send_json(response)
                                await opp_ws.send_json(response)

                    elif data["type"] == "draw":
                        game = games[data["gameId"]]
                        opp_name = game.wplayer.username if user.username == game.bplayer.username else game.bplayer.username
                        opp_player = users[opp_name]

                        response = await draw(games,
                                              data,
                                              agreement=opp_name
                                              in game.draw_offers)
                        await ws.send_json(response)

                        if opp_player.bot:
                            if game.status == DRAW:
                                await opp_player.game_queues[
                                    data["gameId"]].put(game.game_end)
                        else:
                            opp_ws = users[opp_name].game_sockets[
                                data["gameId"]]
                            await opp_ws.send_json(response)

                        if opp_name not in game.draw_offers:
                            game.draw_offers.add(user.username)

                        await round_broadcast(game, users, response)

                    elif data["type"] in ("abort", "resign", "abandone",
                                          "flag"):
                        game = games[data["gameId"]]
                        response = await game_ended(games, user, data,
                                                    data["type"])

                        await ws.send_json(response)

                        opp_name = game.wplayer.username if user.username == game.bplayer.username else game.bplayer.username
                        opp_player = users[opp_name]
                        if opp_player.bot:
                            await opp_player.game_queues[data["gameId"]
                                                         ].put(game.game_end)
                        else:
                            opp_ws = users[opp_name].game_sockets[
                                data["gameId"]]
                            await opp_ws.send_json(response)

                        await round_broadcast(game, users, response)

                    elif data["type"] == "game_user_connected":
                        game = await load_game(request.app, data["gameId"])
                        if session_user is not None:
                            if data["username"] and data[
                                    "username"] != session_user:
                                log.info(
                                    "+++ Existing game_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

                                # Update logged in users as spactators
                                if user.username != game.wplayer.username and user.username != game.bplayer.username and game is not None:
                                    game.spectators.add(user)
                            else:
                                user = users[session_user]
                        else:
                            log.info(
                                "+++ Existing game_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
                        user.ping_counter = 0

                        # update websocket
                        user.game_sockets[data["gameId"]] = ws

                        # remove user seeks
                        await user.clear_seeks(sockets, seeks)

                        if game is None:
                            log.debug("Requseted game %s not found!")
                            response = {
                                "type": "game_not_found",
                                "username": user.username,
                                "gameId": data["gameId"]
                            }
                            await ws.send_json(response)
                            continue
                        else:
                            games[data["gameId"]] = game
                            if user.username != game.wplayer.username and user.username != game.bplayer.username:
                                game.spectators.add(user)
                                response = {
                                    "type":
                                    "spectators",
                                    "spectators":
                                    ", ".join(
                                        (spectator.username
                                         for spectator in game.spectators)),
                                    "gameId":
                                    data["gameId"]
                                }
                                await round_broadcast(game,
                                                      users,
                                                      response,
                                                      full=True)

                            response = {
                                "type": "game_user_connected",
                                "username": user.username,
                                "gameId": data["gameId"],
                                "ply": game.ply
                            }
                            await ws.send_json(response)

                        response = {
                            "type": "fullchat",
                            "lines": list(game.messages)
                        }
                        await ws.send_json(response,
                                           dumps=partial(
                                               json.dumps,
                                               default=datetime.isoformat))

                        loop = asyncio.get_event_loop()
                        game_ping_task = loop.create_task(game_pinger())
                        request.app["tasks"].add(game_ping_task)

                    elif data["type"] == "is_user_present":
                        player_name = data["username"]
                        player = users.get(player_name)
                        if player is not None and data["gameId"] in (
                                player.game_queues
                                if player.bot else player.game_sockets):
                            response = {
                                "type": "user_present",
                                "username": player_name
                            }
                        else:
                            response = {
                                "type": "user_disconnected",
                                "username": player_name
                            }
                        await ws.send_json(response)

                    elif data["type"] == "moretime":
                        # TODO: stop and update game stopwatch time with updated secs
                        game = games[data["gameId"]]

                        opp_color = WHITE if user.username == game.bplayer.username else BLACK
                        if opp_color == game.stopwatch.color:
                            opp_time = game.stopwatch.stop()
                            game.stopwatch.restart(opp_time + MORE_TIME)

                        opp_name = game.wplayer.username if user.username == game.bplayer.username else game.bplayer.username
                        opp_player = users[opp_name]

                        if not opp_player.bot:
                            opp_ws = users[opp_name].game_sockets[
                                data["gameId"]]
                            response = {"type": "moretime"}
                            await opp_ws.send_json(response)

                    elif data["type"] == "roundchat":
                        response = {
                            "type": "roundchat",
                            "user": user.username,
                            "message": data["message"],
                            "room": data["room"]
                        }
                        gameId = data["gameId"]
                        game = await load_game(request.app, gameId)
                        game.messages.append(response)

                        for name in (game.wplayer.username,
                                     game.bplayer.username):
                            player = users[name]
                            if player.bot:
                                if gameId in player.game_queues:
                                    await player.game_queues[gameId].put(
                                        '{"type": "chatLine", "username": "******", "room": "spectator", "text": "%s"}\n'
                                        % (user.username, data["message"]))
                            else:
                                if gameId in player.game_sockets:
                                    player_ws = player.game_sockets[gameId]
                                    await player_ws.send_json(response)

                        await round_broadcast(game, users, response)

                    elif data["type"] == "leave":
                        response = {
                            "type": "roundchat",
                            "user": "",
                            "message": "%s left the game" % user.username,
                            "room": "player"
                        }
                        gameId = data["gameId"]
                        game = await load_game(request.app, gameId)
                        game.messages.append(response)

                        opp_name = game.wplayer.username if user.username == game.bplayer.username else game.bplayer.username
                        opp_player = users[opp_name]
                        if not opp_player.bot and gameId in opp_player.game_sockets:
                            opp_player_ws = opp_player.game_sockets[gameId]
                            await opp_player_ws.send_json(response)

                            response = {
                                "type": "user_disconnected",
                                "username": user.username
                            }
                            await opp_player_ws.send_json(response)

                        await round_broadcast(game, users, response)

                    elif data["type"] == "updateTV":
                        db = request.app["db"]
                        query_filter = {
                            "us": data["profileId"]
                        } if "profileId" in data and data[
                            "profileId"] != "" else {}
                        doc = await db.game.find_one(query_filter,
                                                     sort=[('$natural', -1)])
                        gameId = None
                        if doc is not None:
                            gameId = doc["_id"]
                        if gameId != data["gameId"] and gameId is not None:
                            response = {"type": "updateTV", "gameId": gameId}
                            await ws.send_json(response)
            else:
                log.debug("type(msg.data) != str %s" % msg)
        elif msg.type == aiohttp.WSMsgType.ERROR:
            log.debug("!!! Round ws connection closed with exception %s" %
                      ws.exception())
        else:
            log.debug("other msg.type %s %s" % (msg.type, msg))

    log.info("--- Round Websocket %s closed" % id(ws))

    if game is not None and opp_ws is not None:
        response = {"type": "user_disconnected", "username": user.username}
        await opp_ws.send_json(response)
        await round_broadcast(game, users, response)

    if game is not None and not user.bot:
        del user.game_sockets[game.id]

        if user.username != game.wplayer.username and user.username != game.bplayer.username:
            game.spectators.discard(user)
            response = {
                "type":
                "spectators",
                "spectators":
                ", ".join(
                    (spectator.username for spectator in game.spectators)),
                "gameId":
                game.id
            }
            await round_broadcast(game, users, response, full=True)

    if game_ping_task is not None:
        game_ping_task.cancel()

    return ws
Exemple #3
0
async def round_socket_handler(request):

    users = request.app["users"]
    sockets = request.app["lobbysockets"]
    seeks = request.app["seeks"]
    db = request.app["db"]

    ws = MyWebSocketResponse(heartbeat=3.0, receive_timeout=15.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

    game = None
    opp_ws = None

    log.debug("-------------------------- NEW round 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)
                    # log.debug("Websocket (%s) message: %s" % (id(ws), msg))

                    if game is None:
                        game = await load_game(request.app, data["gameId"])
                        if game is None:
                            continue

                    if data["type"] == "move":
                        # log.info("Got USER move %s %s %s" % (user.username, data["gameId"], data["move"]))

                        async with game.move_lock:
                            try:
                                await play_move(request.app, user, game,
                                                data["move"], data["clocks"],
                                                data["ply"])
                            except Exception:
                                log.exception(
                                    "ERROR: Exception in play_move() in %s by %s ",
                                    data["gameId"], session_user)

                    elif data["type"] == "berserk":
                        game.berserk(data["color"])
                        response = {"type": "berserk", "color": data["color"]}
                        await round_broadcast(game, users, response, full=True)

                    elif data["type"] == "analysis_move":

                        await analysis_move(request.app, user, game,
                                            data["move"], data["fen"],
                                            data["ply"])

                    elif data["type"] == "ready":

                        opp_name = game.wplayer.username if user.username == game.bplayer.username else game.bplayer.username
                        opp_player = users[opp_name]
                        if opp_player.bot:
                            # Janggi game start have to wait for human player setup!
                            if game.variant != "janggi" or not (game.bsetup or
                                                                game.wsetup):
                                await opp_player.event_queue.put(
                                    game.game_start)

                            response = {
                                "type": "gameStart",
                                "gameId": data["gameId"]
                            }
                            await ws.send_json(response)
                        else:
                            response = {
                                "type": "gameStart",
                                "gameId": data["gameId"]
                            }
                            await ws.send_json(response)

                            response = {
                                "type": "user_present",
                                "username": user.username
                            }
                            await round_broadcast(game,
                                                  users,
                                                  game.spectator_list,
                                                  full=True)

                    elif data["type"] == "board":

                        if game.variant == "janggi":
                            if (game.bsetup
                                    or game.wsetup) and game.status <= STARTED:
                                if game.bsetup:
                                    await ws.send_json({
                                        "type":
                                        "setup",
                                        "color":
                                        "black",
                                        "fen":
                                        game.board.initial_fen
                                    })
                                elif game.wsetup:
                                    await ws.send_json({
                                        "type":
                                        "setup",
                                        "color":
                                        "white",
                                        "fen":
                                        game.board.initial_fen
                                    })
                            else:
                                board_response = game.get_board(full=True)
                                await ws.send_json(board_response)
                        else:
                            board_response = game.get_board(full=True)
                            await ws.send_json(board_response)

                    elif data["type"] == "setup":
                        # Janggi game starts with a prelude phase to set up horses and elephants
                        # First the second player (Red) choses his setup! Then the first player (Blue)

                        game.board.initial_fen = data["fen"]
                        game.initial_fen = game.board.initial_fen
                        game.board.fen = game.board.initial_fen
                        # print("--- Got FEN from %s %s" % (data["color"], data["fen"]))

                        opp_name = game.wplayer.username if user.username == game.bplayer.username else game.bplayer.username
                        opp_player = users[opp_name]

                        game.steps[0]["fen"] = data["fen"]
                        game.set_dests()

                        if data["color"] == "black":
                            game.bsetup = False
                            response = {
                                "type": "setup",
                                "color": "white",
                                "fen": data["fen"]
                            }
                            await ws.send_json(response)

                            if opp_player.bot:
                                game.board.janggi_setup("w")
                                game.steps[0]["fen"] = game.board.initial_fen
                                game.set_dests()
                            else:
                                opp_ws = users[opp_name].game_sockets[
                                    data["gameId"]]
                                await opp_ws.send_json(response)
                        else:
                            game.wsetup = False
                            response = game.get_board(full=True)
                            # log.info("User %s asked board. Server sent: %s" % (user.username, board_response["fen"]))
                            await ws.send_json(response)

                            if not opp_player.bot:
                                opp_ws = users[opp_name].game_sockets[
                                    data["gameId"]]
                                await opp_ws.send_json(response)

                        if opp_player.bot:
                            await opp_player.event_queue.put(game.game_start)

                        # restart expiration time after setup phase
                        game.stopwatch.restart(
                            game.stopwatch.time_for_first_move)

                    elif data["type"] == "analysis":

                        # If there is any fishnet client, use it.
                        if len(request.app["workers"]) > 0:
                            work_id = "".join(
                                random.choice(string.ascii_letters +
                                              string.digits) for x in range(6))
                            work = {
                                "work": {
                                    "type": "analysis",
                                    "id": work_id,
                                },
                                # or:
                                # "work": {
                                #   "type": "move",
                                #   "id": "work_id",
                                #   "level": 5 // 1 to 8
                                # },
                                "username": data["username"],
                                "game_id": data["gameId"],  # optional
                                "position": game.board.
                                initial_fen,  # start position (X-FEN)
                                "variant": game.variant,
                                "chess960": game.chess960,
                                "moves": " ".join(game.board.move_stack
                                                  ),  # moves of the game (UCI)
                                "nodes": 500000,  # optional limit
                                #  "skipPositions": [1, 4, 5]  # 0 is the first position
                            }
                            request.app["works"][work_id] = work
                            request.app["fishnet"].put_nowait(
                                (ANALYSIS, work_id))
                        else:
                            engine = users.get("Fairy-Stockfish")

                            if (engine is not None) and engine.online:
                                engine.game_queues[
                                    data["gameId"]] = asyncio.Queue()
                                await engine.event_queue.put(
                                    game.analysis_start(data["username"]))

                        response = chat_response("roundchat",
                                                 "",
                                                 "Analysis request sent...",
                                                 room="spectator")
                        await ws.send_json(response)

                    elif data["type"] == "rematch":

                        rematch_id = None

                        opp_name = game.wplayer.username if user.username == game.bplayer.username else game.bplayer.username
                        opp_player = users[opp_name]
                        handicap = data["handicap"]
                        fen = "" if game.variant == "janggi" else game.initial_fen

                        if opp_player.bot:
                            if opp_player.username == "Random-Mover":
                                engine = users.get("Random-Mover")
                            else:
                                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")

                            color = "w" if game.wplayer.username == opp_name else "b"
                            if handicap:
                                color = "w" if color == "b" else "b"
                            seek = Seek(user,
                                        game.variant,
                                        fen=fen,
                                        color=color,
                                        base=game.base,
                                        inc=game.inc,
                                        byoyomi_period=game.byoyomi_period,
                                        level=game.level,
                                        rated=game.rated,
                                        player1=user,
                                        chess960=game.chess960)
                            seeks[seek.id] = seek

                            response = await join_seek(request.app, engine,
                                                       seek.id)
                            await ws.send_json(response)

                            await engine.event_queue.put(
                                challenge(seek, response))
                            gameId = response["gameId"]
                            rematch_id = gameId
                            engine.game_queues[gameId] = asyncio.Queue()
                        else:
                            try:
                                opp_ws = users[opp_name].game_sockets[
                                    data["gameId"]]
                            except KeyError:
                                # opp disconnected
                                continue

                            if opp_name in game.rematch_offers:
                                color = "w" if game.wplayer.username == opp_name else "b"
                                if handicap:
                                    color = "w" if color == "b" else "b"
                                seek = Seek(user,
                                            game.variant,
                                            fen=fen,
                                            color=color,
                                            base=game.base,
                                            inc=game.inc,
                                            byoyomi_period=game.byoyomi_period,
                                            level=game.level,
                                            rated=game.rated,
                                            player1=user,
                                            chess960=game.chess960)
                                seeks[seek.id] = seek

                                response = await join_seek(
                                    request.app, opp_player, seek.id)
                                rematch_id = response["gameId"]
                                await ws.send_json(response)
                                await opp_ws.send_json(response)
                            else:
                                game.rematch_offers.add(user.username)
                                response = {
                                    "type": "rematch_offer",
                                    "username": user.username,
                                    "message": "Rematch offer sent",
                                    "room": "player",
                                    "user": ""
                                }
                                game.messages.append(response)
                                await ws.send_json(response)
                                await opp_ws.send_json(response)
                        if rematch_id:
                            await round_broadcast(game, users, {
                                "type": "view_rematch",
                                "gameId": rematch_id
                            })

                    elif data["type"] == "reject_rematch":

                        opp_name = game.wplayer.username if user.username == game.bplayer.username else game.bplayer.username

                        if opp_name in game.rematch_offers:
                            await round_broadcast(
                                game,
                                users, {
                                    "type": "rematch_rejected",
                                    "message": "Rematch offer rejected"
                                },
                                full=True)

                    elif data["type"] == "draw":

                        color = WHITE if user.username == game.wplayer.username else BLACK
                        opp_name = game.wplayer.username if color == BLACK else game.bplayer.username
                        opp_player = users[opp_name]

                        response = await draw(game,
                                              user.username,
                                              agreement=opp_name
                                              in game.draw_offers)
                        await ws.send_json(response)
                        if opp_player.bot:
                            if game.status > STARTED and data[
                                    "gameId"] in opp_player.game_queues:
                                await opp_player.game_queues[
                                    data["gameId"]].put(game.game_end)
                        else:
                            try:
                                opp_ws = users[opp_name].game_sockets[
                                    data["gameId"]]
                                await opp_ws.send_json(response)
                            except KeyError:
                                # opp disconnected
                                pass

                        if opp_name not in game.draw_offers:
                            game.draw_offers.add(user.username)

                        await round_broadcast(game, users, response)

                    elif data["type"] == "reject_draw":

                        color = WHITE if user.username == game.wplayer.username else BLACK
                        opp_name = game.wplayer.username if color == BLACK else game.bplayer.username

                        response = reject_draw(game, opp_name)
                        if response is not None:
                            await round_broadcast(game,
                                                  users,
                                                  response,
                                                  full=True)

                    elif data["type"] == "logout":
                        await ws.close()

                    elif data["type"] == "byoyomi":

                        game.byo_correction += game.inc * 1000
                        game.byoyomi_periods[data["color"]] = data["period"]
                        # print("BYOYOMI:", data)

                    elif data["type"] in ("abort", "resign", "abandone",
                                          "flag"):

                        if data["type"] == "abort" and (
                                game is not None) and game.board.ply > 2:
                            continue

                        if game.status > STARTED:
                            # game was already finished!
                            # see  https://github.com/gbtami/pychess-variants/issues/675
                            continue

                        async with game.move_lock:
                            response = await game.game_ended(
                                user, data["type"])

                        await ws.send_json(response)

                        opp_name = game.wplayer.username if user.username == game.bplayer.username else game.bplayer.username
                        opp_player = users[opp_name]
                        if opp_player.bot:
                            if data["gameId"] in opp_player.game_queues:
                                await opp_player.game_queues[
                                    data["gameId"]].put(game.game_end)
                        else:
                            if data["gameId"] in users[opp_name].game_sockets:
                                opp_ws = users[opp_name].game_sockets[
                                    data["gameId"]]
                                await opp_ws.send_json(response)

                        await round_broadcast(game, users, response)

                    elif data["type"] == "embed_user_connected":

                        response = {"type": "embed_user_connected"}
                        await ws.send_json(response)

                    elif data["type"] == "game_user_connected":

                        if session_user is not None:
                            if data["username"] and data[
                                    "username"] != session_user:
                                log.info(
                                    "+++ Existing game_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

                                # Update logged in users as spactators
                                if user.username != game.wplayer.username and user.username != game.bplayer.username and game is not None:
                                    game.spectators.add(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 game_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
                        if data["gameId"] in user.game_sockets:
                            await user.game_sockets[data["gameId"]].close()
                        user.game_sockets[data["gameId"]] = ws
                        user.update_online()

                        # remove user seeks
                        if len(user.lobby_sockets) == 0 or (
                                game.status <= STARTED and
                            (user.username == game.wplayer.username
                             or user.username == game.bplayer.username)):
                            await user.clear_seeks(sockets, seeks)

                        if user.username != game.wplayer.username and user.username != game.bplayer.username:
                            game.spectators.add(user)
                            await round_broadcast(game,
                                                  users,
                                                  game.spectator_list,
                                                  full=True)

                        response = {
                            "type": "game_user_connected",
                            "username": user.username,
                            "gameId": data["gameId"],
                            "ply": game.board.ply,
                            "firstmovetime": game.stopwatch.secs
                        }
                        await ws.send_json(response)

                        response = {
                            "type": "crosstable",
                            "ct": game.crosstable
                        }
                        await ws.send_json(response)

                        response = {
                            "type": "fullchat",
                            "lines": list(game.messages)
                        }
                        await ws.send_json(response)

                        response = {
                            "type": "user_present",
                            "username": user.username
                        }
                        await round_broadcast(game, users, response, full=True)

                        # not connected to lobby socket but connected to game socket
                        if len(user.game_sockets
                               ) == 1 and user.username not in sockets:
                            response = {
                                "type": "u_cnt",
                                "cnt": online_count(users)
                            }
                            await lobby_broadcast(sockets, response)

                    elif data["type"] == "is_user_present":
                        player_name = data["username"]
                        player = users.get(player_name)
                        await asyncio.sleep(1)
                        if player is not None and data["gameId"] in (
                                player.game_queues
                                if player.bot else player.game_sockets):
                            response = {
                                "type": "user_present",
                                "username": player_name
                            }
                        else:
                            response = {
                                "type": "user_disconnected",
                                "username": player_name
                            }
                        await ws.send_json(response)

                    elif data["type"] == "moretime":
                        # TODO: stop and update game stopwatch time with updated secs

                        opp_color = WHITE if user.username == game.bplayer.username else BLACK
                        if opp_color == game.stopwatch.color:
                            opp_time = game.stopwatch.stop()
                            game.stopwatch.restart(opp_time + MORE_TIME)

                        opp_name = game.wplayer.username if user.username == game.bplayer.username else game.bplayer.username
                        opp_player = users[opp_name]

                        if not opp_player.bot:
                            opp_ws = users[opp_name].game_sockets[
                                data["gameId"]]
                            response = {
                                "type": "moretime",
                                "username": opp_name
                            }
                            await opp_ws.send_json(response)
                            await round_broadcast(game, users, response)

                    elif data["type"] == "roundchat":
                        gameId = data["gameId"]

                        # Users running a fishnet worker can ask server side analysis with chat message: !analysis
                        if data["message"] == "!analysis" and user.username in request.app[
                                "fishnet_versions"]:
                            for step in game.steps:
                                if "analysis" in step:
                                    del step["analysis"]
                            await ws.send_json({"type": "request_analysis"})
                            continue

                        response = chat_response("roundchat",
                                                 user.username,
                                                 data["message"],
                                                 room=data["room"])
                        game.messages.append(response)

                        for name in (game.wplayer.username,
                                     game.bplayer.username):
                            player = users[name]
                            if player.bot:
                                if gameId in player.game_queues:
                                    await player.game_queues[gameId].put(
                                        '{"type": "chatLine", "username": "******", "room": "spectator", "text": "%s"}\n'
                                        % (user.username, data["message"]))
                            else:
                                if gameId in player.game_sockets:
                                    player_ws = player.game_sockets[gameId]
                                    await player_ws.send_json(response)

                        await round_broadcast(game, users, response)

                    elif data["type"] == "leave":
                        gameId = data["gameId"]

                        response = chat_response("roundchat",
                                                 "",
                                                 "%s left the game" %
                                                 user.username,
                                                 room="player")
                        game.messages.append(response)

                        opp_name = game.wplayer.username if user.username == game.bplayer.username else game.bplayer.username
                        opp_player = users[opp_name]
                        if not opp_player.bot and gameId in opp_player.game_sockets:
                            opp_player_ws = opp_player.game_sockets[gameId]
                            await opp_player_ws.send_json(response)

                            response = {
                                "type": "user_disconnected",
                                "username": user.username
                            }
                            await opp_player_ws.send_json(response)

                        await round_broadcast(game, users, response)

                    elif data["type"] == "updateTV":
                        if "profileId" in data and data["profileId"] != "":
                            gameId = await tv_game_user(
                                db, users, data["profileId"])
                        else:
                            gameId = await tv_game(db, request.app)

                        if gameId != data["gameId"] and gameId is not None:
                            response = {"type": "updateTV", "gameId": gameId}
                            await ws.send_json(response)

                    elif data["type"] == "count":

                        cur_player = game.bplayer if game.board.color == BLACK else game.wplayer
                        opp_name = game.wplayer.username if user.username == game.bplayer.username else game.bplayer.username
                        opp_player = users[opp_name]
                        opp_ws = users[opp_name].game_sockets[data["gameId"]]

                        if user.username == cur_player.username:
                            if data["mode"] == "start":
                                game.start_manual_count()
                                response = {
                                    "type": "count",
                                    "message":
                                    "Board's honor counting started",
                                    "room": "player",
                                    "user": ""
                                }
                                await ws.send_json(response)
                                await opp_ws.send_json(response)
                                await round_broadcast(game, users, response)
                            elif data["mode"] == "stop":
                                game.stop_manual_count()
                                response = {
                                    "type": "count",
                                    "message":
                                    "Board's honor counting stopped",
                                    "room": "player",
                                    "user": ""
                                }
                                await ws.send_json(response)
                                await opp_ws.send_json(response)
                                await round_broadcast(game, users, response)
                        else:
                            response = {
                                "type": "count",
                                "message":
                                "You can only start/stop board's honor counting on your own turn!",
                                "room": "player",
                                "user": ""
                            }
                            await ws.send_json(response)

                    elif data["type"] == "delete":
                        await db.game.delete_one({"_id": data["gameId"]})
                        response = {"type": "deleted"}
                        await ws.send_json(response)

            elif msg.type == aiohttp.WSMsgType.CLOSED:
                log.debug(
                    "--- Round websocket %s msg.type == aiohttp.WSMsgType.CLOSED",
                    id(ws))
                break

            elif msg.type == aiohttp.WSMsgType.ERROR:
                log.error(
                    "--- Round ws %s msg.type == aiohttp.WSMsgType.ERROR",
                    id(ws))
                break

            else:
                log.debug("--- Round ws other msg.type %s %s", msg.type, msg)

    except OSError:
        # disconnected?
        log.exception("ERROR: OSError in round_socket_handler() owned by %s ",
                      session_user)

    except Exception:
        log.exception(
            "ERROR: Exception in round_socket_handler() owned by %s ",
            session_user)

    finally:
        log.debug("--- wsr.py fianlly: await ws.close() %s", session_user)
        await ws.close()

        if game is not None and user is not None and not user.bot:
            if game.id in user.game_sockets:
                del user.game_sockets[game.id]
                user.update_online()

            if user.username != game.wplayer.username and user.username != game.bplayer.username:
                game.spectators.discard(user)
                await round_broadcast(game,
                                      users,
                                      game.spectator_list,
                                      full=True)

            # not connected to lobby socket and not connected to game socket
            if len(user.game_sockets) == 0 and user.username not in sockets:
                response = {"type": "u_cnt", "cnt": online_count(users)}
                await lobby_broadcast(sockets, response)

        if game is not None and user is not None:
            response = {"type": "user_disconnected", "username": user.username}
            await round_broadcast(game, users, response, full=True)

    return ws
Exemple #4
0
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
Exemple #5
0
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
Exemple #6
0
async def round_socket_handler(request):

    users = request.app["users"]
    sockets = request.app["websockets"]
    seeks = request.app["seeks"]
    games = request.app["games"]
    db = request.app["db"]

    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

    game_ping_task = None
    game = None
    opp_ws = None

    async def game_pinger():
        """ Prevent Heroku to close inactive ws """
        # TODO: use this to detect disconnected games?
        while not ws.closed:
            await ws.send_json({})
            await asyncio.sleep(5)

    log.debug("-------------------------- NEW round 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)
                    # log.debug("Websocket (%s) message: %s" % (id(ws), msg))

                    if data["type"] == "move":
                        # log.info("Got USER move %s %s %s" % (user.username, data["gameId"], data["move"]))
                        game = await load_game(request.app, data["gameId"])
                        move = data["move"]
                        await play_move(request.app, user, game, move,
                                        data["clocks"], data["ply"])

                    elif data["type"] == "ready":
                        game = await load_game(request.app, data["gameId"])
                        opp_name = game.wplayer.username if user.username == game.bplayer.username else game.bplayer.username
                        opp_player = users[opp_name]
                        if opp_player.bot:
                            # Janggi game start have to wait for human player setup!
                            if game.variant != "janggi" or not (game.bsetup or
                                                                game.wsetup):
                                await opp_player.event_queue.put(
                                    game.game_start)

                            response = {
                                "type": "gameStart",
                                "gameId": data["gameId"]
                            }
                            await ws.send_json(response)
                        else:
                            opp_ok = data["gameId"] in users[
                                opp_name].game_sockets
                            # waiting for opp to be ready also
                            if not opp_ok:
                                loop = asyncio.get_event_loop()
                                end_time = loop.time() + 20.0
                                while True:
                                    if (loop.time() + 1.0) >= end_time:
                                        log.debug(
                                            "Game %s aborted because user %s is not ready."
                                            % (data["gameId"], opp_name))
                                        response = await game.abort()
                                        await ws.send_json(response)
                                        break
                                    await asyncio.sleep(1)
                                    opp_ok = data["gameId"] in users[
                                        opp_name].game_sockets
                                    if opp_ok:
                                        break
                            if opp_ok:
                                opp_ws = users[opp_name].game_sockets[
                                    data["gameId"]]
                                response = {
                                    "type": "gameStart",
                                    "gameId": data["gameId"]
                                }
                                await opp_ws.send_json(response)
                                await ws.send_json(response)

                                response = {
                                    "type": "user_present",
                                    "username": opp_name
                                }
                                await ws.send_json(response)

                    elif data["type"] == "board":
                        game = await load_game(request.app, data["gameId"])
                        if game.variant == "janggi":
                            if (game.bsetup
                                    or game.wsetup) and game.status <= STARTED:
                                if game.bsetup:
                                    await ws.send_json({
                                        "type":
                                        "setup",
                                        "color":
                                        "black",
                                        "fen":
                                        game.board.initial_fen
                                    })
                                elif game.wsetup:
                                    await ws.send_json({
                                        "type":
                                        "setup",
                                        "color":
                                        "white",
                                        "fen":
                                        game.board.initial_fen
                                    })
                            else:
                                board_response = game.get_board(full=True)
                                await ws.send_json(board_response)
                        else:
                            board_response = game.get_board(full=True)
                            await ws.send_json(board_response)

                    elif data["type"] == "setup":
                        # Janggi game starts with a prelude phase to set up horses and elephants
                        # First the second player (Red) choses his setup! Then the first player (Blue)
                        game = await load_game(request.app, data["gameId"])
                        game.board.initial_fen = data["fen"]
                        game.initial_fen = game.board.initial_fen
                        game.board.fen = game.board.initial_fen
                        # print("--- Got FEN from %s %s" % (data["color"], data["fen"]))

                        opp_name = game.wplayer.username if user.username == game.bplayer.username else game.bplayer.username
                        opp_player = users[opp_name]

                        game.steps[0]["fen"] = data["fen"]
                        game.set_dests()

                        if data["color"] == "black":
                            game.bsetup = False
                            response = {
                                "type": "setup",
                                "color": "white",
                                "fen": data["fen"]
                            }
                            await ws.send_json(response)

                            if opp_player.bot:
                                game.board.janggi_setup("w")
                                game.steps[0]["fen"] = game.board.initial_fen
                                game.set_dests()
                            else:
                                opp_ws = users[opp_name].game_sockets[
                                    data["gameId"]]
                                await opp_ws.send_json(response)
                        else:
                            game.wsetup = False
                            response = game.get_board(full=True)
                            # log.info("User %s asked board. Server sent: %s" % (user.username, board_response["fen"]))
                            await ws.send_json(response)

                            if not opp_player.bot:
                                opp_ws = users[opp_name].game_sockets[
                                    data["gameId"]]
                                await opp_ws.send_json(response)

                        if opp_player.bot:
                            await opp_player.event_queue.put(game.game_start)

                    elif data["type"] == "analysis":
                        game = await load_game(request.app, data["gameId"])

                        # If there is any fishnet client, use it.
                        if len(request.app["workers"]) > 0:
                            work_id = "".join(
                                random.choice(string.ascii_letters +
                                              string.digits) for x in range(6))
                            work = {
                                "work": {
                                    "type": "analysis",
                                    "id": work_id,
                                },
                                # or:
                                # "work": {
                                #   "type": "move",
                                #   "id": "work_id",
                                #   "level": 5 // 1 to 8
                                # },
                                "username": data["username"],
                                "game_id": data["gameId"],  # optional
                                "position": game.board.
                                initial_fen,  # start position (X-FEN)
                                "variant": game.variant,
                                "chess960": game.chess960,
                                "moves": " ".join(game.board.move_stack
                                                  ),  # moves of the game (UCI)
                                "nodes": 500000,  # optional limit
                                #  "skipPositions": [1, 4, 5]  # 0 is the first position
                            }
                            request.app["works"][work_id] = work
                            request.app["fishnet"].put_nowait(
                                (ANALYSIS, work_id))
                        else:
                            engine = users.get("Fairy-Stockfish")

                            if (engine is not None) and engine.online():
                                engine.game_queues[
                                    data["gameId"]] = asyncio.Queue()
                                await engine.event_queue.put(
                                    game.analysis_start(data["username"]))

                        response = {
                            "type": "roundchat",
                            "user": "",
                            "room": "spectator",
                            "message": "Analysis request sent..."
                        }
                        await ws.send_json(response)

                    elif data["type"] == "rematch":
                        game = await load_game(request.app, data["gameId"])

                        if game is None:
                            log.debug("Requested game %s not found!")
                            response = {
                                "type": "game_not_found",
                                "username": user.username,
                                "gameId": data["gameId"]
                            }
                            await ws.send_json(response)
                            continue

                        opp_name = game.wplayer.username if user.username == game.bplayer.username else game.bplayer.username
                        opp_player = users[opp_name]
                        handicap = data["handicap"]
                        fen = "" if game.variant == "janggi" else game.initial_fen

                        if opp_player.bot:
                            if opp_player.username == "Random-Mover":
                                engine = users.get("Random-Mover")
                            else:
                                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")

                            color = "w" if game.wplayer.username == opp_name else "b"
                            if handicap:
                                color = "w" if color == "b" else "b"
                            seek = Seek(user,
                                        game.variant,
                                        fen=fen,
                                        color=color,
                                        base=game.base,
                                        inc=game.inc,
                                        byoyomi_period=game.byoyomi_period,
                                        level=game.level,
                                        rated=game.rated,
                                        chess960=game.chess960)
                            seeks[seek.id] = seek

                            response = await new_game(request.app, engine,
                                                      seek.id)
                            await ws.send_json(response)

                            await engine.event_queue.put(
                                challenge(seek, response))
                            gameId = response["gameId"]
                            engine.game_queues[gameId] = asyncio.Queue()
                        else:
                            opp_ws = users[opp_name].game_sockets[
                                data["gameId"]]
                            if opp_name in game.rematch_offers:
                                color = "w" if game.wplayer.username == opp_name else "b"
                                if handicap:
                                    color = "w" if color == "b" else "b"
                                seek = Seek(user,
                                            game.variant,
                                            fen=fen,
                                            color=color,
                                            base=game.base,
                                            inc=game.inc,
                                            byoyomi_period=game.byoyomi_period,
                                            level=game.level,
                                            rated=game.rated,
                                            chess960=game.chess960)
                                seeks[seek.id] = seek

                                response = await new_game(
                                    request.app, opp_player, seek.id)
                                await ws.send_json(response)
                                await opp_ws.send_json(response)
                            else:
                                game.rematch_offers.add(user.username)
                                response = {
                                    "type": "offer",
                                    "message": "Rematch offer sent",
                                    "room": "player",
                                    "user": ""
                                }
                                game.messages.append(response)
                                await ws.send_json(response)
                                await opp_ws.send_json(response)

                    elif data["type"] == "draw":
                        game = await load_game(request.app, data["gameId"])
                        opp_name = game.wplayer.username if user.username == game.bplayer.username else game.bplayer.username
                        opp_player = users[opp_name]

                        response = await draw(games,
                                              data,
                                              agreement=opp_name
                                              in game.draw_offers)
                        await ws.send_json(response)
                        if opp_player.bot:
                            if game.status > STARTED:
                                await opp_player.game_queues[
                                    data["gameId"]].put(game.game_end)
                        else:
                            opp_ws = users[opp_name].game_sockets[
                                data["gameId"]]
                            await opp_ws.send_json(response)

                        if opp_name not in game.draw_offers:
                            game.draw_offers.add(user.username)

                        await round_broadcast(game, users, response)

                    elif data["type"] == "logout":
                        await ws.close()

                    elif data["type"] == "byoyomi":
                        game = await load_game(request.app, data["gameId"])
                        game.cur_byoyomi_period = data["period"]

                    elif data["type"] in ("abort", "resign", "abandone",
                                          "flag"):
                        game = await load_game(request.app, data["gameId"])
                        if data["type"] == "abort" and (
                                game is not None) and game.board.ply > 2:
                            continue

                        response = await game.game_ended(user, data["type"])

                        await ws.send_json(response)

                        opp_name = game.wplayer.username if user.username == game.bplayer.username else game.bplayer.username
                        opp_player = users[opp_name]
                        if opp_player.bot:
                            await opp_player.game_queues[data["gameId"]
                                                         ].put(game.game_end)
                        else:
                            opp_ws = users[opp_name].game_sockets[
                                data["gameId"]]
                            await opp_ws.send_json(response)

                        await round_broadcast(game, users, response)

                    elif data["type"] == "game_user_connected":
                        game = await load_game(request.app, data["gameId"])
                        if session_user is not None:
                            if data["username"] and data[
                                    "username"] != session_user:
                                log.info(
                                    "+++ Existing game_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

                                # Update logged in users as spactators
                                if user.username != game.wplayer.username and user.username != game.bplayer.username and game is not None:
                                    game.spectators.add(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 game_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
                        user.ping_counter = 0

                        # update websocket
                        if data["gameId"] in user.game_sockets:
                            await user.game_sockets[data["gameId"]].close()
                        user.game_sockets[data["gameId"]] = ws

                        # remove user seeks
                        await user.clear_seeks(sockets, seeks)

                        if game is None:
                            log.debug("Requested game %s not found!")
                            response = {
                                "type": "game_not_found",
                                "username": user.username,
                                "gameId": data["gameId"]
                            }
                            await ws.send_json(response)
                            continue
                        else:
                            games[data["gameId"]] = game
                            if user.username != game.wplayer.username and user.username != game.bplayer.username:
                                game.spectators.add(user)
                                await round_broadcast(game,
                                                      users,
                                                      game.spectator_list,
                                                      full=True)

                            response = {
                                "type": "game_user_connected",
                                "username": user.username,
                                "gameId": data["gameId"],
                                "ply": game.board.ply
                            }
                            await ws.send_json(response)

                        response = {
                            "type": "crosstable",
                            "ct": game.crosstable
                        }
                        await ws.send_json(response)

                        response = {
                            "type": "fullchat",
                            "lines": list(game.messages)
                        }
                        await ws.send_json(response)

                        loop = asyncio.get_event_loop()
                        game_ping_task = loop.create_task(game_pinger())

                        # not connected to lobby socket but connected to game socket
                        if len(user.game_sockets
                               ) == 1 and user.username not in sockets:
                            request.app["u_cnt"] += 1
                            response = {
                                "type": "u_cnt",
                                "cnt": request.app["u_cnt"]
                            }
                            await lobby_broadcast(sockets, response)

                    elif data["type"] == "is_user_present":
                        player_name = data["username"]
                        player = users.get(player_name)
                        if player is not None and data["gameId"] in (
                                player.game_queues
                                if player.bot else player.game_sockets):
                            response = {
                                "type": "user_present",
                                "username": player_name
                            }
                        else:
                            response = {
                                "type": "user_disconnected",
                                "username": player_name
                            }
                        await ws.send_json(response)

                    elif data["type"] == "moretime":
                        # TODO: stop and update game stopwatch time with updated secs
                        game = await load_game(request.app, data["gameId"])

                        opp_color = WHITE if user.username == game.bplayer.username else BLACK
                        if opp_color == game.stopwatch.color:
                            opp_time = game.stopwatch.stop()
                            game.stopwatch.restart(opp_time + MORE_TIME)

                        opp_name = game.wplayer.username if user.username == game.bplayer.username else game.bplayer.username
                        opp_player = users[opp_name]

                        if not opp_player.bot:
                            opp_ws = users[opp_name].game_sockets[
                                data["gameId"]]
                            response = {
                                "type": "moretime",
                                "username": opp_name
                            }
                            await opp_ws.send_json(response)
                            await round_broadcast(game, users, response)

                    elif data["type"] == "roundchat":
                        gameId = data["gameId"]
                        game = await load_game(request.app, gameId)
                        if data["message"] == "!analysis" and user.username in request.app[
                                "fishnet_versions"]:
                            for step in game.steps:
                                if "analysis" in step:
                                    del step["analysis"]
                            await ws.send_json({"type": "request_analysis"})
                            continue

                        response = {
                            "type": "roundchat",
                            "user": user.username,
                            "message": data["message"],
                            "room": data["room"]
                        }
                        game.messages.append(response)

                        for name in (game.wplayer.username,
                                     game.bplayer.username):
                            player = users[name]
                            if player.bot:
                                if gameId in player.game_queues:
                                    await player.game_queues[gameId].put(
                                        '{"type": "chatLine", "username": "******", "room": "spectator", "text": "%s"}\n'
                                        % (user.username, data["message"]))
                            else:
                                if gameId in player.game_sockets:
                                    player_ws = player.game_sockets[gameId]
                                    await player_ws.send_json(response)

                        await round_broadcast(game, users, response)

                    elif data["type"] == "leave":
                        response = {
                            "type": "roundchat",
                            "user": "",
                            "message": "%s left the game" % user.username,
                            "room": "player"
                        }
                        gameId = data["gameId"]
                        game = await load_game(request.app, gameId)
                        game.messages.append(response)

                        opp_name = game.wplayer.username if user.username == game.bplayer.username else game.bplayer.username
                        opp_player = users[opp_name]
                        if not opp_player.bot and gameId in opp_player.game_sockets:
                            opp_player_ws = opp_player.game_sockets[gameId]
                            await opp_player_ws.send_json(response)

                            response = {
                                "type": "user_disconnected",
                                "username": user.username
                            }
                            await opp_player_ws.send_json(response)

                        await round_broadcast(game, users, response)

                    elif data["type"] == "updateTV":
                        if "profileId" in data and data["profileId"] != "":
                            gameId = await tv_game_user(
                                db, users, data["profileId"])
                        else:
                            gameId = await tv_game(db, request.app)

                        if gameId != data["gameId"] and gameId is not None:
                            response = {"type": "updateTV", "gameId": gameId}
                            await ws.send_json(response)

                    elif data["type"] == "count":

                        game = await load_game(request.app, data["gameId"])
                        cur_player = game.bplayer if game.board.color == BLACK else game.wplayer
                        opp_name = game.wplayer.username if user.username == game.bplayer.username else game.bplayer.username
                        opp_player = users[opp_name]
                        opp_ws = users[opp_name].game_sockets[data["gameId"]]

                        if user.username == cur_player.username:
                            if data["mode"] == "start":
                                game.start_manual_count()
                                response = {
                                    "type": "count",
                                    "message":
                                    "Board's honor counting started",
                                    "room": "player",
                                    "user": ""
                                }
                                await ws.send_json(response)
                                await opp_ws.send_json(response)
                                await round_broadcast(game, users, response)
                            elif data["mode"] == "stop":
                                game.stop_manual_count()
                                response = {
                                    "type": "count",
                                    "message":
                                    "Board's honor counting stopped",
                                    "room": "player",
                                    "user": ""
                                }
                                await ws.send_json(response)
                                await opp_ws.send_json(response)
                                await round_broadcast(game, users, response)
                        else:
                            response = {
                                "type": "count",
                                "message":
                                "You can only start/stop board's honor counting on your own turn!",
                                "room": "player",
                                "user": ""
                            }
                            await ws.send_json(response)

            else:
                log.debug("type(msg.data) != str %s" % msg)
        elif msg.type == aiohttp.WSMsgType.ERROR:
            log.debug("!!! Round ws connection closed with exception %s" %
                      ws.exception())
        else:
            log.debug("other msg.type %s %s" % (msg.type, msg))

    log.info("--- Round Websocket %s closed" % id(ws))

    if game is not None and opp_ws is not None:
        response = {"type": "user_disconnected", "username": user.username}
        await opp_ws.send_json(response)
        await round_broadcast(game, users, response)

    if game is not None and not user.bot:
        if game.id in user.game_sockets:
            del user.game_sockets[game.id]

        if user.username != game.wplayer.username and user.username != game.bplayer.username:
            game.spectators.discard(user)
            await round_broadcast(game, users, game.spectator_list, full=True)

        # not connected to lobby socket and not connected to game socket
        if len(user.game_sockets) == 0 and user.username not in sockets:
            request.app["u_cnt"] -= 1
            response = {"type": "u_cnt", "cnt": request.app["u_cnt"]}
            await lobby_broadcast(sockets, response)

    if game_ping_task is not None:
        game_ping_task.cancel()

    return ws
Exemple #7
0
async def tournament_socket_handler(request):

    users = request.app["users"]
    sockets = request.app["tourneysockets"]
    lobby_sockets = request.app["lobbysockets"]
    tourneychat = request.app["tourneychat"]

    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 tournament 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_players":
                        tournament = await load_tournament(
                            request.app, data["tournamentId"])
                        if tournament is not None:
                            page = data["page"]
                            if user in tournament.players and tournament.players[
                                    user].page != page:
                                tournament.players[user].page = page
                            response = tournament.players_json(page=page)
                            await ws.send_json(response)

                    elif data["type"] == "my_page":
                        tournament = await load_tournament(
                            request.app, data["tournamentId"])
                        if tournament is not None:
                            if user in tournament.players:
                                # force to get users current page by leaderbord status
                                tournament.players[user].page = -1
                            response = tournament.players_json(user=user)
                            await ws.send_json(response)

                    elif data["type"] == "get_games":
                        tournament = await load_tournament(
                            request.app, data["tournamentId"])
                        if tournament is not None:
                            response = tournament.games_json(data["player"])
                            await ws.send_json(response)

                    elif data["type"] == "join":
                        tournament = await load_tournament(
                            request.app, data["tournamentId"])
                        if tournament is not None:
                            await tournament.join(user)
                            response = {
                                "type": "ustatus",
                                "username": user.username,
                                "ustatus": tournament.user_status(user)
                            }
                            await ws.send_json(response)

                    elif data["type"] == "pause":
                        tournament = await load_tournament(
                            request.app, data["tournamentId"])
                        if tournament is not None:
                            await tournament.pause(user)
                            response = {
                                "type": "ustatus",
                                "username": user.username,
                                "ustatus": tournament.user_status(user)
                            }
                            await ws.send_json(response)

                    elif data["type"] == "withdraw":
                        tournament = await load_tournament(
                            request.app, data["tournamentId"])
                        if tournament is not None:
                            await tournament.withdraw(user)
                            response = {
                                "type": "ustatus",
                                "username": user.username,
                                "ustatus": tournament.user_status(user)
                            }
                            await ws.send_json(response)

                    elif data["type"] == "tournament_user_connected":
                        tournamentId = data["tournamentId"]
                        tournament = await load_tournament(
                            request.app, tournamentId)
                        if tournament is None:
                            continue

                        if session_user is not None:
                            if data["username"] and data[
                                    "username"] != session_user:
                                log.info(
                                    "+++ Existing tournament_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
                        if tournamentId not in user.tournament_sockets:
                            user.tournament_sockets[tournamentId] = set()
                        user.tournament_sockets[tournamentId].add(ws)

                        user.update_online()

                        sockets[tournamentId][
                            user.
                            username] = user.tournament_sockets[tournamentId]

                        now = datetime.now(timezone.utc)
                        response = {
                            "type":
                            "tournament_user_connected",
                            "username":
                            user.username,
                            "ustatus":
                            tournament.user_status(user),
                            "urating":
                            tournament.user_rating(user),
                            "tstatus":
                            tournament.status,
                            "tsystem":
                            tournament.system,
                            "tminutes":
                            tournament.minutes,
                            "startsAt":
                            tournament.starts_at.isoformat(),
                            "startFen":
                            tournament.fen,
                            "description":
                            tournament.description,
                            "frequency":
                            tournament.frequency,
                            "secondsToStart":
                            (tournament.starts_at - now).total_seconds()
                            if tournament.starts_at > now else 0,
                            "secondsToFinish":
                            (tournament.ends_at - now).total_seconds()
                            if tournament.starts_at < now else 0,
                        }
                        if tournament.frequency == SHIELD:
                            variant_name = tournament.variant + (
                                "960" if tournament.chess960 else "")
                            defender = users[request.app["shield_owners"]
                                             [variant_name]]
                            response["defender_title"] = defender.title
                            response["defender_name"] = defender.username

                        await ws.send_json(response)

                        if (tournament.top_game is not None) and (
                                tournament.top_game.status <= STARTED):
                            await ws.send_json(tournament.top_game_json)

                        if tournament.status > T_STARTED:
                            await ws.send_json(tournament.summary)

                        response = {
                            "type": "fullchat",
                            "lines": list(tourneychat[tournamentId])
                        }
                        await ws.send_json(response)

                        if user.username not in tournament.spectators:
                            tournament.spactator_join(user)
                            await tournament.broadcast(
                                tournament.spectator_list)

                        if len(user.game_sockets) == 0 and len(
                                user.lobby_sockets) == 0:
                            response = {
                                "type": "u_cnt",
                                "cnt": online_count(users)
                            }
                            await lobby_broadcast(lobby_sockets, response)

                    elif data["type"] == "lobbychat":
                        tournamentId = data["tournamentId"]
                        tournament = await load_tournament(
                            request.app, tournamentId)
                        message = data["message"]
                        response = None

                        if user.username in ADMINS:
                            if message.startswith("/silence"):
                                response = silence(message,
                                                   tourneychat[tournamentId],
                                                   users)
                            elif message.startswith("/abort"):
                                if tournament.status in (T_CREATED, T_STARTED):
                                    await tournament.abort()
                            else:
                                response = chat_response(
                                    "lobbychat", user.username,
                                    data["message"])
                        else:
                            if user.silence == 0:
                                response = chat_response(
                                    "lobbychat", user.username,
                                    data["message"])

                        if response is not None:
                            await tournament.broadcast(response)
                            tourneychat[tournamentId].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(
                    "--- Tournament websocket %s msg.type == aiohttp.WSMsgType.CLOSED",
                    id(ws))
                break

            elif msg.type == aiohttp.WSMsgType.ERROR:
                log.error(
                    "--- Tournament ws %s msg.type == aiohttp.WSMsgType.ERROR",
                    id(ws))
                break

            else:
                log.debug("--- Tournament ws other msg.type %s %s", msg.type,
                          msg)

    except OSError:
        # disconnected
        pass

    except Exception:
        log.exception(
            "ERROR: Exception in tournament_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:
            for tournamentId in user.tournament_sockets:
                if ws in user.tournament_sockets[tournamentId]:
                    user.tournament_sockets[tournamentId].remove(ws)

                    if len(user.tournament_sockets[tournamentId]) == 0:
                        del user.tournament_sockets[tournamentId]
                        user.update_online()

                        if tournamentId in sockets and user.username in sockets[
                                tournamentId]:
                            del sockets[tournamentId][user.username]
                            tournament = await load_tournament(
                                request.app, tournamentId)
                            tournament.spactator_leave(user)
                            await tournament.broadcast(
                                tournament.spectator_list)

                        if not user.online:
                            response = {
                                "type": "u_cnt",
                                "cnt": online_count(users)
                            }
                            await lobby_broadcast(lobby_sockets, response)
                    break

    return ws
Exemple #8
0
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