async def _handle_call(self, msg):
        """
        Execute all hooks installed for based on the Action of the message.

        First the '_on_action' hook is executed and its response is returned to
        the client. If there is no '_on_action' hook for Action in the message
        a CallError with a NotImplemtendError is returned.

        Next the '_after_action' hook is executed.

        """
        try:
            handlers = self.route_map[msg.action]
        except KeyError:
            raise NotImplementedError(f"No handler for '{msg.action}' "
                                      "registered.")

        if not handlers.get('_skip_schema_validation', False):
            validate_payload(msg, self._ocpp_version)

        # OCPP uses camelCase for the keys in the payload. It's more pythonic
        # to use snake_case for keyword arguments. Therefore the keys must be
        # 'translated'. Some examples:
        #
        # * chargePointVendor becomes charge_point_vendor
        # * firmwareVersion becomes firmwareVersion
        snake_case_payload = camel_to_snake_case(msg.payload)

        try:
            handler = handlers['_on_action']
        except KeyError:
            raise NotImplementedError(f"No handler for '{msg.action}' "
                                      "registered.")

        try:
            response = handler(**snake_case_payload)
            if inspect.isawaitable(response):
                response = await response
        except Exception as e:
            LOGGER.exception("Error while handling request '%s'", msg)
            response = msg.create_call_error(e).to_json()
            await self._send(response)

            return

        temp_response_payload = asdict(response)

        # Remove nones ensures that we strip out optional arguments
        # which were not set and have a default value of None
        response_payload = remove_nones(temp_response_payload)

        # The response payload must be 'translated' from snake_case to
        # camelCase. So:
        #
        # * charge_point_vendor becomes chargePointVendor
        # * firmware_version becomes firmwareVersion
        camel_case_payload = snake_to_camel_case(response_payload)

        response = msg.create_call_result(camel_case_payload)

        if not handlers.get('_skip_schema_validation', False):
            validate_payload(response, self._ocpp_version)

        await self._send(response.to_json())

        try:
            handler = handlers['_after_action']
            # Create task to avoid blocking when making a call inside the
            # after handler
            response = handler(**snake_case_payload)
            if inspect.isawaitable(response):
                asyncio.ensure_future(response)
        except KeyError:
            # '_on_after' hooks are not required. Therefore ignore exception
            # when no '_on_after' hook is installed.
            pass
Пример #2
0
    async def _handle_call(self, msg, *, context: RouterContext = None):
        """
        Execute all hooks installed for based on the Action of the message.

        First the '_on_action' hook is executed and its response is returned to
        the client. If there is no '_on_action' hook for Action in the message
        a CallError with a NotImplemtendError is returned.

        Next the '_after_action' hook is executed.

        """
        ocpp_version = subprotocol_to_ocpp_version(self.subprotocol)

        try:
            handlers = self._route_map[msg.action]
        except KeyError:
            raise NotImplementedError(f"No handler for '{msg.action}' "
                                      "registered.")

        if not handlers.get("_skip_schema_validation", False):
            validate_payload(msg, ocpp_version)

        # OCPP uses camelCase for the keys in the payload. It's more pythonic
        # to use snake_case for keyword arguments. Therefore the keys must be
        # 'translated'. Some examples:
        #
        # * chargePointVendor becomes charge_point_vendor
        # * firmwareVersion becomes firmwareVersion
        snake_case_payload = camel_to_snake_case(msg.payload)

        try:
            handler = handlers["_on_action"]
        except KeyError:
            raise NotImplementedError(f"No handler for '{msg.action}' "
                                      "registered.")

        handler_context = HandlerContext(
            charging_station_id=context.charging_station_id,
            _router_context=context,
            _router=self,
        )
        # Convert message to correct Call instance
        class_ = getattr(context.ocpp_adapter.call, f"{msg.action}Payload")
        payload = class_(**snake_case_payload)
        try:
            response = handler(payload=payload, context=handler_context)
            if inspect.isawaitable(response):
                response = await response
        except Exception as e:
            log.exception("Error while handling request '%s'", msg)
            response = msg.create_call_error(e).to_json()
            await self._send(message=response,
                             is_response=True,
                             context=context)

        temp_response_payload = asdict(response)

        # Remove nones ensures that we strip out optional arguments
        # which were not set and have a default value of None
        response_payload = remove_nones(temp_response_payload)

        # The response payload must be 'translated' from snake_case to
        # camelCase. So:
        #
        # * charge_point_vendor becomes chargePointVendor
        # * firmware_version becomes firmwareVersion
        camel_case_payload = snake_to_camel_case(response_payload)

        response = msg.create_call_result(camel_case_payload)

        if not handlers.get("_skip_schema_validation", False):
            validate_payload(response, ocpp_version)

        await self._send(message=response.to_json(),
                         is_response=True,
                         context=context)

        try:
            handler = handlers["_after_action"]
            response = handler(payload=payload, context=handler_context)
            if inspect.isawaitable(response):
                if self._create_task:
                    # Create task to avoid blocking when making a call
                    # inside the after handler
                    asyncio.ensure_future(response)
                else:
                    await response
        except KeyError:
            # '_on_after' hooks are not required. Therefore ignore exception
            # when no '_on_after' hook is installed.
            pass