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 = {}
        self._destinations = {}
        self.communication_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):
        """
        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
        """
        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]

        if command.command_type == CommunicationCommandType.BROADCAST:
            for destination, endpoint in self._destinations.items():
                if destination != sender.id:
                    self._transmit_message(command.message, source, endpoint)
        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])

    def _transmit_message(self, message: str, source: CommunicationSource, destination: CommunicationDestination):
        source.hand_over_message(message, destination)

        if can_transmit(source.node.position, destination.node.position, self.communication_medium):
            if self.communication_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 + self.communication_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 = {}
    self._destinations = {}
    self.communication_medium = communication_medium

handle_command(command, sender)

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
Source code in gradysim/simulator/handler/communication.py
def handle_command(self, command: CommunicationCommand, sender: Node):
    """
    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
    """
    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]

    if command.command_type == CommunicationCommandType.BROADCAST:
        for destination, endpoint in self._destinations.items():
            if destination != sender.id:
                self._transmit_message(command.message, source, endpoint)
    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])

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