Skip to content

Communication

gradysim.simulator.handler.communication.CommunicationHandler

Bases: INodeHandler

Adds communication to the simulation. Nodes, through their providers, can send this handler communication commands that dictate how a message should be sent. This message will be delivered to the destination node.

Messages are transmited through a medium that determines conditions like communication range and failure rate. Messages can fail to be delivered or be delivered late.

Source code in gradysim/simulator/handler/communication.py
class CommunicationHandler(INodeHandler):
    """
    Adds communication to the simulation. Nodes, through their providers, can
    send this handler communication commands that dictate how a message should
    be sent. This message will be delivered to the destination node.

    Messages are transmited through a [medium][gradysim.simulator.handler.communication.CommunicationMedium] that
    determines conditions like communication range and failure rate. Messages can fail to be delivered or 
    be delivered late.
    """
    @staticmethod
    def get_label() -> str:
        return "communication"

    _sources: Dict[int, CommunicationSource]
    _destinations: Dict[int, CommunicationDestination]
    _event_loop: EventLoop

    def __init__(self, communication_medium: CommunicationMedium = CommunicationMedium()):
        """
        Initializes the communication handler.

        Args:
            communication_medium: Configuration of the network conditions. If not set all default values will be used.
        """
        self._injected = False

        self._sources: Dict[int, CommunicationSource] = {}
        self._destinations: Dict[int, CommunicationDestination] = {}

        self.default_medium = communication_medium

    def inject(self, event_loop: EventLoop):
        self._injected = True
        self._event_loop = event_loop

    def register_node(self, node: Node):
        if not self._injected:
            raise CommunicationException("Error registering node: Cannot register node on uninitialized "
                                         "node handler")
        self._sources[node.id] = CommunicationSource(node)
        self._destinations[node.id] = CommunicationDestination(node)

    def handle_command(self,
                       command: CommunicationCommand,
                       sender: Node,
                       medium: CommunicationMedium = None):
        """
        Performs a communication command. This method should be called by the node's
        provider to transmit a communication command to the communication handler.

        Args:
            command: Command being issued
            sender: Node issuing the command
            medium: Optional communication medium to use for this specific command. If not set, the default medium
                    of the handler will be used.
        """
        if sender.id == command.destination:
            raise CommunicationException("Error transmitting message: message destination is equal to sender. Try "
                                         "using schedule_timer.")

        source = self._sources[sender.id]

        # Use the provided medium if available; otherwise fall back to the default handler medium
        if medium is None:
            medium = self.default_medium

        if command.command_type == CommunicationCommandType.BROADCAST:
            for destination, endpoint in self._destinations.items():
                if destination != sender.id:
                    self._transmit_message(command.message, source, endpoint, medium)
        else:
            destination = command.destination
            if destination is None:
                raise CommunicationException("Error transmitting message: a destination is "
                                             "required when command type SEND is used.")
            if destination not in self._destinations:
                raise CommunicationException(f"Error transmitting message: destination {destination} does not exist.")

            self._transmit_message(command.message, source, self._destinations[destination], medium)

    def _transmit_message(self, message: str, source: CommunicationSource, destination: CommunicationDestination,
                          medium: CommunicationMedium):
        """
        Transmits a message from source to destination through the communication medium.
        """
        source.hand_over_message(message, destination)

        if can_transmit(source.node.position, destination.node.position, medium):
            if medium.delay <= 0:
                self._event_loop.schedule_event(
                    self._event_loop.current_time,
                    lambda: destination.receive_message(message, source),
                    label_node(destination.node) + " handle_packet"
                )
            else:
                self._event_loop.schedule_event(
                    self._event_loop.current_time + medium.delay,
                    lambda: destination.receive_message(message, source),
                    label_node(destination.node) + " handle_packet"
                )

__init__(communication_medium=CommunicationMedium())

Initializes the communication handler.

Parameters:

Name Type Description Default
communication_medium CommunicationMedium

Configuration of the network conditions. If not set all default values will be used.

CommunicationMedium()
Source code in gradysim/simulator/handler/communication.py
def __init__(self, communication_medium: CommunicationMedium = CommunicationMedium()):
    """
    Initializes the communication handler.

    Args:
        communication_medium: Configuration of the network conditions. If not set all default values will be used.
    """
    self._injected = False

    self._sources: Dict[int, CommunicationSource] = {}
    self._destinations: Dict[int, CommunicationDestination] = {}

    self.default_medium = communication_medium

handle_command(command, sender, medium=None)

Performs a communication command. This method should be called by the node's provider to transmit a communication command to the communication handler.

Parameters:

Name Type Description Default
command CommunicationCommand

Command being issued

required
sender Node

Node issuing the command

required
medium CommunicationMedium

Optional communication medium to use for this specific command. If not set, the default medium of the handler will be used.

None
Source code in gradysim/simulator/handler/communication.py
def handle_command(self,
                   command: CommunicationCommand,
                   sender: Node,
                   medium: CommunicationMedium = None):
    """
    Performs a communication command. This method should be called by the node's
    provider to transmit a communication command to the communication handler.

    Args:
        command: Command being issued
        sender: Node issuing the command
        medium: Optional communication medium to use for this specific command. If not set, the default medium
                of the handler will be used.
    """
    if sender.id == command.destination:
        raise CommunicationException("Error transmitting message: message destination is equal to sender. Try "
                                     "using schedule_timer.")

    source = self._sources[sender.id]

    # Use the provided medium if available; otherwise fall back to the default handler medium
    if medium is None:
        medium = self.default_medium

    if command.command_type == CommunicationCommandType.BROADCAST:
        for destination, endpoint in self._destinations.items():
            if destination != sender.id:
                self._transmit_message(command.message, source, endpoint, medium)
    else:
        destination = command.destination
        if destination is None:
            raise CommunicationException("Error transmitting message: a destination is "
                                         "required when command type SEND is used.")
        if destination not in self._destinations:
            raise CommunicationException(f"Error transmitting message: destination {destination} does not exist.")

        self._transmit_message(command.message, source, self._destinations[destination], medium)

gradysim.simulator.handler.communication.CommunicationMedium dataclass

Conditions through which the messages are delivered. Can influence how and when messages can be delivered.

Source code in gradysim/simulator/handler/communication.py
@dataclass
class CommunicationMedium:
    """
    Conditions through which the messages are delivered. Can influence how and when messages can be delivered.
    """
    transmission_range: float = 60
    """Maximum range in meters for message delivery. Messages destined to nodes outside this range will not be delivered"""

    delay: float = 0
    """Sets a delay in seconds for message delivery, representing network delay. Range is evaluated before the delay is applied"""

    failure_rate: float = 0
    """Failure chance between 0 and 1 for message delivery. 0 represents messages never failing and 1 always fails."""

delay: float = 0 class-attribute instance-attribute

Sets a delay in seconds for message delivery, representing network delay. Range is evaluated before the delay is applied

failure_rate: float = 0 class-attribute instance-attribute

Failure chance between 0 and 1 for message delivery. 0 represents messages never failing and 1 always fails.

transmission_range: float = 60 class-attribute instance-attribute

Maximum range in meters for message delivery. Messages destined to nodes outside this range will not be delivered