def test_fipa_encoding_unknown_performative(): """Test that we raise an exception when the performative is unknown during encoding.""" msg = FIPAMessage(message_id=0, dialogue_reference=(str(0), ''), target=1, performative=FIPAMessage.Performative.ACCEPT) with pytest.raises(ValueError, match="Performative not valid:"): with mock.patch.object(FIPAMessage.Performative, "__eq__", return_value=False): FIPASerializer().encode(msg)
def test_performative_match_accept(): """Test the serialization - deserialization of the match_accept performative.""" msg = FIPAMessage(message_id=0, dialogue_reference=(str(0), ''), target=1, performative=FIPAMessage.Performative.MATCH_ACCEPT) msg_bytes = FIPASerializer().encode(msg) envelope = Envelope(to="receiver", sender="sender", protocol_id=FIPAMessage.protocol_id, message=msg_bytes) envelope_bytes = envelope.encode() actual_envelope = Envelope.decode(envelope_bytes) expected_envelope = envelope assert expected_envelope == actual_envelope deserialised_msg = FIPASerializer().decode(envelope.message) assert msg.get("performative") == deserialised_msg.get("performative")
def _on_propose(self, propose: FIPAMessage, dialogue: Dialogue) -> None: """ Handle a Propose. :param propose: the message containing the Propose :param dialogue: the dialogue :return: None """ new_msg_id = cast(int, propose.get("message_id")) + 1 strategy = cast(Strategy, self.context.strategy) proposals = cast(List[Description], propose.get("proposal")) logger.debug("[{}]: on Propose as {}.".format(self.context.agent_name, dialogue.role)) for num, proposal_description in enumerate(proposals): if num > 0: continue # TODO: allow for dialogue branching with multiple proposals transaction_msg = generate_transaction_message( proposal_description, dialogue.dialogue_label, dialogue.is_seller, self.context.agent_public_key) if strategy.is_profitable_transaction( transaction_msg, is_seller=dialogue.is_seller): logger.info("[{}]: Accepting propose (as {}).".format( self.context.agent_name, dialogue.role)) transactions = cast(Transactions, self.context.transactions) transactions.add_locked_tx(transaction_msg, as_seller=dialogue.is_seller) transactions.add_pending_initial_acceptance( dialogue.dialogue_label, new_msg_id, transaction_msg) fipa_msg = FIPAMessage( performative=FIPAMessage.Performative.ACCEPT, message_id=new_msg_id, dialogue_reference=dialogue.dialogue_label. dialogue_reference, target=propose.get("message_id")) else: logger.info("[{}]: Declining propose (as {})".format( self.context.agent_name, dialogue.role)) fipa_msg = FIPAMessage( performative=FIPAMessage.Performative.DECLINE, message_id=new_msg_id, dialogue_reference=dialogue.dialogue_label. dialogue_reference, target=propose.get("message_id")) dialogues = cast(Dialogues, self.context.dialogues) dialogues.dialogue_stats.add_dialogue_endstate( Dialogue.EndState.DECLINED_PROPOSE, dialogue.is_self_initiated) dialogue.outgoing_extend(fipa_msg) self.context.outbox.put_message( to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=FIPASerializer().encode(fipa_msg))
def _on_services_search_result(self, agent_pbks: List[str], is_searching_for_sellers: bool) -> None: """ Process the search result for services. :param agent_pbks: the agent public keys matching the search query :param is_searching_for_sellers: whether it is searching for sellers or not :return: None """ agent_pbks_set = set(agent_pbks) if self.crypto.public_key in agent_pbks_set: agent_pbks_set.remove(self.crypto.public_key) agent_pbks = list(agent_pbks_set) searched_for = "sellers" if is_searching_for_sellers else "buyers" logger.debug("[{}]: Found potential {}: {}".format( self.agent_name, searched_for, agent_pbks)) services = self.game_instance.build_services_dict( is_supply=not is_searching_for_sellers) if services is None: response = "demanding" if is_searching_for_sellers else "supplying" logger.debug("[{}]: No longer {} any goods...".format( self.agent_name, response)) return for agent_pbk in agent_pbks: dialogue = self.game_instance.dialogues.create_self_initiated( agent_pbk, self.crypto.public_key, not is_searching_for_sellers) cfp = FIPAMessage( message_id=STARTING_MESSAGE_ID, dialogue_id=dialogue.dialogue_label.dialogue_id, target=STARTING_MESSAGE_TARGET, performative=FIPAMessage.Performative.CFP, query=json.dumps(services).encode("utf-8"), ) dialogue.outgoing_extend([cfp]) cfp_bytes = FIPASerializer().encode(cfp) logger.debug( "[{}]: send_cfp_as_{}: msg_id={}, dialogue_id={}, destination={}, target={}, services={}" .format( self.agent_name, dialogue.role, cfp.get("id"), cfp.get("dialogue_id"), agent_pbk, cfp.get("target"), services, )) self.mailbox.outbox.put_message( to=agent_pbk, sender=self.crypto.public_key, protocol_id=FIPAMessage.protocol_id, message=cfp_bytes, )
def test_performative_inform(): """Test the serialization-deserialization of the inform performative.""" msg = FIPAMessage(message_id=0, dialogue_reference=(str(0), ''), target=1, performative=FIPAMessage.Performative.INFORM, json_data={"foo": "bar"}) msg_bytes = FIPASerializer().encode(msg) envelope = Envelope(to="receiver", sender="sender", protocol_id=FIPAMessage.protocol_id, message=msg_bytes) envelope_bytes = envelope.encode() actual_envelope = Envelope.decode(envelope_bytes) expected_envelope = envelope assert expected_envelope == actual_envelope deserialised_msg = FIPASerializer().decode(envelope.message) assert msg.get("performative") == deserialised_msg.get("performative")
def test_fipa_accept_serialization(): """Test that the serialization for the 'fipa' protocol works.""" msg = FIPAMessage(message_id=0, dialogue_reference=(str(0), ''), target=0, performative=FIPAMessage.Performative.ACCEPT) msg_bytes = FIPASerializer().encode(msg) envelope = Envelope(to="receiver", sender="sender", protocol_id=FIPAMessage.protocol_id, message=msg_bytes) envelope_bytes = envelope.encode() actual_envelope = Envelope.decode(envelope_bytes) expected_envelope = envelope assert expected_envelope == actual_envelope actual_msg = FIPASerializer().decode(actual_envelope.message) expected_msg = msg assert expected_msg == actual_msg
def test_error_handler_handle(self): """Test the handle function.""" msg = FIPAMessage(message_id=0, dialogue_reference=(str(0), ''), target=0, performative=FIPAMessage.Performative.ACCEPT) msg_bytes = FIPASerializer().encode(msg) envelope = Envelope(to=self.public_key, sender=self.public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) self.my_error_handler.handle(message=msg, sender=envelope.sender)
async def test_messages(self): """Test that at the beginning, the search request returns an empty search result.""" msg = FIPAMessage((str(0), ''), 0, 0, FIPAMessage.Performative.CFP, query=None) msg_bytes = FIPASerializer().encode(msg) envelope = Envelope(to=DEFAULT_OEF, sender=self.public_key_1, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) with pytest.raises(AEAConnectionError): await OEFLocalConnection(self.public_key_1, self.node).send(envelope) self.multiplexer1.connect() msg = FIPAMessage((str(0), str(1)), 0, 0, FIPAMessage.Performative.CFP, query=None) msg_bytes = FIPASerializer().encode(msg) envelope = Envelope(to="this_public_key_does_not_exist", sender=self.public_key_1, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) self.multiplexer1.put(envelope) # check the result response_envelope = self.multiplexer1.get(block=True, timeout=5.0) assert response_envelope.protocol_id == OEFMessage.protocol_id assert response_envelope.sender == DEFAULT_OEF result = OEFSerializer().decode(response_envelope.message) assert result.get("type") == OEFMessage.Type.DIALOGUE_ERROR
def handle_envelope(self, envelope: Envelope) -> None: """ Implement the reaction to an envelope. :param envelope: the envelope :return: None """ msg = FIPASerializer().decode(envelope.message) msg_performative = FIPAMessage.Performative(msg.get('performative')) proposals = cast(List[Description], msg.get("proposal")) message_id = cast(int, msg.get("id")) dialogue_id = cast(int, msg.get("dialogue_id")) if msg_performative == FIPAMessage.Performative.PROPOSE: if proposals is not []: for item in proposals: logger.info( "[{}]: received proposal={} in dialogue={}".format( self.context.agent_name, item.values, dialogue_id)) if "Price" in item.values.keys(): if item.values["Price"] < self.max_price: self.handle_accept(envelope.sender, message_id, dialogue_id) else: self.handle_decline(envelope.sender, message_id, dialogue_id)
def handle_dialogue_message(self, envelope: Envelope) -> None: """ Handle messages from the other agents. The agents expect a response. :param envelope: the envelope. :return: None """ message = FIPASerializer().decode(envelope.message) # type: Message logger.debug("Handling Dialogue message. type={}".format( type(message.get("performative")))) if self.dialogues.is_belonging_to_registered_dialogue( message, self.crypto.public_key, envelope.sender): self.on_existing_dialogue(message, envelope.sender) elif self.dialogues.is_permitted_for_new_dialogue( message, self.game_instance.game_configuration.agent_pbks, envelope.sender): self.on_new_dialogue(message, envelope.sender) else: self.on_unidentified_dialogue(message, envelope.sender)
def test_fipa_cfp_serialization(): """Test that the serialization for the 'fipa' protocol works.""" query = Query(Constraint('something', ConstraintType('>', 1))) msg = FIPAMessage(message_id=0, dialogue_id=0, target=0, performative=FIPAMessage.Performative.CFP, query=query) msg_bytes = FIPASerializer().encode(msg) envelope = Envelope(to="receiver", sender="sender", protocol_id=FIPAMessage.protocol_id, message=msg_bytes) envelope_bytes = envelope.encode() actual_envelope = Envelope.decode(envelope_bytes) expected_envelope = envelope assert expected_envelope == actual_envelope actual_msg = FIPASerializer().decode(actual_envelope.message) expected_msg = msg assert expected_msg == actual_msg
def test_handle(): """Tests handle method of an agent.""" node = LocalNode() agent_name = "MyAgent" private_key_pem_path = os.path.join(CUR_PATH, "data", "priv.pem") crypto = Crypto(private_key_pem_path=private_key_pem_path) public_key = crypto.public_key mailbox = MailBox(OEFLocalConnection(public_key, node)) msg = DefaultMessage(type=DefaultMessage.Type.BYTES, content=b"hello") message_bytes = DefaultSerializer().encode(msg) envelope = Envelope(to="Agent1", sender=public_key, protocol_id="unknown_protocol", message=message_bytes) agent = AEA(agent_name, mailbox, private_key_pem_path=private_key_pem_path, directory=str(Path(CUR_PATH, "data", "dummy_aea"))) t = Thread(target=agent.start) try: t.start() agent.mailbox.inbox._queue.put(envelope) env = agent.mailbox.outbox._queue.get(block=True, timeout=5.0) assert env.protocol_id == "default", \ "The envelope is not the expected protocol (Unsupported protocol)" # DECODING ERROR msg = "hello".encode("utf-8") envelope = Envelope(to=public_key, sender=public_key, protocol_id='default', message=msg) agent.mailbox.inbox._queue.put(envelope) # UNSUPPORTED SKILL msg = FIPASerializer().encode( FIPAMessage(performative=FIPAMessage.Performative.ACCEPT, message_id=0, dialogue_id=0, destination=public_key, target=1)) envelope = Envelope(to=public_key, sender=public_key, protocol_id="fipa", message=msg) agent.mailbox.inbox._queue.put(envelope) finally: agent.stop() t.join()
def handle_envelope(self, envelope: Envelope) -> None: """ Dispatch envelope to relevant handler and respond. :param envelope: the envelope :return: None """ fipa_msg = FIPASerializer().decode(envelope.message) fipa_msg = cast(FIPAMessage, fipa_msg) fipa_msg_performative = fipa_msg.get("performative") # FIPAMessage.Performative(fipa_msg.get("performative")) logger.debug("[{}]: Identifying dialogue of FIPAMessage={}".format(self.context.agent_name, fipa_msg)) dialogues = cast(Dialogues, self.context.dialogues) if dialogues.is_belonging_to_registered_dialogue(fipa_msg, envelope.sender, self.context.agent_public_key): dialogue = dialogues.get_dialogue(fipa_msg, envelope.sender, self.context.agent_public_key) dialogue.incoming_extend(fipa_msg) elif dialogues.is_permitted_for_new_dialogue(fipa_msg, envelope.sender): dialogue = dialogues.create_opponent_initiated(fipa_msg, envelope.sender) dialogue.incoming_extend(fipa_msg) else: logger.debug("[{}]: Unidentified dialogue.".format(self.context.agent_name)) default_msg = DefaultMessage(type=DefaultMessage.Type.BYTES, content=b'This message belongs to an unidentified dialogue.') msg_bytes = DefaultSerializer().encode(default_msg) self.context.outbox.put_message(to=envelope.sender, sender=self.context.agent_public_key, protocol_id=DefaultMessage.protocol_id, message=msg_bytes) return logger.debug("[{}]: Handling FIPAMessage of performative={}".format(self.context.agent_name, fipa_msg_performative)) fipa_msg = cast(FIPAMessage, fipa_msg) if fipa_msg_performative == FIPAMessage.Performative.CFP: self._on_cfp(fipa_msg, dialogue) elif fipa_msg_performative == FIPAMessage.Performative.PROPOSE: self._on_propose(fipa_msg, dialogue) elif fipa_msg_performative == FIPAMessage.Performative.DECLINE: self._on_decline(fipa_msg, dialogue) elif fipa_msg_performative == FIPAMessage.Performative.ACCEPT: self._on_accept(fipa_msg, dialogue) elif fipa_msg_performative == FIPAMessage.Performative.MATCH_ACCEPT: self._on_match_accept(fipa_msg, dialogue)
def _on_accept(self, accept: FIPAMessage, dialogue: Dialogue) -> None: """ Handle an Accept. :param accept: the Accept message :param dialogue: the dialogue :return: None """ transactions = cast(Transactions, self.context.transactions) assert dialogue.dialogue_label in transactions.pending_proposals \ and accept.get("target") in transactions.pending_proposals[dialogue.dialogue_label] logger.debug("[{}]: on_accept: msg_id={}, dialogue_id={}, origin={}, target={}" .format(self.context.agent_name, accept.get("id"), accept.get("dialogue_id"), dialogue.dialogue_label.dialogue_opponent_pbk, accept.get("target"))) new_msg_id = cast(int, accept.get("id")) + 1 transaction_msg = transactions.pop_pending_proposal(dialogue.dialogue_label, cast(int, accept.get("target"))) strategy = cast(Strategy, self.context.strategy) ownership_state_after_locks = transactions.ownership_state_after_locks(self.context.ownership_state, is_seller=dialogue.is_seller) if strategy.is_profitable_transaction(self.context.preferences, ownership_state_after_locks, transaction_msg): if strategy.is_world_modeling: pass # TODO # strategy.world_state.update_on_initial_accept(transaction_msg) logger.debug("[{}]: Locking the current state (as {}).".format(self.context.agent_name, dialogue.role)) transactions.add_locked_tx(transaction_msg, as_seller=dialogue.is_seller) self.context.decision_maker_message_queue.put(transaction_msg) msg = FIPAMessage(message_id=new_msg_id, dialogue_id=accept.get("dialogue_id"), target=accept.get("id"), performative=FIPAMessage.Performative.MATCH_ACCEPT) dialogue.outgoing_extend(msg) msg_bytes = FIPASerializer().encode(msg) result = Envelope(to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) else: logger.debug("[{}]: Decline the accept (as {}).".format(self.context.agent_name, dialogue.role)) msg = FIPAMessage(message_id=new_msg_id, dialogue_id=accept.get("dialogue_id"), target=accept.get("id"), performative=FIPAMessage.Performative.DECLINE) dialogue.outgoing_extend(msg) msg_bytes = FIPASerializer().encode(msg) result = Envelope(to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) dialogues = cast(Dialogues, self.context.dialogues) dialogues.dialogue_stats.add_dialogue_endstate(Dialogue.EndState.DECLINED_ACCEPT, dialogue.is_self_initiated) self.context.outbox.put(result)
def _on_accept(self, accept: FIPAMessage, dialogue: Dialogue) -> None: """ Handle an Accept. :param accept: the Accept message :param dialogue: the dialogue :return: None """ logger.debug( "[{}]: on_accept: msg_id={}, dialogue_id={}, origin={}, target={}". format(self.context.agent_name, accept.get("message_id"), accept.get("dialogue_id"), dialogue.dialogue_label.dialogue_opponent_pbk, accept.get("target"))) new_msg_id = cast(int, accept.get("message_id")) + 1 transactions = cast(Transactions, self.context.transactions) transaction_msg = transactions.pop_pending_proposal( dialogue.dialogue_label, cast(int, accept.get("target"))) strategy = cast(Strategy, self.context.strategy) if strategy.is_profitable_transaction(transaction_msg, is_seller=dialogue.is_seller): logger.info("[{}]: locking the current state (as {}).".format( self.context.agent_name, dialogue.role)) transactions.add_locked_tx(transaction_msg, as_seller=dialogue.is_seller) self.context.decision_maker_message_queue.put(transaction_msg) else: logger.debug("[{}]: decline the Accept (as {}).".format( self.context.agent_name, dialogue.role)) fipa_msg = FIPAMessage( performative=FIPAMessage.Performative.DECLINE, message_id=new_msg_id, dialogue_reference=dialogue.dialogue_label.dialogue_reference, target=accept.get("message_id"), ) dialogue.outgoing_extend(fipa_msg) dialogues = cast(Dialogues, self.context.dialogues) dialogues.dialogue_stats.add_dialogue_endstate( Dialogue.EndState.DECLINED_ACCEPT, dialogue.is_self_initiated) self.context.outbox.put_message( to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=FIPASerializer().encode(fipa_msg))
def handle(self, message: Message, sender: str) -> None: """ Implement the reaction to a message. :param message: the message :param sender: the sender :return: None """ tx_msg_response = cast(TransactionMessage, message) if tx_msg_response is not None and \ TransactionMessage.Performative(tx_msg_response.get("performative")) == TransactionMessage.Performative.ACCEPT: logger.info("[{}]: transaction was successful.".format( self.context.agent_name)) json_data = { 'transaction_digest': tx_msg_response.get("transaction_digest") } dialogue_label = DialogueLabel.from_json( cast(Dict[str, str], tx_msg_response.get("dialogue_label"))) dialogues = cast(Dialogues, self.context.dialogues) dialogue = dialogues.dialogues[dialogue_label] fipa_msg = cast(FIPAMessage, dialogue.last_incoming_message) new_message_id = cast(int, fipa_msg.get("message_id")) + 1 new_target_id = cast(int, fipa_msg.get("target")) + 1 counterparty_pbk = dialogue.dialogue_label.dialogue_opponent_pbk inform_msg = FIPAMessage( message_id=new_message_id, dialogue_reference=dialogue.dialogue_label.dialogue_reference, target=new_target_id, performative=FIPAMessage.Performative.INFORM, json_data=json_data) dialogue.outgoing_extend(inform_msg) self.context.outbox.put_message( to=counterparty_pbk, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=FIPASerializer().encode(inform_msg)) logger.info( "[{}]: informing counterparty={} of transaction digest.". format(self.context.agent_name, counterparty_pbk[-5:])) self._received_tx_message = True else: logger.info("[{}]: transaction was not successful.".format( self.context.agent_name))
def test_error_invalid_message(self): """Test the invalid message.""" msg = FIPAMessage(message_id=0, dialogue_reference=(str(0), ''), target=0, performative=FIPAMessage.Performative.ACCEPT) msg_bytes = FIPASerializer().encode(msg) envelope = Envelope(to=self.public_key, sender=self.public_key, protocol_id=OEFMessage.protocol_id, message=msg_bytes) self.my_error_handler.send_invalid_message(envelope) envelope = self.my_aea.inbox.get(block=True, timeout=1.0) msg = DefaultSerializer().decode(envelope.message) assert msg.get("type") == DefaultMessage.Type.ERROR assert msg.get( "error_code") == DefaultMessage.ErrorCode.INVALID_MESSAGE.value
def test_error_skill_unsupported_protocol(self): """Test the unsupported error message.""" msg = FIPAMessage(message_id=0, dialogue_reference=(str(0), ''), target=0, performative=FIPAMessage.Performative.ACCEPT) msg_bytes = FIPASerializer().encode(msg) envelope = Envelope(to=self.public_key, sender=self.public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) self.my_error_handler.send_unsupported_protocol(envelope) envelope = self.my_aea.inbox.get(block=True, timeout=1.0) msg = DefaultSerializer().decode(envelope.message) assert msg.get("type") == DefaultMessage.Type.ERROR assert msg.get("error_code" ) == DefaultMessage.ErrorCode.UNSUPPORTED_PROTOCOL.value
def handle(self, message: Message, sender: str) -> None: """ Dispatch message to relevant handler and respond. :param message: the message :param sender: the sender :return: None """ tx_message = cast(TransactionMessage, message) if TransactionMessage.Performative(tx_message.get( "performative")) == TransactionMessage.Performative.ACCEPT: logger.info( "[{}]: transaction confirmed by decision maker, sending match accept." .format(self.context.agent_name)) dialogue_label = DialogueLabel.from_json( cast(Dict[str, str], tx_message.get("dialogue_label"))) dialogues = cast(Dialogues, self.context.dialogues) dialogue = dialogues.dialogues[dialogue_label] tac_message = dialogue.last_incoming_message if tac_message is not None and tac_message.get( "performative") == FIPAMessage.Performative.ACCEPT: fipa_msg = FIPAMessage( performative=FIPAMessage.Performative. MATCH_ACCEPT_W_ADDRESS, message_id=cast(int, tac_message.get("message_id")) + 1, dialogue_reference=dialogue.dialogue_label. dialogue_reference, target=tac_message.get("message_id"), address=tx_message.get("transaction_digest")) dialogue.outgoing_extend(fipa_msg) self.context.outbox.put_message( to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=FIPASerializer().encode(fipa_msg)) else: logger.info( "[{}]: last message should be of performative accept.". format(self.context.agent_name)) else: logger.info("[{}]: transaction was not successful.".format( self.context.agent_name))
def _handle_search(self, agents: List[str], search_id: int, is_searching_for_sellers: bool) -> None: """ Handle the search response. :param agents: the agents returned by the search :param is_searching_for_sellers: whether the agent is searching for sellers :return: None """ searched_for = 'sellers' if is_searching_for_sellers else 'buyers' if len(agents) > 0: logger.info( "[{}]: found potential {} agents={} on search_id={}.".format( self.context.agent_name, searched_for, list(map(lambda x: x[-5:], agents)), search_id)) strategy = cast(Strategy, self.context.strategy) dialogues = cast(Dialogues, self.context.dialogues) query = strategy.get_own_services_query(is_searching_for_sellers) for opponent_pbk in agents: dialogue = dialogues.create_self_initiated( opponent_pbk, self.context.agent_public_key, not is_searching_for_sellers) logger.info("[{}]: sending CFP to agent={}".format( self.context.agent_name, opponent_pbk[-5:])) fipa_msg = FIPAMessage( message_id=FIPAMessage.STARTING_MESSAGE_ID, dialogue_reference=dialogue.dialogue_label. dialogue_reference, performative=FIPAMessage.Performative.CFP, target=FIPAMessage.STARTING_TARGET, query=query) dialogue.outgoing_extend(fipa_msg) self.context.outbox.put_message( to=opponent_pbk, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=FIPASerializer().encode(fipa_msg)) else: logger.info( "[{}]: found no {} agents on search_id={}, continue searching." .format(self.context.agent_name, searched_for, search_id))
def handle_accept(self, sender: str, message_id: int, dialogue_id: int): """ Handle sending accept message. :param sender: the sender of the message :param message_id: the message id :param dialogue_id: the dialogue id """ new_message_id = message_id + 1 new_target_id = message_id logger.info("[{}]: accepting the proposal from sender={}".format( self.context.agent_name, sender)) msg = FIPAMessage(message_id=new_message_id, dialogue_id=dialogue_id, target=new_target_id, performative=FIPAMessage.Performative.ACCEPT) self.context.outbox.put_message(to=sender, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=FIPASerializer().encode(msg))
def on_decline(self, msg_id: int, dialogue_id: int, origin: str, target: int) -> None: """ On decline event handler. :param msg_id: the message id. :param dialogue_id: the dialogue id. :param origin: the public key of the sender. :param target: the message target. :return: None """ msg = FIPAMessage(message_id=msg_id, dialogue_id=dialogue_id, target=target, performative=FIPAMessage.Performative.DECLINE) msg_bytes = FIPASerializer().encode(msg) envelope = Envelope(to=self.public_key, sender=origin, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) self.in_queue.put(envelope)
def on_accept(self, msg_id: int, dialogue_id: int, origin: str, target: int) -> None: """ On accept event handler. :param msg_id: the message id. :param dialogue_id: the dialogue id. :param origin: the public key of the sender. :param target: the message target. :return: None """ performative = FIPAMessage.Performative.MATCH_ACCEPT if msg_id == 4 and target == 3 else FIPAMessage.Performative.ACCEPT msg = FIPAMessage(message_id=msg_id, dialogue_id=dialogue_id, target=target, performative=performative) msg_bytes = FIPASerializer().encode(msg) envelope = Envelope(to=self.public_key, sender=origin, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) self.in_queue.put(envelope)
def _handle_search(self, agents: List[str]) -> None: """ Handle the search response. :param agents: the agents returned by the search :return: None """ strategy = cast(Strategy, self.context.strategy) if len(agents) > 0: strategy.on_search_success() logger.info("[{}]: found agents={}, stopping search.".format( self.context.agent_name, list(map(lambda x: x[-5:], agents)))) # pick first agent found opponent_pbk = agents[0] dialogues = cast(Dialogues, self.context.dialogues) dialogue = dialogues.create_self_initiated( opponent_pbk, self.context.agent_public_key, is_seller=False) query = strategy.get_service_query() logger.info("[{}]: sending CFP to agent={}".format( self.context.agent_name, opponent_pbk[-5:])) cfp_msg = FIPAMessage( message_id=STARTING_MESSAGE_ID, dialogue_reference=dialogue.dialogue_label.dialogue_reference, performative=FIPAMessage.Performative.CFP, target=STARTING_TARGET_ID, query=query) dialogue.outgoing_extend(cfp_msg) self.context.outbox.put_message( to=opponent_pbk, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=FIPASerializer().encode(cfp_msg)) else: logger.info("[{}]: found no agents, continue searching.".format( self.context.agent_name)) strategy.on_search_failed()
def _handle_inform(self, msg: FIPAMessage, sender: str, message_id: int, dialogue: Dialogue) -> None: """ Handle the INFORM. If the INFORM message contains the transaction_digest then verify that it is settled, otherwise do nothing. If the transaction is settled send the weather data, otherwise do nothing. :param msg: the message :param sender: the sender :param message_id: the message id :param dialogue: the dialogue object :return: None """ new_message_id = message_id + 1 new_target = message_id logger.info("[{}]: received INFORM from sender={}".format( self.context.agent_name, sender[-5:])) json_data = cast(dict, msg.get("json_data")) if "Done" in json_data: inform_msg = FIPAMessage( message_id=new_message_id, dialogue_reference=dialogue.dialogue_label.dialogue_reference, target=new_target, performative=FIPAMessage.Performative.INFORM, json_data=dialogue.weather_data) dialogue.outgoing_extend(inform_msg) # import pdb; pdb.set_trace() self.context.outbox.put_message( to=sender, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=FIPASerializer().encode(inform_msg)) # dialogues = cast(Dialogues, self.context.dialogues) # dialogues.dialogue_stats.add_dialogue_endstate(Dialogue.EndState.SUCCESSFUL) else: logger.warning("I didn't receive the transaction digest!")
def on_cfp(self, msg_id: int, dialogue_id: int, origin: str, target: int, query: CFP_TYPES) -> None: """ On cfp event handler. :param msg_id: the message id. :param dialogue_id: the dialogue id. :param origin: the public key of the sender. :param target: the message target. :param query: the query. :return: None """ msg = FIPAMessage(message_id=msg_id, dialogue_id=dialogue_id, target=target, performative=FIPAMessage.Performative.CFP, query=query if query != b"" else None) msg_bytes = FIPASerializer().encode(msg) envelope = Envelope(to=self.public_key, sender=origin, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) self.in_queue.put(envelope)
def test_communication(): """Test that two multiplexer can communicate through the node.""" with LocalNode() as node: multiplexer1 = Multiplexer([OEFLocalConnection("multiplexer1", node)]) multiplexer2 = Multiplexer([OEFLocalConnection("multiplexer2", node)]) multiplexer1.connect() multiplexer2.connect() msg = DefaultMessage(type=DefaultMessage.Type.BYTES, content=b"hello") msg_bytes = DefaultSerializer().encode(msg) envelope = Envelope(to="multiplexer2", sender="multiplexer1", protocol_id=DefaultMessage.protocol_id, message=msg_bytes) multiplexer1.put(envelope) msg = FIPAMessage((str(0), ''), 0, 0, FIPAMessage.Performative.CFP, query=None) msg_bytes = FIPASerializer().encode(msg) envelope = Envelope(to="multiplexer2", sender="multiplexer1", protocol_id=FIPAMessage.protocol_id, message=msg_bytes) multiplexer1.put(envelope) msg = FIPAMessage((str(0), str(1)), 0, 0, FIPAMessage.Performative.PROPOSE, proposal=[]) msg_bytes = FIPASerializer().encode(msg) envelope = Envelope(to="multiplexer2", sender="multiplexer1", protocol_id=FIPAMessage.protocol_id, message=msg_bytes) multiplexer1.put(envelope) msg = FIPAMessage((str(0), str(1)), 0, 0, FIPAMessage.Performative.ACCEPT) msg_bytes = FIPASerializer().encode(msg) envelope = Envelope(to="multiplexer2", sender="multiplexer1", protocol_id=FIPAMessage.protocol_id, message=msg_bytes) multiplexer1.put(envelope) msg = FIPAMessage((str(0), str(1)), 0, 0, FIPAMessage.Performative.DECLINE) msg_bytes = FIPASerializer().encode(msg) envelope = Envelope(to="multiplexer2", sender="multiplexer1", protocol_id=FIPAMessage.protocol_id, message=msg_bytes) multiplexer1.put(envelope) envelope = multiplexer2.get(block=True, timeout=1.0) msg = DefaultSerializer().decode(envelope.message) assert envelope.protocol_id == "default" assert msg.get("content") == b"hello" envelope = multiplexer2.get(block=True, timeout=1.0) msg = FIPASerializer().decode(envelope.message) assert envelope.protocol_id == "fipa" assert msg.get("performative") == FIPAMessage.Performative.CFP envelope = multiplexer2.get(block=True, timeout=1.0) msg = FIPASerializer().decode(envelope.message) assert envelope.protocol_id == "fipa" assert msg.get("performative") == FIPAMessage.Performative.PROPOSE envelope = multiplexer2.get(block=True, timeout=1.0) msg = FIPASerializer().decode(envelope.message) assert envelope.protocol_id == "fipa" assert msg.get("performative") == FIPAMessage.Performative.ACCEPT envelope = multiplexer2.get(block=True, timeout=1.0) msg = FIPASerializer().decode(envelope.message) assert envelope.protocol_id == "fipa" assert msg.get("performative") == FIPAMessage.Performative.DECLINE multiplexer1.disconnect() multiplexer2.disconnect()
def on_cfp(self, cfp: Message, dialogue: Dialogue) -> Envelope: """ Handle a CFP. :param cfp: the message containing the CFP :param dialogue: the dialogue :return: a Propose or a Decline """ assert cfp.get("performative") == FIPAMessage.Performative.CFP goods_description = self.game_instance.get_service_description( is_supply=dialogue.is_seller) new_msg_id = cfp.get("id") + 1 decline = False cfp_services = json.loads(cfp.get("query").decode('utf-8')) if not self.game_instance.is_matching(cfp_services, goods_description): decline = True logger.debug( "[{}]: Current holdings do not satisfy CFP query.".format( self.agent_name)) else: proposal = self.game_instance.generate_proposal( cfp_services, dialogue.is_seller) if proposal is None: decline = True logger.debug( "[{}]: Current strategy does not generate proposal that satisfies CFP query." .format(self.agent_name)) if decline: logger.debug("[{}]: sending to {} a Decline{}".format( self.agent_name, dialogue.dialogue_label.dialogue_opponent_pbk, pprint.pformat({ "msg_id": new_msg_id, "dialogue_id": cfp.get("dialogue_id"), "origin": dialogue.dialogue_label.dialogue_opponent_pbk, "target": cfp.get("target") }))) msg = FIPAMessage(message_id=new_msg_id, dialogue_id=cfp.get("dialogue_id"), performative=FIPAMessage.Performative.DECLINE, target=cfp.get("id")) dialogue.outgoing_extend([msg]) msg_bytes = FIPASerializer().encode(msg) response = Envelope( to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.crypto.public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) self.game_instance.stats_manager.add_dialogue_endstate( EndState.DECLINED_CFP, dialogue.is_self_initiated) else: proposal = cast(Description, proposal) transaction_id = generate_transaction_id( self.crypto.public_key, dialogue.dialogue_label.dialogue_opponent_pbk, dialogue.dialogue_label, dialogue.is_seller) transaction = Transaction.from_proposal( proposal=proposal, transaction_id=transaction_id, is_sender_buyer=not dialogue.is_seller, counterparty=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.crypto.public_key) self.game_instance.transaction_manager.add_pending_proposal( dialogue.dialogue_label, new_msg_id, transaction) logger.debug("[{}]: sending to {} a Propose{}".format( self.agent_name, dialogue.dialogue_label.dialogue_opponent_pbk, pprint.pformat({ "msg_id": new_msg_id, "dialogue_id": cfp.get("dialogue_id"), "origin": dialogue.dialogue_label.dialogue_opponent_pbk, "target": cfp.get("id"), "propose": proposal.values }))) msg = FIPAMessage(performative=FIPAMessage.Performative.PROPOSE, message_id=new_msg_id, dialogue_id=cfp.get("dialogue_id"), target=cfp.get("id"), proposal=[proposal]) dialogue.outgoing_extend([msg]) dialogue.outgoing_extend([msg]) msg_bytes = FIPASerializer().encode(msg) response = Envelope( to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.crypto.public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) return response
def on_accept(self, accept: Message, dialogue: Dialogue) -> List[Envelope]: """ Handle an Accept. :param accept: the message containing the Accept :param dialogue: the dialogue :return: a Decline, or an Accept and a Transaction, or a Transaction (in a Message object) """ assert accept.get("performative") == FIPAMessage.Performative.ACCEPT \ and dialogue.dialogue_label in self.game_instance.transaction_manager.pending_proposals \ and accept.get("target") in self.game_instance.transaction_manager.pending_proposals[dialogue.dialogue_label] logger.debug( "[{}]: on_accept: msg_id={}, dialogue_id={}, origin={}, target={}". format(self.agent_name, accept.get("id"), accept.get("dialogue_id"), dialogue.dialogue_label.dialogue_opponent_pbk, accept.get("target"))) new_msg_id = accept.get("id") + 1 results = [] transaction = self.game_instance.transaction_manager.pop_pending_proposal( dialogue.dialogue_label, accept.get("target")) is_profitable_transaction, accept_log_msg = self.game_instance.is_profitable_transaction( transaction, dialogue) logger.debug(accept_log_msg) if is_profitable_transaction: if self.game_instance.strategy.is_world_modeling: self.game_instance.world_state.update_on_initial_accept( transaction) logger.debug("[{}]: Locking the current state (as {}).".format( self.agent_name, dialogue.role)) self.game_instance.transaction_manager.add_locked_tx( transaction, as_seller=dialogue.is_seller) tac_msg = TACMessage( tac_type=TACMessage.Type.TRANSACTION, transaction_id=transaction.transaction_id, is_sender_buyer=transaction.is_sender_buyer, counterparty=transaction.counterparty, amount=transaction.amount, quantities_by_good_pbk=transaction.quantities_by_good_pbk) dialogue.outgoing_extend([tac_msg]) tac_bytes = TACSerializer().encode(tac_msg) results.append( Envelope(to=self.game_instance.controller_pbk, sender=self.crypto.public_key, protocol_id=TACMessage.protocol_id, message=tac_bytes)) msg = FIPAMessage( message_id=new_msg_id, dialogue_id=accept.get("dialogue_id"), target=accept.get("id"), performative=FIPAMessage.Performative.MATCH_ACCEPT) dialogue.outgoing_extend([msg]) msg_bytes = FIPASerializer().encode(msg) results.append( Envelope(to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.crypto.public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes)) else: logger.debug("[{}]: Decline the accept (as {}).".format( self.agent_name, dialogue.role)) msg = FIPAMessage(message_id=new_msg_id, dialogue_id=accept.get("dialogue_id"), target=accept.get("id"), performative=FIPAMessage.Performative.DECLINE) dialogue.outgoing_extend([msg]) msg_bytes = FIPASerializer().encode(msg) results.append( Envelope(to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.crypto.public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes)) self.game_instance.stats_manager.add_dialogue_endstate( EndState.DECLINED_ACCEPT, dialogue.is_self_initiated) return results
def _on_cfp(self, cfp: FIPAMessage, dialogue: Dialogue) -> None: """ Handle a CFP. :param cfp: the fipa message containing the CFP :param dialogue: the dialogue :return: None """ strategy = cast(Strategy, self.context.strategy) transactions = cast(Transactions, self.context.transactions) ownership_state_after_locks = transactions.ownership_state_after_locks(self.context.ownership_state, is_seller=dialogue.is_seller) own_service_description = strategy.get_own_service_description(ownership_state_after_locks, is_supply=dialogue.is_seller) new_msg_id = cast(int, cfp.get("id")) + 1 cfp_query = cfp.get("query") cfp_query = cast(Query, cfp_query) decline = False if not cfp_query.check(own_service_description): decline = True logger.debug("[{}]: Current holdings do not satisfy CFP query.".format(self.context.agent_name)) else: proposal_description = strategy.get_proposal_for_query(cfp_query, self.context.preferences, ownership_state_after_locks, is_seller=dialogue.is_seller, tx_fee=1.0) if proposal_description is None: decline = True logger.debug("[{}]: Current strategy does not generate proposal that satisfies CFP query.".format(self.context.agent_name)) if decline: logger.debug("[{}]: sending to {} a Decline{}".format(self.context.agent_name, dialogue.dialogue_label.dialogue_opponent_pbk, pprint.pformat({ "msg_id": new_msg_id, "dialogue_id": cfp.get("dialogue_id"), "origin": dialogue.dialogue_label.dialogue_opponent_pbk, "target": cfp.get("target") }))) msg = FIPAMessage(message_id=new_msg_id, dialogue_id=cfp.get("dialogue_id"), performative=FIPAMessage.Performative.DECLINE, target=cfp.get("id")) dialogue.outgoing_extend(msg) msg_bytes = FIPASerializer().encode(msg) result = Envelope(to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) dialogues = cast(Dialogues, self.context.dialogues) dialogues.dialogue_stats.add_dialogue_endstate(Dialogue.EndState.DECLINED_CFP, dialogue.is_self_initiated) else: assert proposal_description is not None transaction_id = generate_transaction_id(self.context.agent_public_key, dialogue.dialogue_label.dialogue_opponent_pbk, dialogue.dialogue_label, dialogue.is_seller) transaction_msg = TransactionMessage(transaction_id=transaction_id, sender=self.context.agent_public_key, counterparty=dialogue.dialogue_label.dialogue_opponent_pbk, currency='FET', amount=proposal_description.values['amount'], is_sender_buyer=not dialogue.is_seller, sender_tx_fee=1, counterparty_tx_fee=1, quantities_by_good_pbk=proposal_description.values['description']) transactions = cast(Transactions, self.context.transactions) transactions.add_pending_proposal(dialogue.dialogue_label, new_msg_id, transaction_msg) logger.debug("[{}]: sending to {} a Propose{}".format(self.context.agent_name, dialogue.dialogue_label.dialogue_opponent_pbk, pprint.pformat({ "msg_id": new_msg_id, "dialogue_id": cfp.get("dialogue_id"), "origin": dialogue.dialogue_label.dialogue_opponent_pbk, "target": cfp.get("id"), "propose": proposal_description.values }))) msg = FIPAMessage(performative=FIPAMessage.Performative.PROPOSE, message_id=new_msg_id, dialogue_id=cfp.get("dialogue_id"), target=cfp.get("id"), proposal=[proposal_description]) dialogue.outgoing_extend(msg) msg_bytes = FIPASerializer().encode(msg) result = Envelope(to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) self.context.outbox.put(result)