Ejemplo n.º 1
0
async def ws_handler(request):
    channel = request.match_info['channel']
    ws = WebSocketResponse()
    await ws.prepare(request)
    print('Someone joined channel : %s.' % channel)

    try:
        request.app['sockets'][channel].append(ws)
    except KeyError:
        request.app['sockets'][channel] = []
        request.app['sockets'][channel].append(ws)

    while not ws.closed:
        msg = await ws.receive()
        if msg.tp == MsgType.text:
            if msg.data == 'close':
                await ws.close()
            else:
                print('The client responded: ' + msg.data)
        elif msg.tp == MsgType.close:
            print('websocket connection closed')
        elif msg.tp == MsgType.error:
            print('ws connection closed with exception %s' % ws.exception())

    request.app['sockets'][channel].remove(ws)
    print('Someone disconnected from channel : %s.' % channel)
    return ws
Ejemplo n.º 2
0
    async def controller(self, request: Request):

        ws = WebSocketResponse()

        await ws.prepare(request)

        clients.append(ws)

        logger.info("New client connected to the sync service")

        async for msg in ws:
            if msg.type == WSMsgType.TEXT:
                if msg.data == 'close':
                    await ws.close()
                else:
                    message = json.loads(msg.data)

                    action = message['action']
                    diff = message['diff']

                    if not self._config.dashboard_config_loader.is_loaded:
                        self._config.dashboard_config_loader.data = default_dashboard_data

                    dict_merge(diff['added'],
                               self._config.dashboard_config_loader.data)
                    dict_merge(diff['updated'],
                               self._config.dashboard_config_loader.data)

                    find_removed_node(
                        diff['deleted'],
                        self._config.dashboard_config_loader.data)

                    # TODO: delay with some sec (and add if new trigger)
                    self._config.save()

                    dispatch_clients = list(filter(lambda c: c != ws, clients))

                    if dispatch_clients:

                        action['time'] = time()
                        action_msg = json.dumps(action)

                        logger.debug("Action dispatch to %s clients(s)",
                                     len(dispatch_clients))

                        for client in dispatch_clients:
                            await client.send_str(action_msg)

            elif msg.type == WSMsgType.ERROR:
                logger.error("ws connection closed with exception %s",
                             ws.exception())

        logger.info("websocket connection closed")

        clients.remove(ws)

        return ws
Ejemplo n.º 3
0
    async def handle_web_socket(self, request):
        """
        Handles a new arriving web socket

        :param request: request received.
        :return:
        """
        self.logger.debug('starting handle_web_socket')
        ws = WebSocketResponse()
        await ws.prepare(request)

        session_id = str(uuid.uuid1())
        ip_address = self.server_data.ip_address4
        if self.server_data.use_ipv6:
            ip_address = self.server_data.ip_address6

        peername = request.transport.get_extra_info('peername')
        host, port = peername

        from auction_server.auction_session import AuctionSession
        session = AuctionSession(session_id, ip_address,
                                 self.server_data.local_port, host, port,
                                 self.server_data.protocol)

        client_connection = ClientConnection(session_id)
        client_connection.set_web_socket(ws)
        client_connection.set_session(session)
        session.set_connection(client_connection)
        self.session_manager.add_session(session)

        try:
            async for msg in ws:
                if msg.type == WSMsgType.text:
                    await self.process_message(session, msg.data)

                elif msg.type == WSMsgType.error:
                    self.logger.debug(
                        'ws connection closed with exception %s' %
                        ws.exception())

                elif msg.type == WSMsgType.close:
                    self.logger.debug('ws connection closed')
        finally:
            if session_id in self.session_manager.get_session_keys():
                self.session_manager.del_session(session_id)

            self.logger.debug('# active sessions: {0}'.format(
                str(len(self.session_manager.session_objects))))

        self.logger.debug('websocket connection closed')
        return ws
Ejemplo n.º 4
0
def test_receive_exc_in_reader(make_request, loop, reader):
    req = make_request('GET', '/')
    ws = WebSocketResponse()
    yield from ws.prepare(req)

    exc = ValueError()
    res = helpers.create_future(loop)
    res.set_exception(exc)
    reader.read = make_mocked_coro(res)

    msg = yield from ws.receive()
    assert msg.tp == WSMsgType.error
    assert msg.data is exc
    assert ws.exception() is exc
Ejemplo n.º 5
0
def test_receive_exc_in_reader(make_request, loop, reader):
    req = make_request('GET', '/')
    ws = WebSocketResponse()
    yield from ws.prepare(req)

    exc = ValueError()
    res = helpers.create_future(loop)
    res.set_exception(exc)
    reader.read = make_mocked_coro(res)

    msg = yield from ws.receive()
    assert msg.tp == MsgType.error
    assert msg.data is exc
    assert ws.exception() is exc
Ejemplo n.º 6
0
 async def on_connect(self, request):
     web_socket = WebSocketResponse()
     await web_socket.prepare(request)
     self.app['websockets'].add(web_socket)
     try:
         async for msg in web_socket:
             if msg.type == WSMsgType.TEXT:
                 await self.on_status(None)
             elif msg.type == WSMsgType.ERROR:
                 print('web socket connection closed with exception %s' %
                       web_socket.exception())
     finally:
         self.app['websockets'].discard(web_socket)
     return web_socket
Ejemplo n.º 7
0
def function113(function271):
    var2027 = function271('GET', '/')
    var2897 = WebSocketResponse()
    yield from var2897.prepare(var2027)
    var962 = ValueError()
    var2897._writer = mock.Mock()
    var2897._writer.close.side_effect = var962
    yield from var2897.close()
    assert var2897.closed
    assert (var2897.exception() is var962)
    var2897._closed = False
    var2897._writer.close.side_effect = asyncio.CancelledError()
    with pytest.raises(asyncio.CancelledError):
        yield from var2897.close()
Ejemplo n.º 8
0
    async def _receive_msg(self, ws: web.WebSocketResponse):
        msg = await ws.receive()

        if msg.tp == MsgType.text:
            if msg.data == self.stop_msg:
                print('Got stop msg')
                await ws.close()
            else:
                await self.process_msg(msg.data)
        elif msg.tp == MsgType.close:
            print('websocket connection closed')
        elif msg.tp == MsgType.error:
            print('ws connection closed with exception %s' %
                  ws.exception())
Ejemplo n.º 9
0
def test_receive_client_disconnected(make_request, loop, reader):
    req = make_request('GET', '/')
    ws = WebSocketResponse()
    yield from ws.prepare(req)

    exc = errors.ClientDisconnectedError()
    res = helpers.create_future(loop)
    res.set_exception(exc)
    reader.read = make_mocked_coro(res)

    msg = yield from ws.receive()
    assert ws.closed
    assert msg.tp == WSMsgType.close
    assert msg.data is None
    assert ws.exception() is None
Ejemplo n.º 10
0
def test_receive_client_disconnected(make_request, loop, reader):
    req = make_request('GET', '/')
    ws = WebSocketResponse()
    yield from ws.prepare(req)

    exc = errors.ClientDisconnectedError()
    res = helpers.create_future(loop)
    res.set_exception(exc)
    reader.read = make_mocked_coro(res)

    msg = yield from ws.receive()
    assert ws.closed
    assert msg.tp == MsgType.close
    assert msg.data is None
    assert ws.exception() is None
Ejemplo n.º 11
0
 async def log(self, request):
     web_socket = WebSocketResponse()
     await web_socket.prepare(request)
     self.app['websockets'].add(web_socket)
     try:
         async for msg in web_socket:
             if msg.type == WSMsgType.TEXT:
                 if msg.data == 'close':
                     await web_socket.close()
             elif msg.type == WSMsgType.ERROR:
                 print('web socket connection closed with exception %s' %
                       web_socket.exception())
     finally:
         self.app['websockets'].remove(web_socket)
     return web_socket
Ejemplo n.º 12
0
    def test_close_exc2(self):
        req = self.make_request("GET", "/")
        ws = WebSocketResponse()
        self.loop.run_until_complete(ws.prepare(req))

        exc = ValueError()
        self.writer.close.side_effect = exc
        ws._writer = self.writer

        self.loop.run_until_complete(ws.close())
        self.assertTrue(ws.closed)
        self.assertIs(ws.exception(), exc)

        ws._closed = False
        self.writer.close.side_effect = asyncio.CancelledError()
        self.assertRaises(asyncio.CancelledError, self.loop.run_until_complete, ws.close())
Ejemplo n.º 13
0
    async def _websocket_handler(self, request: web.Request):
        """Handle websocket client."""

        ws_client = WebSocketResponse()
        ws_client.authenticated = False
        await ws_client.prepare(request)
        request.app["clients"].append(ws_client)

        # handle incoming messages
        async for msg in ws_client:
            try:
                if msg.type == WSMsgType.error:
                    LOGGER.warning("ws connection closed with exception %s",
                                   ws_client.exception())
                if msg.type != WSMsgType.text:
                    continue
                if msg.data == "close":
                    await ws_client.close()
                    break
                # regular message
                json_msg = msg.json(loads=ujson.loads)
                if "command" in json_msg and "data" in json_msg:
                    # handle command
                    await self._handle_command(
                        ws_client,
                        json_msg["command"],
                        json_msg["data"],
                        json_msg.get("id"),
                    )
                elif "event" in json_msg:
                    # handle event
                    await self._handle_event(ws_client, json_msg["event"],
                                             json_msg.get("data"))
            except AuthenticationError as exc:  # pylint:disable=broad-except
                # disconnect client on auth errors
                await self._send_json(ws_client, error=str(exc), **json_msg)
                await ws_client.close(message=str(exc).encode())
            except Exception as exc:  # pylint:disable=broad-except
                # log the error only
                await self._send_json(ws_client, error=str(exc), **json_msg)
                LOGGER.error("Error with WS client", exc_info=exc)

        # websocket disconnected
        request.app["clients"].remove(ws_client)
        LOGGER.debug("websocket connection closed: %s", request.remote)

        return ws_client
Ejemplo n.º 14
0
    def test_close_exc2(self):
        req = self.make_request('GET', '/')
        ws = WebSocketResponse()
        ws.start(req)

        exc = ValueError()
        self.writer.close.side_effect = exc
        ws._writer = self.writer

        self.loop.run_until_complete(ws.close())
        self.assertTrue(ws.closed)
        self.assertIs(ws.exception(), exc)

        ws._closed = False
        self.writer.close.side_effect = asyncio.CancelledError()
        self.assertRaises(asyncio.CancelledError,
                          self.loop.run_until_complete, ws.close())
Ejemplo n.º 15
0
def function2536(function271, arg68):
    var3402 = function271('GET', '/')
    var3771 = WebSocketResponse()
    yield from var3771.prepare(var3402)
    var3771._reader = mock.Mock()
    var2011 = ValueError()
    var1794 = helpers.create_future(arg68)
    var1794.set_exception(var2011)
    var3771._reader.read = make_mocked_coro(var1794)
    var3771._payload_writer.drain = mock.Mock()
    var3771._payload_writer.drain.return_value = helpers.create_future(arg68)
    var3771._payload_writer.drain.return_value.set_result(True)
    var2571 = yield from var3771.function1900()
    assert (var2571.type == WSMsgType.ERROR)
    assert (var2571.type is var2571.tp)
    assert (var2571.data is var2011)
    assert (var3771.exception() is var2011)
Ejemplo n.º 16
0
async def test_close_exc2(make_request):

    req = make_request('GET', '/')
    ws = WebSocketResponse()
    await ws.prepare(req)

    exc = ValueError()
    ws._writer = mock.Mock()
    ws._writer.close.side_effect = exc
    await ws.close()
    assert ws.closed
    assert ws.exception() is exc

    ws._closed = False
    ws._writer.close.side_effect = asyncio.CancelledError()
    with pytest.raises(asyncio.CancelledError):
        await ws.close()
Ejemplo n.º 17
0
def test_receive_exc_in_reader(make_request, loop, reader):
    req = make_request('GET', '/')
    ws = WebSocketResponse()
    yield from ws.prepare(req)

    exc = ValueError()
    res = helpers.create_future(loop)
    res.set_exception(exc)
    reader.read = make_mocked_coro(res)
    ws._resp_impl.transport.drain.return_value = helpers.create_future(loop)
    ws._resp_impl.transport.drain.return_value.set_result(True)

    msg = yield from ws.receive()
    assert msg.type == WSMsgType.ERROR
    assert msg.type is msg.tp
    assert msg.data is exc
    assert ws.exception() is exc
Ejemplo n.º 18
0
async def test_close_exc2(make_request):

    req = make_request('GET', '/')
    ws = WebSocketResponse()
    await ws.prepare(req)

    exc = ValueError()
    ws._writer = mock.Mock()
    ws._writer.close.side_effect = exc
    await ws.close()
    assert ws.closed
    assert ws.exception() is exc

    ws._closed = False
    ws._writer.close.side_effect = asyncio.CancelledError()
    with pytest.raises(asyncio.CancelledError):
        await ws.close()
Ejemplo n.º 19
0
async def test_receive_exc_in_reader(make_request, loop):
    req = make_request('GET', '/')
    ws = WebSocketResponse()
    await ws.prepare(req)

    ws._reader = mock.Mock()
    exc = ValueError()
    res = loop.create_future()
    res.set_exception(exc)
    ws._reader.read = make_mocked_coro(res)
    ws._payload_writer.drain = mock.Mock()
    ws._payload_writer.drain.return_value = loop.create_future()
    ws._payload_writer.drain.return_value.set_result(True)

    msg = await ws.receive()
    assert msg.type == WSMsgType.ERROR
    assert msg.data is exc
    assert ws.exception() is exc
Ejemplo n.º 20
0
async def test_receive_exc_in_reader(make_request, loop):
    req = make_request('GET', '/')
    ws = WebSocketResponse()
    await ws.prepare(req)

    ws._reader = mock.Mock()
    exc = ValueError()
    res = loop.create_future()
    res.set_exception(exc)
    ws._reader.read = make_mocked_coro(res)
    ws._payload_writer.drain = mock.Mock()
    ws._payload_writer.drain.return_value = loop.create_future()
    ws._payload_writer.drain.return_value.set_result(True)

    msg = await ws.receive()
    assert msg.type == WSMsgType.ERROR
    assert msg.data is exc
    assert ws.exception() is exc
Ejemplo n.º 21
0
def test_close_exc(make_request, reader, loop):
    req = make_request('GET', '/')

    ws = WebSocketResponse()
    yield from ws.prepare(req)

    exc = ValueError()
    reader.read.return_value = helpers.create_future(loop)
    reader.read.return_value.set_exception(exc)

    yield from ws.close()
    assert ws.closed
    assert ws.exception() is exc

    ws._closed = False
    reader.read.return_value = helpers.create_future(loop)
    reader.read.return_value.set_exception(asyncio.CancelledError())
    with pytest.raises(asyncio.CancelledError):
        yield from ws.close()
    assert ws.close_code == 1006
Ejemplo n.º 22
0
def test_close_exc(make_request, reader, loop):
    req = make_request('GET', '/')

    ws = WebSocketResponse()
    yield from ws.prepare(req)

    exc = ValueError()
    reader.read.return_value = helpers.create_future(loop)
    reader.read.return_value.set_exception(exc)

    yield from ws.close()
    assert ws.closed
    assert ws.exception() is exc

    ws._closed = False
    reader.read.return_value = helpers.create_future(loop)
    reader.read.return_value.set_exception(asyncio.CancelledError())
    with pytest.raises(asyncio.CancelledError):
        yield from ws.close()
    assert ws.close_code == 1006
Ejemplo n.º 23
0
    def test_close_exc(self):
        req = self.make_request("GET", "/")
        reader = self.reader.set_parser.return_value = mock.Mock()

        ws = WebSocketResponse()
        self.loop.run_until_complete(ws.prepare(req))

        exc = ValueError()
        reader.read.return_value = asyncio.Future(loop=self.loop)
        reader.read.return_value.set_exception(exc)

        self.loop.run_until_complete(ws.close())
        self.assertTrue(ws.closed)
        self.assertIs(ws.exception(), exc)

        ws._closed = False
        reader.read.return_value = asyncio.Future(loop=self.loop)
        reader.read.return_value.set_exception(asyncio.CancelledError())
        self.assertRaises(asyncio.CancelledError, self.loop.run_until_complete, ws.close())
        self.assertEqual(ws.close_code, 1006)
Ejemplo n.º 24
0
def function479(function271, arg926, arg363):
    var1796 = function271('GET', '/')
    var300 = WebSocketResponse()
    yield from var300.prepare(var1796)
    var300._reader = mock.Mock()
    var4357 = ValueError()
    var300._reader.read.return_value = helpers.create_future(arg926)
    var300._reader.read.return_value.set_exception(var4357)
    var300._payload_writer.drain = mock.Mock()
    var300._payload_writer.drain.return_value = helpers.create_future(arg926)
    var300._payload_writer.drain.return_value.set_result(True)
    yield from var300.close()
    assert var300.closed
    assert (var300.exception() is var4357)
    var300._closed = False
    var300._reader.read.return_value = helpers.create_future(arg926)
    var300._reader.read.return_value.set_exception(asyncio.CancelledError())
    with pytest.raises(asyncio.CancelledError):
        yield from var300.close()
    assert (var300.close_code == 1006)
Ejemplo n.º 25
0
    def test_close_exc(self):
        req = self.make_request('GET', '/')
        reader = self.reader.set_parser.return_value = mock.Mock()

        ws = WebSocketResponse()
        ws.start(req)

        exc = ValueError()
        reader.read.return_value = asyncio.Future(loop=self.loop)
        reader.read.return_value.set_exception(exc)

        self.loop.run_until_complete(ws.close())
        self.assertTrue(ws.closed)
        self.assertIs(ws.exception(), exc)

        ws._closed = False
        reader.read.return_value = asyncio.Future(loop=self.loop)
        reader.read.return_value.set_exception(asyncio.CancelledError())
        self.assertRaises(asyncio.CancelledError,
                          self.loop.run_until_complete, ws.close())
        self.assertEqual(ws.close_code, 1006)
Ejemplo n.º 26
0
async def test_close_exc(make_request, loop, mocker):
    req = make_request('GET', '/')

    ws = WebSocketResponse()
    await ws.prepare(req)

    ws._reader = mock.Mock()
    exc = ValueError()
    ws._reader.read.return_value = loop.create_future()
    ws._reader.read.return_value.set_exception(exc)
    ws._payload_writer.drain = mock.Mock()
    ws._payload_writer.drain.return_value = loop.create_future()
    ws._payload_writer.drain.return_value.set_result(True)

    await ws.close()
    assert ws.closed
    assert ws.exception() is exc

    ws._closed = False
    ws._reader.read.return_value = loop.create_future()
    ws._reader.read.return_value.set_exception(asyncio.CancelledError())
    with pytest.raises(asyncio.CancelledError):
        await ws.close()
    assert ws.close_code == 1006
Ejemplo n.º 27
0
async def ws_handler(request):
    resp = WebSocketResponse()
    ok, protocol = resp.can_start(request)
    logger.debug('ok %s, protocol %s', ok, protocol)
    if not ok:
        raise Exception('Could not start!')

    await resp.prepare(request)
    logger.debug('Someone joined.')
    app = request.app
    app['sockets'].append(resp)

    async for msg in resp:
        if msg.tp == MsgType.text:
            try:
                m = json.loads(msg.data)
                logger.debug('Got msg %s', m)
                if m['type'] in MSG_TYPES:
                    if hasattr(request, 'session'):
                        await get_tweets(resp, app, request.session, m, request.conn)
                    else:
                        logger.info('Unknown client, closing')
                        break
            except Exception as e:
                logger.exception('Got error %s', e)
                resp.send_str(json.dumps({'type': 'error', 'desc': 'Server error'}))
                break

        elif msg.tp == MsgType.error:
            logger.exception('ws connection closed with exception %s', resp.exception())

    await resp.close()
    app['sockets'].remove(resp)
    logger.debug('Connection is closed %s', resp)
    logger.debug('Return Response')
    return resp
Ejemplo n.º 28
0
async def test_close_exc(make_request, loop, mocker):
    req = make_request('GET', '/')

    ws = WebSocketResponse()
    await ws.prepare(req)

    ws._reader = mock.Mock()
    exc = ValueError()
    ws._reader.read.return_value = loop.create_future()
    ws._reader.read.return_value.set_exception(exc)
    ws._payload_writer.drain = mock.Mock()
    ws._payload_writer.drain.return_value = loop.create_future()
    ws._payload_writer.drain.return_value.set_result(True)

    await ws.close()
    assert ws.closed
    assert ws.exception() is exc

    ws._closed = False
    ws._reader.read.return_value = loop.create_future()
    ws._reader.read.return_value.set_exception(asyncio.CancelledError())
    with pytest.raises(asyncio.CancelledError):
        await ws.close()
    assert ws.close_code == 1006
Ejemplo n.º 29
0
async def lobby_socket_handler(request):

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

    ws = WebSocketResponse()

    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
    ping_counter = [0]

    async def lobby_pinger(ping_counter):
        """ Prevent Heroku to close inactive ws """
        while not ws.closed:
            if ping_counter[0] > 2:
                await ws.close(code=1009)

                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:
                    # log.info("%s went offline (PINGER)" % user.username)
                    await user.clear_seeks(sockets, seeks)
                    await user.quit_lobby(sockets, disconnect=True)
                    break

            if user.bot:
                await user.event_queue.put("\n")
                # heroku needs something at least in 50 sec not to close BOT connections (stream events) on server side
            else:
                await ws.send_json({
                    "type": "ping",
                    "timestamp": "%s" % time()
                })
            await asyncio.sleep(3)
            ping_counter[0] += 1

    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":
                        ping_counter[0] -= 1

                    elif 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["byoyomi_period"],
                                    level=data["level"],
                                    rated=data["rated"],
                                    chess960=data["chess960"],
                                    handicap=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)

                        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
                            }

                        ping_counter[0] = 0
                        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)

                        loop = asyncio.get_event_loop()
                        lobby_ping_task = loop.create_task(
                            lobby_pinger(ping_counter))

                        # 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
                            if len(user.lobby_sockets) == 1:
                                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 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:
            await user.clear_seeks(sockets, seeks)
            await user.quit_lobby(sockets, disconnect=False)

    if lobby_ping_task is not None:
        lobby_ping_task.cancel()

    return ws
Ejemplo n.º 30
0
async def round_socket_handler(request):

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

    ws = WebSocketResponse()

    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:
                            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":
                        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.byo_correction += game.inc * 1000
                        game.byoyomi_periods[0 if data["color"] ==
                                             "white" else 1] = data["period"]
                        # print("BYOYOMI:", data)

                    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:
                            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"] == "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
                        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 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)

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

                        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)
                        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
                        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:
        response = {"type": "user_disconnected", "username": user.username}
        await round_broadcast(game, users, response, full=True)

    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