Exemplo n.º 1
0
    async def process_request(self, request: dict) -> dict:
        """
        This should be called for each client request.

        Parses requests and deals with any errors and responses to client.
        :param request: dict which has to be formatted as follows:
            {
              "endpoint": "string which endpoint to use",
              "data": [optional] data to be used on endpoint function (list of member IDs etc)
            }
            Endpoint is available if it was decorated with @endpoint_register
        """
        if not isinstance(request, dict):
            logger.critical(
                "Error processing socket comm, request is not a dict.")
            return InternalServerError().response

        endpoint_key = request.get("endpoint")

        if not endpoint_key:
            return EndpointError(400, "No endpoint specified.").response
        elif not isinstance(endpoint_key, str):
            return EndpointError(400,
                                 "Endpoint name has to be a string.").response

        function = _endpoints_mapping.get(endpoint_key)

        if function is None:
            return EndpointNotFound().response

        endpoint_data = request.get("data")

        try:
            # Key data is optional
            if not endpoint_data:
                endpoint_returned_data = await function(self)
            else:
                endpoint_returned_data = await function(self, endpoint_data)
        except TypeError as e:
            logger.critical(
                f"Bad arguments for endpoint {endpoint_key} {endpoint_data} {e}"
            )
            return EndpointBadArguments().response
        except EndpointError as e:
            # If endpoint function raises then return it's response
            return e.response
        except Exception as e:
            logger.critical(
                f"Error processing socket endpoint: {endpoint_key} , data:{endpoint_data} {e}"
            )
            return InternalServerError().response

        # If we've come all the way here then no errors occurred and endpoint function executed correctly.
        server_response = EndpointSuccess().response

        # Endpoint return data is optional
        if endpoint_returned_data is None:
            return server_response
        else:
            server_response.update({"data": endpoint_returned_data})
            return endpoint_returned_data
Exemplo n.º 2
0
    async def handle_client(self, client, client_name: str):
        while True:  # keep receiving client requests until he closes/disconnects
            request = ""

            while True:  # buffer client request in case of long message
                try:
                    buffer = (await self.bot.loop.sock_recv(
                        client, buffer_size)).decode("utf8")
                    request += buffer
                except ConnectionResetError:
                    # If the client disconnects without sending quit.
                    logger.debug(f"{client_name} disconnected.")
                    return

                if len(buffer) < buffer_size:
                    break
                elif len(request) > maximum_buffer:
                    response = EndpointError(400,
                                             "Buffer size exceeded.").response
                    await self.send_to_client(client, json.dumps(response))
                    client.close()
                    return

            if not request:
                logger.debug("Empty, closing.")
                break

            try:
                request = json.loads(request)
            except json.JSONDecodeError:
                response = EndpointError(
                    400, "Not a valid JSON formatted request.").response
                await self.send_to_client(client, json.dumps(response))
                logger.debug(f"{client_name}:{response}:{request}")
                continue

            logger.debug(f"Server got:{request}")

            # TODO
            # temporal hardcoded fix to make ping endpoint public
            endpoint_key = request.get("endpoint")

            if client not in self.verified_clients and endpoint_key != "ping":
                token = request.get("auth")
                if token is not None and token == self.auth_token:
                    self.verified_clients.add(client)
                    response = EndpointSuccess().response
                    await self.send_to_client(client, json.dumps(response))
                    logger.info(f"{client_name} successfully authorized.")
                    continue
                else:
                    response = EndpointError(
                        401,
                        "Verification unsuccessful, closing conn..").response
                    await self.send_to_client(client, json.dumps(response))
                    logger.debug(f"{client_name}:{response}:{request}")
                    break

            response = await self.process_request(request)
            logger.debug(f"Request processed, response:{response}")
            await self.send_to_client(client, json.dumps(response))

        logger.info(f"Closing {client_name}")
        self.verified_clients.discard(client)
        client.close()