diff --git a/lib/tfw/__init__.py b/lib/tfw/__init__.py index d0e877b..9736ade 100644 --- a/lib/tfw/__init__.py +++ b/lib/tfw/__init__.py @@ -1,6 +1,6 @@ # Copyright (C) 2018 Avatao.com Innovative Learning Kft. # All Rights Reserved. See LICENSE file for details. -from .event_handler_base import EventHandlerBase, TriggeredEventHandler +from .event_handler_base import EventHandlerBase, TriggeredEventHandler, BroadcastingEventHandler from .fsm_base import FSMBase from .linear_fsm import LinearFSM diff --git a/lib/tfw/event_handler_base.py b/lib/tfw/event_handler_base.py index cfce6f7..8771f35 100644 --- a/lib/tfw/event_handler_base.py +++ b/lib/tfw/event_handler_base.py @@ -2,8 +2,13 @@ # All Rights Reserved. See LICENSE file for details. from abc import ABC, abstractmethod +from json import dumps +from hashlib import md5 from tfw.networking.event_handlers import ServerConnector +from tfw.config.logs import logging + +LOG = logging.getLogger(__name__) class EventHandlerBase(ABC): @@ -28,12 +33,14 @@ class EventHandlerBase(ABC): """ response = self.dispatch_handling(message) if response: - response['key'] = message['key'] self.server_connector.send(response) def dispatch_handling(self, message): """ Used to dispatch messages to their specific handlers. + + :param message: the message received + :returns: the message to send back """ if message['key'] != 'reset': return self.handle_event(message) @@ -45,6 +52,7 @@ class EventHandlerBase(ABC): Abstract method that implements the handling of messages. :param message: the message received + :returns: the message to send back """ raise NotImplementedError @@ -54,6 +62,7 @@ class EventHandlerBase(ABC): Usually 'reset' events receive some sort of special treatment. :param message: the message received + :returns: the message to send back """ return None @@ -100,3 +109,38 @@ class TriggeredEventHandler(EventHandlerBase, ABC): if message.get('trigger') == self.trigger: return super().dispatch_handling(message) return None + + +class BroadcastingEventHandler(EventHandlerBase, ABC): + # pylint: disable=abstract-method + """ + Abstract base class for EventHandlers which broadcast responses + and intelligently ignore their own broadcasted messages they receive. + """ + def __init__(self, key): + super().__init__(key) + self.own_message_hashes = [] + + def event_handler_callback(self, message): + message_hash = self.hash_message(message) + + if message_hash in self.own_message_hashes: + self.own_message_hashes.remove(message_hash) + return + + response = self.dispatch_handling(message) + if response: + self.own_message_hashes.append(self.hash_message(response)) + self.server_connector.send(self.make_broadcast_message(response)) + + @staticmethod + def hash_message(message): + message_bytes = dumps(message, sort_keys=True).encode() + return md5(message_bytes).hexdigest() + + @staticmethod + def make_broadcast_message(message): + return { + 'key': 'broadcast', + 'data': message + }