Source code for simfleet.strategies

import json
import random

from loguru import logger

from .customer import CustomerStrategyBehaviour
from .fleetmanager import FleetManagerStrategyBehaviour
from .helpers import PathRequestException
from .protocol import REQUEST_PERFORMATIVE, ACCEPT_PERFORMATIVE, REFUSE_PERFORMATIVE, PROPOSE_PERFORMATIVE, \
    CANCEL_PERFORMATIVE, INFORM_PERFORMATIVE, QUERY_PROTOCOL, REQUEST_PROTOCOL
from .transport import TransportStrategyBehaviour
from .utils import TRANSPORT_WAITING, TRANSPORT_WAITING_FOR_APPROVAL, CUSTOMER_WAITING, TRANSPORT_MOVING_TO_CUSTOMER, \
    CUSTOMER_ASSIGNED, TRANSPORT_WAITING_FOR_STATION_APPROVAL, TRANSPORT_MOVING_TO_STATION, \
    TRANSPORT_CHARGING, TRANSPORT_CHARGED, TRANSPORT_NEEDS_CHARGING


################################################################
#                                                              #
#                     FleetManager Strategy                    #
#                                                              #
################################################################
[docs]class DelegateRequestBehaviour(FleetManagerStrategyBehaviour): """ The default strategy for the FleetManager agent. By default it delegates all requests to all transports. """
[docs] async def run(self): if not self.agent.registration: await self.send_registration() msg = await self.receive(timeout=5) logger.debug("Manager received message: {}".format(msg)) if msg: for transport in self.get_transport_agents().values(): msg.to = str(transport["jid"]) logger.debug("Manager sent request to transport {}".format(transport["name"])) await self.send(msg)
################################################################ # # # Transport Strategy # # # ################################################################
[docs]class AcceptAlwaysStrategyBehaviour(TransportStrategyBehaviour): """ The default strategy for the Transport agent. By default it accepts every request it receives if available. """
[docs] async def run(self): if self.agent.needs_charging(): if self.agent.stations is None or len(self.agent.stations) < 1: logger.warning("Transport {} looking for a station.".format(self.agent.name)) await self.send_get_stations() else: station = random.choice(list(self.agent.stations.keys())) logger.info("Transport {} reserving station {}.".format(self.agent.name, station)) await self.send_proposal(station) self.agent.status = TRANSPORT_WAITING_FOR_STATION_APPROVAL msg = await self.receive(timeout=5) if not msg: return logger.debug("Transport received message: {}".format(msg)) try: content = json.loads(msg.body) except TypeError: content = {} performative = msg.get_metadata("performative") protocol = msg.get_metadata("protocol") if protocol == QUERY_PROTOCOL: if performative == INFORM_PERFORMATIVE: self.agent.stations = content logger.info("Got list of current stations: {}".format(list(self.agent.stations.keys()))) elif performative == CANCEL_PERFORMATIVE: logger.info("Cancellation of request for stations information.") elif protocol == REQUEST_PROTOCOL: logger.debug("Transport {} received request protocol from customer/station.".format(self.agent.name)) if performative == REQUEST_PERFORMATIVE: if self.agent.status == TRANSPORT_WAITING: if not self.has_enough_autonomy(content["origin"], content["dest"]): await self.cancel_proposal(content["customer_id"]) self.agent.status = TRANSPORT_NEEDS_CHARGING else: await self.send_proposal(content["customer_id"], {}) self.agent.status = TRANSPORT_WAITING_FOR_APPROVAL elif performative == ACCEPT_PERFORMATIVE: if self.agent.status == TRANSPORT_WAITING_FOR_APPROVAL: logger.debug("Transport {} got accept from {}".format(self.agent.name, content["customer_id"])) try: self.agent.status = TRANSPORT_MOVING_TO_CUSTOMER await self.pick_up_customer(content["customer_id"], content["origin"], content["dest"]) except PathRequestException: logger.error("Transport {} could not get a path to customer {}. Cancelling..." .format(self.agent.name, content["customer_id"])) self.agent.status = TRANSPORT_WAITING await self.cancel_proposal(content["customer_id"]) except Exception as e: logger.error("Unexpected error in transport {}: {}".format(self.agent.name, e)) await self.cancel_proposal(content["customer_id"]) self.agent.status = TRANSPORT_WAITING else: await self.cancel_proposal(content["customer_id"]) elif performative == REFUSE_PERFORMATIVE: logger.debug("Transport {} got refusal from customer/station".format(self.agent.name)) self.agent.status = TRANSPORT_WAITING elif performative == INFORM_PERFORMATIVE: if self.agent.status == TRANSPORT_WAITING_FOR_STATION_APPROVAL: logger.info("Transport {} got accept from station {}".format(self.agent.name, content["station_id"])) try: self.agent.status = TRANSPORT_MOVING_TO_STATION await self.send_confirmation_travel(content["station_id"]) await self.go_to_the_station(content["station_id"], content["dest"]) except PathRequestException: logger.error("Transport {} could not get a path to station {}. Cancelling..." .format(self.agent.name, content["station_id"])) self.agent.status = TRANSPORT_WAITING await self.cancel_proposal(content["station_id"]) except Exception as e: logger.error("Unexpected error in transport {}: {}".format(self.agent.name, e)) await self.cancel_proposal(content["station_id"]) self.agent.status = TRANSPORT_WAITING elif self.agent.status == TRANSPORT_CHARGING: if content["status"] == TRANSPORT_CHARGED: self.agent.transport_charged() await self.agent.drop_station() elif performative == CANCEL_PERFORMATIVE: logger.info("Cancellation of request for {} information".format(self.agent.fleet_type))
################################################################ # # # Customer Strategy # # # ################################################################
[docs]class AcceptFirstRequestBehaviour(CustomerStrategyBehaviour): """ The default strategy for the Customer agent. By default it accepts the first proposal it receives. """
[docs] async def run(self): if self.agent.fleetmanagers is None: await self.send_get_managers(self.agent.fleet_type) msg = await self.receive(timeout=5) if msg: performative = msg.get_metadata("performative") if performative == INFORM_PERFORMATIVE: self.agent.fleetmanagers = json.loads(msg.body) return elif performative == CANCEL_PERFORMATIVE: logger.info("Cancellation of request for {} information".format(self.agent.type_service)) return if self.agent.status == CUSTOMER_WAITING: await self.send_request(content={}) msg = await self.receive(timeout=5) if msg: performative = msg.get_metadata("performative") transport_id = msg.sender if performative == PROPOSE_PERFORMATIVE: if self.agent.status == CUSTOMER_WAITING: logger.debug( "Customer {} received proposal from transport {}".format(self.agent.name, transport_id)) await self.accept_transport(transport_id) self.agent.status = CUSTOMER_ASSIGNED else: await self.refuse_transport(transport_id) elif performative == CANCEL_PERFORMATIVE: if self.agent.transport_assigned == str(transport_id): logger.warning( "Customer {} received a CANCEL from Transport {}.".format(self.agent.name, transport_id)) self.agent.status = CUSTOMER_WAITING