예제 #1
0
파일: wsr.py 프로젝트: PayitLay/charcoalmom
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
예제 #2
0
async def index(request):
    """ Create home html. """

    users = request.app["users"]
    games = request.app["games"]
    db = request.app["db"]

    # Who made the request?
    session = await aiohttp_session.get_session(request)
    session_user = session.get("user_name")

    session["last_visit"] = datetime.now().isoformat()
    session["guest"] = True
    if session_user is not None:
        log.info("+++ Existing user %s connected." % session_user)
        doc = await db.user.find_one({"_id": session_user})
        if doc is not None:
            session["guest"] = False

        if session_user in users:
            user = users[session_user]
        else:
            log.debug("New lichess user appeared!", session_user)
            perfs = {variant: DEFAULT_PERF for variant in VARIANTS}
            user = User(db=db,
                        username=session_user,
                        anon=session["guest"],
                        perfs=perfs)
            users[user.username] = user
        user.ping_counter = 0
    else:
        user = User(db=db, anon=True)
        log.info("+++ New guest user %s connected." % user.username)
        users[user.username] = user
        session["user_name"] = user.username

    view = "lobby"
    gameId = request.match_info.get("gameId")

    if request.path == "/about":
        view = "about"
    elif request.path == "/howtoplay":
        view = "howtoplay"
    elif request.path == "/players":
        view = "players"
    elif request.path == "/games":
        view = "games"
    elif request.path == "/patron/thanks":
        view = "thanks"
    elif request.path == "/level8win":
        view = "level8win"
    elif request.path == "/tv":
        view = "tv"
        doc = await db.game.find_one({}, sort=[('$natural', -1)])
        if doc is not None:
            gameId = doc["_id"]

    profileId = request.match_info.get("profileId")
    variant = request.match_info.get("variant")
    if profileId is not None:
        view = "profile"
        if request.path[-3:] == "/tv":
            view = "tv"
            # TODO: tv for variants
            doc = await db.game.find_one({"us": profileId},
                                         sort=[('$natural', -1)])
            if doc is not None:
                gameId = doc["_id"]

    # Do we have gameId in request url?
    if gameId is not None:
        if view != "tv":
            view = "round"
        game = await load_game(request.app, gameId)
        if game is None:
            log.debug("Requseted game %s not in app['games']" % gameId)
            template = request.app["jinja"].get_template("404.html")
            return web.Response(text=html_minify(template.render({"home":
                                                                  URI})),
                                content_type="text/html")
        games[gameId] = game

        if game.status > STARTED:
            view = "analysis"

        if user.username != game.wplayer.username and user.username != game.bplayer.username:
            game.spectators.add(user)

    if view == "profile" or view == "level8win":
        if (profileId in users) and not users[profileId].enabled:
            template = request.app["jinja"].get_template("closed.html")
        else:
            template = request.app["jinja"].get_template("profile.html")
    elif view == "players":
        template = request.app["jinja"].get_template("players.html")
    else:
        template = request.app["jinja"].get_template("index.html")

    render = {
        "app_name": "PyChess",
        "title": view.capitalize(),
        "view": view,
        "home": URI,
        "user": user.username if session["guest"] else "",
        "anon": user.anon,
        "country": session["country"] if "country" in session else "",
        "guest": session["guest"],
        "profile": profileId if profileId is not None else "",
    }
    if profileId is not None:
        render["title"] = "Profile • " + profileId
        render["icons"] = VARIANT_ICONS
        if profileId not in users or users[profileId].perfs is None:
            render["ratings"] = {}
        else:
            render["ratings"] = {
                k: ("%s%s" % (int(round(v["gl"]["r"], 0)),
                              "?" if v["gl"]["d"] > PROVISIONAL_PHI else ""),
                    v["nb"])
                for (k, v) in sorted(users[profileId].perfs.items(),
                                     key=lambda x: x[1]["nb"],
                                     reverse=True)
            }
        if variant is not None:
            render["variant"] = variant
        render["profile_title"] = users[
            profileId].title if profileId in users else ""

    if view == "players":
        render["icons"] = VARIANT_ICONS
        render["users"] = request.app["users"]
        render["highscore"] = request.app["highscore"]

    if gameId is not None:
        render["gameid"] = gameId
        render["variant"] = game.variant
        render["wplayer"] = game.wplayer.username
        render["wtitle"] = game.wplayer.title
        render["wrating"] = game.wrating
        render["wrdiff"] = game.wrdiff
        render["chess960"] = game.chess960
        render["rated"] = game.rated
        render["level"] = game.level
        render["bplayer"] = game.bplayer.username
        render["btitle"] = game.bplayer.title
        render["brating"] = game.brating
        render["brdiff"] = game.brdiff
        render["fen"] = game.board.fen
        render["base"] = game.base
        render["inc"] = game.inc
        render["result"] = game.result
        render["status"] = game.status
        render["date"] = game.date.isoformat()
        render[
            "title"] = game.wplayer.username + ' vs ' + game.bplayer.username

    if view == "level8win":
        render["level"] = 8
        render["profile"] = "Fairy-Stockfish"

    text = template.render(render)

    # log.debug("Response: %s" % text)
    response = web.Response(text=html_minify(text), content_type="text/html")
    hostname = urlparse(URI).hostname
    response.set_cookie("user",
                        session["user_name"],
                        domain=hostname,
                        secure="." not in hostname,
                        max_age=31536000)
    return response
예제 #3
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 else None

    lobby_ping_task = None

    log.debug("-------------------------- NEW lobby WEBSOCKET by %s" % user)

    async for msg in ws:
        if msg.type == aiohttp.WSMsgType.TEXT:
            if type(msg.data) == str:
                if msg.data == "close":
                    log.debug("Got 'close' msg.")
                    break
                else:
                    data = json.loads(msg.data)
                    if not data["type"] == "pong":
                        log.debug("Websocket (%s) message: %s" % (id(ws), msg))

                    if data["type"] == "pong":
                        user.ping_counter -= 1

                    elif data["type"] == "get_seeks":
                        response = get_seeks(seeks)
                        await ws.send_json(response)

                    elif data["type"] == "create_ai_challenge":
                        variant = data["variant"]
                        engine = users.get("Fairy-Stockfish")

                        if engine is None or not engine.online:
                            # TODO: message that engine is offline, but capture BOT will play instead
                            engine = users.get("Random-Mover")

                        seek = Seek(user, variant, data["fen"], data["color"], data["minutes"], data["increment"], data["level"], data["rated"], data["chess960"])
                        # print("SEEK", user, variant, data["fen"], data["color"], data["minutes"], data["increment"], data["level"], False, data["chess960"])
                        seeks[seek.id] = seek

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

                        gameId = response["gameId"]
                        engine.game_queues[gameId] = asyncio.Queue()
                        await engine.event_queue.put(challenge(seek, response))

                    elif data["type"] == "create_seek":
                        print("create_seek", data)
                        create_seek(seeks, user, data)
                        await lobby_broadcast(sockets, get_seeks(seeks))

                    elif data["type"] == "delete_seek":
                        del seeks[data["seekID"]]
                        del user.seeks[data["seekID"]]

                        await lobby_broadcast(sockets, get_seeks(seeks))

                    elif data["type"] == "accept_seek":
                        if data["seekID"] not in seeks:
                            continue

                        seek = seeks[data["seekID"]]
                        print("accept_seek", seek.as_json)
                        response = await new_game(request.app, user, data["seekID"])
                        await ws.send_json(response)

                        if seek.user.lobby_ws is not None:
                            await seek.user.lobby_ws.send_json(response)

                        if seek.user.bot:
                            gameId = response["gameId"]
                            seek.user.game_queues[gameId] = asyncio.Queue()
                            await seek.user.event_queue.put(challenge(seek, response))

                        # Inform others, new_game() deleted accepted seek allready.
                        await lobby_broadcast(sockets, get_seeks(seeks))

                    elif data["type"] == "lobby_user_connected":
                        if session_user is not None:
                            if data["username"] and data["username"] != session_user:
                                log.info("+++ Existing lobby_user %s socket connected as %s." % (session_user, data["username"]))
                                session_user = data["username"]
                                if session_user in users:
                                    user = users[session_user]
                                else:
                                    user = User(db=request.app["db"], username=data["username"], anon=data["username"].startswith("Anonymous"))
                                    users[user.username] = user
                                response = {"type": "lobbychat", "user": "", "message": "%s joined the lobby" % session_user}
                            else:
                                user = users[session_user]
                                response = {"type": "lobbychat", "user": "", "message": "%s joined the lobby" % session_user}
                        else:
                            log.info("+++ Existing lobby_user %s socket reconnected." % data["username"])
                            session_user = data["username"]
                            if session_user in users:
                                user = users[session_user]
                            else:
                                user = User(db=request.app["db"], username=data["username"], anon=data["username"].startswith("Anonymous"))
                                users[user.username] = user
                            response = {"type": "lobbychat", "user": "", "message": "%s rejoined the lobby" % session_user}

                        user.ping_counter = 0
                        await lobby_broadcast(sockets, response)

                        # update websocket
                        sockets[user.username] = ws
                        user.lobby_ws = ws

                        response = {"type": "lobby_user_connected", "username": user.username}
                        await ws.send_json(response)

                        response = {"type": "fullchat", "lines": list(request.app["chat"])}
                        await ws.send_json(response, dumps=partial(json.dumps, default=datetime.isoformat))

                        loop = asyncio.get_event_loop()
                        lobby_ping_task = loop.create_task(user.pinger(sockets, seeks, users, games))
                        request.app["tasks"].add(lobby_ping_task)

                    elif data["type"] == "lobbychat":
                        response = {"type": "lobbychat", "user": user.username, "message": data["message"]}
                        await lobby_broadcast(sockets, response)
                        request.app["chat"].append(response)

                    elif data["type"] == "disconnect":
                        # Used only to test socket disconnection...
                        await ws.close(code=1009)

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

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

    if lobby_ping_task is not None:
        lobby_ping_task.cancel()
        if user is not None:
            await user.clear_seeks(sockets, seeks)
            await user.quit_lobby(sockets, disconnect=False)
    return ws