Exemple #1
0
    async def _process_event(self, row_i: int, col_i: int, event: ZoneEvent,
                             socket: web.WebSocketResponse) -> None:
        try:
            event_processor = self._event_processor_factory.get_processor(
                event.type)
        except UnknownEvent:
            server_logger.warning(
                f"Unknown received event type '{event.type}'")
            return

        try:
            await event_processor.process(row_i,
                                          col_i,
                                          event,
                                          sender_socket=socket)
        except UnableToProcessEvent as exc:
            server_logger.debug(
                f"Unable to process event {event.type}: {str(exc)}")

            exception_event = exc.event
            exception_event_str = self._event_serializer_factory.get_serializer(
                exception_event.type).dump_json(exception_event)

            # FIXME: do kept this feature ?
            await socket.send_str(exception_event_str)
Exemple #2
0
    async def _listen(self, socket: web.WebSocketResponse, row_i: int,
                      col_i: int) -> None:
        server_logger.info(f"Listen websocket for zone {row_i},{col_i}")
        async for msg in socket:
            server_logger.debug(
                f"Receive message on websocket for zone {row_i},{col_i}: {msg}"
            )

            if msg.type == aiohttp.WSMsgType.ERROR:
                server_logger.error(
                    f"Zone websocket closed with exception {socket.exception()}"
                )
            else:
                try:
                    await self._process_msg(row_i, col_i, msg, socket)
                except DisconnectClient:
                    await socket.send_str(
                        self._event_serializer_factory.get_serializer(
                            ZoneEventType.SERVER_PERMIT_CLOSE).dump_json(
                                ZoneEvent(
                                    type=ZoneEventType.SERVER_PERMIT_CLOSE,
                                    data=EmptyData())))
                    return

        server_logger.info(f"Websocket of zone {row_i},{col_i} closed")
Exemple #3
0
    async def get_new_socket(self, request: Request, row_i: int,
                             col_i: int) -> web.WebSocketResponse:
        server_logger.info(f"Create websocket for zone {row_i},{col_i}")

        # Create socket
        socket = web.WebSocketResponse()
        await socket.prepare(request)

        # TODO BS 2019-01-23: Implement a heartbeat to close sockets where client disapear
        # see https://github.com/aio-libs/aiohttp/issues/961#issuecomment-239647597
        # Something lik asyncio.ensure_future(self._heartbeat(ws))

        # Make it available for send job
        self._sockets.setdefault((row_i, col_i), []).append(socket)

        # Start to listen client messages
        try:
            await self._listen(socket, row_i, col_i)
        except CancelledError:
            server_logger.debug(f"websocket ({row_i},{col_i}) seems cancelled")

        # If this code reached: ws is disconnected
        server_logger.debug(f"remove websocket ({row_i},{col_i})")
        self._sockets[(row_i, col_i)].remove(socket)

        return socket
Exemple #4
0
    async def _process(
        self,
        row_i: int,
        col_i: int,
        event: ZoneEvent[ClickActionData],
        sender_socket: web.WebSocketResponse,
    ) -> None:
        # FIXME Experimental way to identify action ...for now, only manage build ...
        path = event.data.base_url.split("?")[0]
        parts = path.split("/")
        character_id: str = parts[2]
        build_description_id: str = parts[5]
        character = self._kernel.character_lib.get(character_id)

        # FIXME BS: use dicts instead list for action descriptions
        description = next(
            ad
            for ad in self._kernel.game.config.actions[ActionType.BUILD]
            if ad.id == build_description_id
        )
        action = self._kernel.action_factory.get_build_action(description)
        input_ = action.input_model_serializer.load(event.data.to_dict())
        try:
            action.check_request_is_possible(character, input_)
            zone_events, sender_events = action.perform_from_event(character, input_)
        except ImpossibleAction as exc:
            # TODO BS: send event error
            server_logger.error(f"impossible action {build_description_id}: {str(exc)}")
            return

        for zone_event in zone_events:
            event_str = self._event_serializer_factory.get_serializer(zone_event.type).dump_json(
                zone_event
            )
            for socket in self._zone_events_manager.get_sockets(row_i, col_i):
                server_logger.debug(f"Send event on socket: {event_str}")

                try:
                    await socket.send_str(event_str)
                except Exception as exc:
                    server_logger.exception(exc)

        for sender_event in sender_events:
            event_str = self._event_serializer_factory.get_serializer(sender_event.type).dump_json(
                sender_event
            )
            server_logger.debug(f"Send event on socket: {event_str}")
            await sender_socket.send_str(event_str)
Exemple #5
0
    async def _process(
        self,
        row_i: int,
        col_i: int,
        event: ZoneEvent[PlayerMoveData],
        sender_socket: web.WebSocketResponse,
    ) -> None:
        # FIXME BS 2019-01-23: Check what move is possible (tile can be a rock, or water ...)
        # TODO BS 2019-01-23: Check given character id is authenticated used (security)
        # FIXME BS 2020-07-04: Check there is no build with traversable false
        # FIXME BS 2020-07-04: check move is just near previous position + refuse move event
        character = self._character_lib.get(event.data.character_id)
        self._character_lib.move_on_zone(
            character, to_row_i=event.data.to_row_i, to_col_i=event.data.to_col_i
        )

        event_str = self._event_serializer_factory.get_serializer(event.type).dump_json(event)
        for socket in self._zone_events_manager.get_sockets(row_i, col_i):
            server_logger.debug(f"Send event on socket: {event_str}")

            try:
                await socket.send_str(event_str)
            except Exception as exc:
                server_logger.exception(exc)
Exemple #6
0
 def build_from_validation_error(
         self, error: ProcessValidationError) -> DefaultErrorSchema:
     server_logger.debug(str(error))
     return super().build_from_validation_error(error)