Beispiel #1
0
 async def agent_processing(http_connection) -> bool:
     # we block here to give it some time for the envelope to make it to the queue
     await asyncio.sleep(1)
     envelope = await http_connection.receive()
     if envelope is not None:
         incoming_message = cast(
             HttpMessage,
             HttpSerializer().decode(envelope.message))
         message = HttpMessage(
             performative=HttpMessage.Performative.RESPONSE,
             dialogue_reference=("", ""),
             target=incoming_message.message_id,
             message_id=incoming_message.message_id + 1,
             version=incoming_message.version,
             headers=incoming_message.headers,
             status_code=201,
             status_text="Created",
             bodyy=b"Response body",
         )
         response_envelope = Envelope(
             to=envelope.sender,
             sender=envelope.to,
             protocol_id=envelope.protocol_id,
             context=envelope.context,
             message=HttpSerializer().encode(message),
         )
         await http_connection.send(response_envelope)
         is_exiting_correctly = True
     else:
         is_exiting_correctly = False
     return is_exiting_correctly
    async def test_connecting_to_aca(self):
        http_client_connection = HTTPClientConnection(
            address=self.aea_address,
            provider_address=self.aca_admin_address,
            provider_port=self.aca_admin_port,
        )
        http_client_connection.loop = asyncio.get_event_loop()

        # Request messages
        request_http_message = HttpMessage(
            dialogue_reference=("", ""),
            target=0,
            message_id=1,
            performative=HttpMessage.Performative.REQUEST,
            method="GET",
            url="http://{}:{}/status".format(self.aca_admin_address,
                                             self.aca_admin_port),
            headers="",
            version="",
            bodyy=b"",
        )
        request_envelope = Envelope(
            to="ACA",
            sender="AEA",
            protocol_id=HTTP_PROTOCOL_PUBLIC_ID,
            message=HttpSerializer().encode(request_http_message),
        )

        try:
            # connect to ACA
            await http_client_connection.connect()
            assert http_client_connection.connection_status.is_connected is True

            # send request to ACA
            await http_client_connection.send(envelope=request_envelope)

            # receive response from ACA
            response_envelop = await http_client_connection.receive()

            # check the response
            assert response_envelop.to == self.aea_address
            assert response_envelop.sender == "HTTP Server"
            assert response_envelop.protocol_id == HTTP_PROTOCOL_PUBLIC_ID
            decoded_response_message = HttpSerializer().decode(
                response_envelop.message)
            assert (decoded_response_message.performative ==
                    HttpMessage.Performative.RESPONSE)
            assert decoded_response_message.version == ""
            assert decoded_response_message.status_code == 200
            assert decoded_response_message.status_text == "OK"
            assert decoded_response_message.headers is not None
            assert decoded_response_message.version is not None

        finally:
            # disconnect from ACA
            await http_client_connection.disconnect()
            assert http_client_connection.connection_status.is_connected is False
Beispiel #3
0
 async def test_send_connection_send(self):
     """Test send connection error."""
     client_id = "to_key"
     message = HttpMessage(
         performative=HttpMessage.Performative.RESPONSE,
         dialogue_reference=("", ""),
         target=1,
         message_id=2,
         headers="",
         version="",
         status_code=200,
         status_text="Success",
         bodyy=b"",
     )
     envelope = Envelope(
         to=client_id,
         sender="from_key",
         protocol_id=self.protocol_id,
         message=HttpSerializer().encode(message),
     )
     self.http_connection.channel.pending_request_ids.add("to_key")
     await self.http_connection.send(envelope)
     assert (self.http_connection.channel.dispatch_ready_envelopes.get(
         client_id) == envelope)
     assert self.http_connection.channel.pending_request_ids == set()
     # clean up:
     self.http_connection.channel.dispatch_ready_envelopes = (
         {})  # type: Dict[str, Envelope]
    def to_envelope(self, connection_id: PublicId, agent_address: str) -> Envelope:
        """
        Process incoming API request by packaging into Envelope and sending it in-queue.

        The Envelope's message body contains the "performative", "path", "params", and "payload".

        :param http_method: the http method
        :param url: the url
        :param param: the parameter
        :param body: the body
        """
        uri = URI(self.full_url_pattern)
        context = EnvelopeContext(connection_id=connection_id, uri=uri)
        http_message = HttpMessage(
            dialogue_reference=("", ""),
            target=0,
            message_id=1,
            performative=HttpMessage.Performative.REQUEST,
            method=self.method,
            url=self.full_url_pattern,
            headers=self.parameters.header.as_string(),
            bodyy=self.body.encode() if self.body is not None else b"",
            version="",
        )
        envelope = Envelope(
            to=agent_address,
            sender=self.id,
            protocol_id=PublicId.from_str("fetchai/http:0.1.0"),
            context=context,
            message=HttpSerializer().encode(http_message),
        )
        return envelope
Beispiel #5
0
    def send(self, request_envelope: Envelope) -> None:
        """
        Convert an http envelope into an http request, send the http request, wait for and receive its response, translate the response into a response envelop,
        and send the response envelope to the in-queue.

        :param request_envelope: the envelope containing an http request
        :return: None
        """
        if self.excluded_protocols is not None:
            if request_envelope.protocol_id in self.excluded_protocols:
                logger.error(
                    "This envelope cannot be sent with the http client connection: protocol_id={}"
                    .format(request_envelope.protocol_id))
                raise ValueError("Cannot send message.")

            if request_envelope is not None:
                request_http_message = cast(
                    HttpMessage,
                    HttpSerializer().decode(request_envelope.message))
                if (request_http_message.performative ==
                        HttpMessage.Performative.REQUEST):
                    response = requests.request(
                        method=request_http_message.method,
                        url=request_http_message.url,
                        headers=request_http_message.headers,
                        data=request_http_message.bodyy,
                    )
                    response_envelope = self.to_envelope(
                        self.connection_id, request_http_message, response)
                    self.in_queue.put_nowait(response_envelope)  # type: ignore
                else:
                    logger.warning(
                        "The HTTPMessage performative must be a REQUEST. Envelop dropped."
                    )
Beispiel #6
0
    def to_envelope(
        self,
        connection_id: PublicId,
        http_request_message: HttpMessage,
        http_response: requests.models.Response,
    ) -> Envelope:
        """
        Convert an HTTP response object (from the 'requests' library) into an Envelope containing an HttpMessage (from the 'http' Protocol).

        :param connection_id: the connection id
        :param http_request_message: the message of the http request envelop
        :param http_response: the http response object
        """

        context = EnvelopeContext(connection_id=connection_id)
        http_message = HttpMessage(
            dialogue_reference=http_request_message.dialogue_reference,
            target=http_request_message.target,
            message_id=http_request_message.message_id,
            performative=HttpMessage.Performative.RESPONSE,
            status_code=http_response.status_code,
            headers=json.dumps(dict(http_response.headers)),
            status_text=http_response.reason,
            bodyy=http_response.content
            if http_response.content is not None else b"",
            version="",
        )
        envelope = Envelope(
            to=self.agent_address,
            sender="HTTP Server",
            protocol_id=PublicId.from_str("fetchai/http:0.1.0"),
            context=context,
            message=HttpSerializer().encode(http_message),
        )
        return envelope
Beispiel #7
0
    async def to_envelope(self, request: web.Request) -> Envelope:
        """
        Convert a webhook request object into an Envelope containing an HttpMessage (from the 'http' Protocol).

        :param request: the webhook request
        :return: The envelop representing the webhook request
        """

        payload_bytes = await request.read()
        version = str(request.version[0]) + "." + str(request.version[1])

        context = EnvelopeContext(uri=URI("aea/mail/base.py"))
        http_message = HttpMessage(
            performative=HttpMessage.Performative.REQUEST,
            method=request.method,
            url=str(request.url),
            version=version,
            headers=json.dumps(dict(request.headers)),
            bodyy=payload_bytes if payload_bytes is not None else b"",
        )
        envelope = Envelope(
            to=self.agent_address,
            sender=request.remote,
            protocol_id=PublicId.from_str("fetchai/http:0.1.0"),
            context=context,
            message=HttpSerializer().encode(http_message),
        )
        return envelope
Beispiel #8
0
    def _handle_get(self, http_msg: HttpMessage) -> None:
        """
        Handle a Http request of verb GET.

        :param http_msg: the http message
        :return: None
        """
        http_response = HttpMessage(
            dialogue_reference=http_msg.dialogue_reference,
            target=http_msg.message_id,
            message_id=http_msg.message_id + 1,
            performative=HttpMessage.Performative.RESPONSE,
            version=http_msg.version,
            status_code=200,
            status_text="Success",
            headers=http_msg.headers,
            bodyy=json.dumps({
                "tom": {
                    "type": "cat",
                    "age": 10
                }
            }).encode("utf-8"),
        )
        self.context.logger.info("[{}] responding with: {}".format(
            self.context.agent_name, http_response))
        self.context.outbox.put_message(
            sender=self.context.agent_address,
            to=http_msg.counterparty,
            protocol_id=http_response.protocol_id,
            message=HttpSerializer().encode(http_response),
        )
Beispiel #9
0
async def test_http_send():
    """Test the send functionality of the http client connection."""
    address = get_host()
    port = get_unused_tcp_port()
    agent_address = "some agent address"

    http_client_connection = HTTPClientConnection(
        address=agent_address,
        provider_address=address,
        provider_port=port,
    )
    http_client_connection.loop = asyncio.get_event_loop()

    request_http_message = HttpMessage(
        dialogue_reference=("", ""),
        target=0,
        message_id=1,
        performative=HttpMessage.Performative.REQUEST,
        method="",
        url="",
        headers="",
        version="",
        bodyy=b"",
    )
    request_envelope = Envelope(
        to="receiver",
        sender="sender",
        protocol_id=UNKNOWN_PROTOCOL_PUBLIC_ID,
        message=HttpSerializer().encode(request_http_message),
    )

    connection_response_mock = Mock()
    connection_response_mock.status_code = 200

    with mock.patch.object(requests,
                           "request",
                           return_value=connection_response_mock):
        await http_client_connection.connect()
        assert http_client_connection.connection_status.is_connected is True

    send_response_mock = Mock()
    send_response_mock.status_code = 200
    send_response_mock.headers = {"headers": "some header"}
    send_response_mock.reason = "OK"
    send_response_mock.content = b"Some content"

    with mock.patch.object(requests,
                           "request",
                           return_value=send_response_mock):
        await http_client_connection.send(envelope=request_envelope)
        # TODO: Consider returning the response from the server in order to be able to assert that the message send!
        assert True

    await http_client_connection.disconnect()
    assert http_client_connection.connection_status.is_connected is False
Beispiel #10
0
 def admin_get(self, path: str, content: Dict = None):
     # Request message & envelope
     request_http_message = HttpMessage(
         performative=HttpMessage.Performative.REQUEST,
         method="GET",
         url=self.admin_url + path,
         headers="",
         version="",
         bodyy=b""
         if content is None else json.dumps(content).encode("utf-8"),
     )
     self.context.outbox.put_message(
         to=self.admin_url,
         sender=self.context.agent_address,
         protocol_id=HTTP_PROTOCOL_PUBLIC_ID,
         message=HttpSerializer().encode(request_http_message),
     )
Beispiel #11
0
    def from_envelope(cls, envelope: Optional[Envelope] = None) -> "Response":
        """
        Turn an envelope into a response.

        :param envelope: the envelope
        :return: the response
        """
        if envelope is not None:
            http_message = cast(HttpMessage, HttpSerializer().decode(envelope.message))
            if http_message.performative == HttpMessage.Performative.RESPONSE:
                response = Response(
                    http_message.status_code,
                    http_message.status_text,
                    http_message.bodyy,
                )
            else:
                response = Response(SERVER_ERROR, "Server error")
        else:
            response = Response(REQUEST_TIMEOUT, "Request Timeout")
        return response
Beispiel #12
0
 def _admin_post(self, path: str, content: Dict = None):
     # Request message & envelope
     request_http_message = HttpMessage(
         performative=HttpMessage.Performative.REQUEST,
         method="POST",
         url=self.admin_url + path,
         headers="",
         version="",
         bodyy=b""
         if content is None else json.dumps(content).encode("utf-8"),
     )
     context = EnvelopeContext(
         connection_id=HTTP_CLIENT_CONNECTION_PUBLIC_ID)
     envelope = Envelope(
         to=self.admin_url,
         sender=self.context.agent_address,
         protocol_id=HTTP_PROTOCOL_PUBLIC_ID,
         context=context,
         message=HttpSerializer().encode(request_http_message),
     )
     self.context.outbox.put(envelope)
Beispiel #13
0
 async def test_send_connection_drop(self):
     """Test send connection error."""
     client_id = "to_key"
     message = HttpMessage(
         performative=HttpMessage.Performative.RESPONSE,
         dialogue_reference=("", ""),
         target=1,
         message_id=2,
         headers="",
         version="",
         status_code=200,
         status_text="Success",
         bodyy=b"",
     )
     envelope = Envelope(
         to=client_id,
         sender="from_key",
         protocol_id=self.protocol_id,
         message=HttpSerializer().encode(message),
     )
     await self.http_connection.send(envelope)
     # we expect the envelope to be dropped
     assert (self.http_connection.channel.dispatch_ready_envelopes.get(
         client_id) is None)
    async def test_end_to_end_aea_aca(self):
        # AEA components
        ledger_apis = LedgerApis({}, FetchAICrypto.identifier)
        wallet = Wallet({FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE})
        identity = Identity(
            name="my_aea_1",
            address=wallet.addresses.get(FetchAICrypto.identifier),
            default_address_key=FetchAICrypto.identifier,
        )
        http_client_connection = HTTPClientConnection(
            address=self.aea_address,
            provider_address=self.aca_admin_address,
            provider_port=self.aca_admin_port,
        )
        resources = Resources()

        # create AEA
        aea = AEA(identity, [http_client_connection], wallet, ledger_apis,
                  resources)

        # Add http protocol to AEA resources
        http_protocol_configuration = ProtocolConfig.from_json(
            yaml.safe_load(
                open(
                    os.path.join(
                        self.cwd,
                        "packages",
                        "fetchai",
                        "protocols",
                        "http",
                        "protocol.yaml",
                    ))))
        http_protocol = Protocol(http_protocol_configuration, HttpSerializer())
        resources.add_protocol(http_protocol)

        # Request message & envelope
        request_http_message = HttpMessage(
            dialogue_reference=("", ""),
            target=0,
            message_id=1,
            performative=HttpMessage.Performative.REQUEST,
            method="GET",
            url="http://{}:{}/status".format(self.aca_admin_address,
                                             self.aca_admin_port),
            headers="",
            version="",
            bodyy=b"",
        )
        request_envelope = Envelope(
            to="ACA",
            sender="AEA",
            protocol_id=HTTP_PROTOCOL_PUBLIC_ID,
            message=HttpSerializer().encode(request_http_message),
        )

        # add a simple skill with handler
        skill_context = SkillContext(aea.context)
        skill_config = SkillConfig(name="simple_skill",
                                   author="fetchai",
                                   version="0.1.0")
        aea_handler = AEAHandler(skill_context=skill_context,
                                 name="aea_handler")
        simple_skill = Skill(skill_config,
                             skill_context,
                             handlers={aea_handler.name: aea_handler})
        resources.add_skill(simple_skill)

        # add error skill to AEA
        error_skill = Skill.from_dir(os.path.join(AEA_DIR, "skills", "error"))
        resources.add_skill(error_skill)

        # start AEA thread
        t_aea = Thread(target=aea.start)
        try:
            t_aea.start()
            time.sleep(1.0)
            aea.outbox.put(request_envelope)
            time.sleep(5.0)
            assert (aea_handler.handled_message.performative ==
                    HttpMessage.Performative.RESPONSE)
            assert aea_handler.handled_message.version == ""
            assert aea_handler.handled_message.status_code == 200
            assert aea_handler.handled_message.status_text == "OK"
            assert aea_handler.handled_message.headers is not None
            assert aea_handler.handled_message.version is not None
        finally:
            aea.stop()
            t_aea.join()