예제 #1
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
예제 #2
0
async def event_stream(request):
    auth = request.headers.get("Authorization")
    if auth is None:
        return web.HTTPForbidden()

    token = auth[auth.find("Bearer") + 7:]
    if token not in BOT_TOKENS:
        log.error("BOT account auth with token %s failed" % token)
        return web.HTTPForbidden()

    user_agent = request.headers.get("User-Agent")
    username = user_agent[user_agent.find("user:"******"users"]
    seeks = request.app["seeks"]
    sockets = request.app["websockets"]
    games = request.app["games"]
    db = request.app["db"]

    resp = web.StreamResponse()
    resp.content_type = "text/plain"
    await resp.prepare(request)

    if username in users:
        bot_player = users[username]
        # After BOT lost connection it may have ongoing games
        # We notify BOT and he can ask to create new game_streams
        # to continue those games
        for gameId in bot_player.game_queues:
            if gameId in games and games[gameId].status == STARTED:
                await bot_player.event_queue.put(games[gameId].game_start)
    else:
        bot_player = User(bot=True, username=username)
        users[bot_player.username] = bot_player

        doc = await db.user.find_one({"_id": username})
        if doc is None:
            result = await db.user.insert_one({
                "_id": username,
                "first_name": None,
                "last_name": None,
                "country": None,
                "title": "BOT",
            })
            print("db insert user result %s" % repr(result.inserted_id))

    bot_player.bot_online = True

    log.info("+++ BOT %s connected" % bot_player.username)

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

    # inform others
    # TODO: do we need this at all?
    await lobby_broadcast(sockets, get_seeks(seeks))

    # send "challenge" and "gameStart" events from event_queue to the BOT
    while bot_player.online:
        answer = await bot_player.event_queue.get()
        try:
            if request.protocol.transport.is_closing():
                log.error(
                    "BOT %s request.protocol.transport.is_closing() == True ..."
                    % username)
                break
            else:
                await resp.write(answer.encode("utf-8"))
                await resp.drain()
        except Exception:
            log.error("BOT %s event_stream is broken..." % username)
            break

    pinger_task.cancel()
    await bot_player.clear_seeks(sockets, seeks)
    return resp