diff --git a/source/__main__.py b/source/__main__.py index 434618d..1d60555 100644 --- a/source/__main__.py +++ b/source/__main__.py @@ -1,15 +1,5 @@ -import threading - from source.managers import Manager manager = Manager("wlp1s0") - -thread_receive = threading.Thread(target=manager.receiveLoop) -thread_send = threading.Thread(target=manager.sendLoop) - -thread_receive.start() -thread_send.start() - -thread_receive.join() -thread_send.join() +manager.loop() diff --git a/source/behaviors/events/DiscoveryEvent.py b/source/behaviors/events/DiscoveryEvent.py index 2fc8da7..03ad7e6 100644 --- a/source/behaviors/events/DiscoveryEvent.py +++ b/source/behaviors/events/DiscoveryEvent.py @@ -3,5 +3,5 @@ from source import packets class DiscoveryEvent(base.BaseEvent): - def handle(self, packet: packets.DiscoveryPacket): - pass + def handle(self, packet: packets.DiscoveryPacket, address: tuple): + print("discovery event !") diff --git a/source/behaviors/events/__init__.py b/source/behaviors/events/__init__.py index e69de29..60163d0 100644 --- a/source/behaviors/events/__init__.py +++ b/source/behaviors/events/__init__.py @@ -0,0 +1,3 @@ +from . import base + +from .DiscoveryEvent import DiscoveryEvent diff --git a/source/behaviors/events/base/BaseEvent.py b/source/behaviors/events/base/BaseEvent.py index 7d32e30..21ed149 100644 --- a/source/behaviors/events/base/BaseEvent.py +++ b/source/behaviors/events/base/BaseEvent.py @@ -1,5 +1,13 @@ import abc +from source import packets + class BaseEvent(abc.ABC): - pass + @abc.abstractmethod + def handle(self, packet: packets.base.BasePacket, address: tuple) -> None: + """ + Handle a packet + :param packet: the packet to handle + :param address: the address of the machine that sent the packet + """ diff --git a/source/behaviors/roles/UndefinedRole.py b/source/behaviors/roles/UndefinedRole.py index 26d5193..3e374f9 100644 --- a/source/behaviors/roles/UndefinedRole.py +++ b/source/behaviors/roles/UndefinedRole.py @@ -4,6 +4,6 @@ from source import managers, packets class UndefinedRole(base.BaseRole): - def run(self, manager: "managers.Manager"): + def handle(self, manager: "managers.Manager"): packet = packets.DiscoveryPacket() manager.communication.broadcast(packet) diff --git a/source/behaviors/roles/__init__.py b/source/behaviors/roles/__init__.py index ed6f133..912d337 100644 --- a/source/behaviors/roles/__init__.py +++ b/source/behaviors/roles/__init__.py @@ -1 +1,2 @@ +from . import base from .UndefinedRole import UndefinedRole diff --git a/source/behaviors/roles/base/BaseRole.py b/source/behaviors/roles/base/BaseRole.py index 378fbe6..d1c732f 100644 --- a/source/behaviors/roles/base/BaseRole.py +++ b/source/behaviors/roles/base/BaseRole.py @@ -5,7 +5,7 @@ from source import managers class BaseRole(abc.ABC): @abc.abstractmethod - def run(self, manager: "managers.Manager") -> None: + def handle(self, manager: "managers.Manager") -> None: """ Behavior of the role """ diff --git a/source/managers/CommunicationManager.py b/source/managers/CommunicationManager.py index eaa2393..2a54281 100644 --- a/source/managers/CommunicationManager.py +++ b/source/managers/CommunicationManager.py @@ -5,6 +5,7 @@ import zlib import bidict from source import packets +from source.managers import Manager from source.utils.crypto.type import CipherType @@ -13,7 +14,9 @@ class CommunicationManager: Manage everything about communication """ - def __init__(self, interface: str, broadcast_address: str = "ff02::1", port: int = 5555): + def __init__(self, manager: "Manager", interface: str, broadcast_address: str = "ff02::1", port: int = 5555): + self.manager = manager + self.broadcast_address = broadcast_address self.port = port @@ -59,7 +62,7 @@ class CommunicationManager: # get the header identifier of the type of this packet header: typing.Optional[bytes] = self.packet_types.inverse.get(type(packet)) if header is None: - raise Exception(f"Unrecognised packet type: {type(packet)}. Has it been registered ?") + raise KeyError(f"Unrecognised packet type: {type(packet)}. Has it been registered ?") # get the encoded packet data data = packet.pack() @@ -88,7 +91,7 @@ class CommunicationManager: # get the type of the packet from its header packet_type: typing.Optional[typing.Type[packets.base.BasePacket]] = self.packet_types.get(header) if header is None: - raise Exception(f"Unrecognised packet header: {header}. Has it been registered ?") + raise KeyError(f"Unrecognised packet header: {header}. Has it been registered ?") # unpack the packet return packet_type.unpack(data) diff --git a/source/managers/EventManager.py b/source/managers/EventManager.py new file mode 100644 index 0000000..ffe915a --- /dev/null +++ b/source/managers/EventManager.py @@ -0,0 +1,53 @@ +import typing +import warnings + +from source import packets +from source.behaviors import events +from source.managers import Manager + + +class EventManager: + def __init__(self, manager: "Manager"): + self.manager = manager + + # events + self.event_handlers: dict[typing.Type[packets.base.BasePacket], events.base.BaseEvent] = {} + + def register_event_handler(self, packet_type: typing.Type[packets.base.BasePacket], event: events.base.BaseEvent) -> None: + """ + Register a new event to react to a specific packet type + :param packet_type: the type of packet to listen to + :param event: the event handler + """ + + self.event_handlers[packet_type] = event + + def handle(self, packet: packets.base.BasePacket, address: tuple) -> None: + """ + Handle the packet received + :param packet: the packet to handle + :param address: the address of the machine that sent the packet + """ + + # get the event handler of this kind of packet + event_handler = self.event_handlers.get(type(packet)) + if event_handler is None: + raise KeyError(f"Unrecognised packet type: {type(packet)}. Has it been registered ?") + + # use the event handler on the packet + event_handler.handle(packet, address) + + def loop(self): + while True: + try: + # wait for a new packet + packet, address = self.manager.communication.receive() + print(f"Received message from {address}: {packet}") + # give it to the event handler + self.manager.event.handle(packet, address) + + except KeyboardInterrupt: + print("Stopping listener.") + + except Exception as exception: + warnings.warn(str(exception)) diff --git a/source/managers/Manager.py b/source/managers/Manager.py index e0a2942..4f9603a 100644 --- a/source/managers/Manager.py +++ b/source/managers/Manager.py @@ -1,30 +1,31 @@ -from . import CommunicationManager +import threading + from source import packets -from source.behaviors import roles +from source.behaviors import events class Manager: def __init__(self, interface: str): - self.communication = CommunicationManager(interface) + from . import CommunicationManager, EventManager, RoleManager + + # communication manager + self.communication = CommunicationManager(self, interface) self.communication.register_packet_type(b"DISC", packets.DiscoveryPacket) - # define the role of our machine - # TODO(Faraphel): give the manager to the role directly ? register ? - self.role = roles.UndefinedRole() + # event manager + self.event = EventManager(self) + self.event.register_event_handler(packets.DiscoveryPacket, events.DiscoveryEvent()) + # role manager + self.role = RoleManager(self) - def sendLoop(self): - while True: - self.role.run(self) + def loop(self): + # run a thread for the event and the role manager + event_thread = threading.Thread(target=self.event.loop) + role_thread = threading.Thread(target=self.role.loop) - def receiveLoop(self): - try: - while True: - packet, address = self.communication.receive() - print(f"Received message from {address}: {packet}") + event_thread.start() + role_thread.start() - # get corresponding event - # handle it - - except KeyboardInterrupt: - print("Stopping listener.") \ No newline at end of file + event_thread.join() + role_thread.join() \ No newline at end of file diff --git a/source/managers/RoleManager.py b/source/managers/RoleManager.py new file mode 100644 index 0000000..2d93452 --- /dev/null +++ b/source/managers/RoleManager.py @@ -0,0 +1,25 @@ +from source.behaviors import roles +from source.managers import Manager + + +class RoleManager: + def __init__(self, manager: "Manager"): + self.manager = manager + + # the currently used role + self.current: roles.base.BaseRole = roles.UndefinedRole() + + def handle(self) -> None: + """ + Run the role + """ + + self.current.handle(self.manager) + + def loop(self) -> None: + """ + Handle forever + """ + + while True: + self.handle() diff --git a/source/managers/__init__.py b/source/managers/__init__.py index 723dbce..c140338 100644 --- a/source/managers/__init__.py +++ b/source/managers/__init__.py @@ -1,2 +1,5 @@ from .CommunicationManager import CommunicationManager +from .EventManager import EventManager +from .RoleManager import RoleManager + from .Manager import Manager