mirror of
				https://github.com/avatao-content/baseimage-tutorial-framework
				synced 2025-11-04 12:52:54 +00:00 
			
		
		
		
	Merge branch 'ocicat', the unrealized dream. Ocicat will return...
This commit is contained in:
		
							
								
								
									
										6
									
								
								lib/tfw/event_handler_base/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								lib/tfw/event_handler_base/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
# Copyright (C) 2018 Avatao.com Innovative Learning Kft.
 | 
			
		||||
# All Rights Reserved. See LICENSE file for details.
 | 
			
		||||
 | 
			
		||||
from .event_handler_base import EventHandlerBase
 | 
			
		||||
from .boradcasting_event_handler import BroadcastingEventHandler
 | 
			
		||||
from .fsm_aware_event_handler import FSMAwareEventHandler
 | 
			
		||||
							
								
								
									
										30
									
								
								lib/tfw/event_handler_base/boradcasting_event_handler.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								lib/tfw/event_handler_base/boradcasting_event_handler.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
# Copyright (C) 2018 Avatao.com Innovative Learning Kft.
 | 
			
		||||
# All Rights Reserved. See LICENSE file for details.
 | 
			
		||||
 | 
			
		||||
from abc import ABC
 | 
			
		||||
 | 
			
		||||
from tfw.event_handler_base.event_handler_base import EventHandlerBase
 | 
			
		||||
from tfw.crypto import message_checksum
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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 = message_checksum(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(message_checksum(response))
 | 
			
		||||
            self.server_connector.broadcast(response)
 | 
			
		||||
							
								
								
									
										126
									
								
								lib/tfw/event_handler_base/event_handler_base.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								lib/tfw/event_handler_base/event_handler_base.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,126 @@
 | 
			
		||||
# Copyright (C) 2018 Avatao.com Innovative Learning Kft.
 | 
			
		||||
# All Rights Reserved. See LICENSE file for details.
 | 
			
		||||
 | 
			
		||||
from abc import ABC, abstractmethod
 | 
			
		||||
from inspect import currentframe
 | 
			
		||||
from typing import Iterable
 | 
			
		||||
 | 
			
		||||
from tfw.networking.event_handlers.server_connector import ServerConnector
 | 
			
		||||
from tfw.config.logs import logging
 | 
			
		||||
 | 
			
		||||
LOG = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EventHandlerBase(ABC):
 | 
			
		||||
    """
 | 
			
		||||
    Abstract base class for all Python based EventHandlers. Useful implementation template
 | 
			
		||||
    for other languages.
 | 
			
		||||
 | 
			
		||||
    Derived classes must implement the handle_event() method
 | 
			
		||||
    """
 | 
			
		||||
    def __init__(self, key):
 | 
			
		||||
        self.server_connector = ServerConnector()
 | 
			
		||||
        self.keys = []
 | 
			
		||||
        if isinstance(key, str):
 | 
			
		||||
            self.keys.append(key)
 | 
			
		||||
        elif isinstance(key, Iterable):
 | 
			
		||||
            self.keys = list(key)
 | 
			
		||||
 | 
			
		||||
        self.subscribe(*self.keys)
 | 
			
		||||
        self.server_connector.register_callback(self.event_handler_callback)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def key(self):
 | 
			
		||||
        """
 | 
			
		||||
        Returns the oldest key this EventHandler was subscribed to.
 | 
			
		||||
        """
 | 
			
		||||
        return self.keys[0]
 | 
			
		||||
 | 
			
		||||
    def event_handler_callback(self, message):
 | 
			
		||||
        """
 | 
			
		||||
        Callback that is invoked when receiving a message.
 | 
			
		||||
        Dispatches messages to handler methods and sends
 | 
			
		||||
        a response back in case the handler returned something.
 | 
			
		||||
        This is subscribed in __init__().
 | 
			
		||||
        """
 | 
			
		||||
        if not self.check_key(message):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        response = self.dispatch_handling(message)
 | 
			
		||||
        if response:
 | 
			
		||||
            self.server_connector.send(response)
 | 
			
		||||
 | 
			
		||||
    def check_key(self, message):
 | 
			
		||||
        """
 | 
			
		||||
        Checks whether the message is intended for this
 | 
			
		||||
        EventHandler.
 | 
			
		||||
 | 
			
		||||
        This is necessary because ZMQ handles PUB - SUB
 | 
			
		||||
        connetions with pattern matching (e.g. someone
 | 
			
		||||
        subscribed to 'fsm' will receive 'fsm_update'
 | 
			
		||||
        messages as well.
 | 
			
		||||
        """
 | 
			
		||||
        if '' in self.keys:
 | 
			
		||||
            return True
 | 
			
		||||
        return message['key'] in self.keys
 | 
			
		||||
 | 
			
		||||
    def dispatch_handling(self, message):
 | 
			
		||||
        """
 | 
			
		||||
        Used to dispatch messages to their specific handlers.
 | 
			
		||||
 | 
			
		||||
        :param message: the message received
 | 
			
		||||
        :returns: the message to send back
 | 
			
		||||
        """
 | 
			
		||||
        return self.handle_event(message)
 | 
			
		||||
 | 
			
		||||
    @abstractmethod
 | 
			
		||||
    def handle_event(self, message):
 | 
			
		||||
        """
 | 
			
		||||
        Abstract method that implements the handling of messages.
 | 
			
		||||
 | 
			
		||||
        :param message: the message received
 | 
			
		||||
        :returns: the message to send back
 | 
			
		||||
        """
 | 
			
		||||
        raise NotImplementedError
 | 
			
		||||
 | 
			
		||||
    def subscribe(self, *keys):
 | 
			
		||||
        """
 | 
			
		||||
        Subscribe this EventHandler to receive events for given keys.
 | 
			
		||||
        Note that you can subscribe to the same key several times in which
 | 
			
		||||
        case you will need to unsubscribe multiple times in order to stop
 | 
			
		||||
        receiving events.
 | 
			
		||||
 | 
			
		||||
        :param keys: list of keys to subscribe to
 | 
			
		||||
        """
 | 
			
		||||
        for key in keys:
 | 
			
		||||
            self.server_connector.subscribe(key)
 | 
			
		||||
            self.keys.append(key)
 | 
			
		||||
 | 
			
		||||
    def unsubscribe(self, *keys):
 | 
			
		||||
        """
 | 
			
		||||
        Unsubscribe this eventhandler from the given keys.
 | 
			
		||||
 | 
			
		||||
        :param keys: list of keys to unsubscribe from
 | 
			
		||||
        """
 | 
			
		||||
        for key in keys:
 | 
			
		||||
            self.server_connector.unsubscribe(key)
 | 
			
		||||
            self.keys.remove(key)
 | 
			
		||||
 | 
			
		||||
    def cleanup(self):
 | 
			
		||||
        """
 | 
			
		||||
        Perform cleanup actions such as releasing database
 | 
			
		||||
        connections and stuff like that.
 | 
			
		||||
        """
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def get_local_instances(cls):
 | 
			
		||||
        frame = currentframe()
 | 
			
		||||
        if frame is None:
 | 
			
		||||
            raise EnvironmentError('inspect.currentframe() is not supported!')
 | 
			
		||||
 | 
			
		||||
        locals_values = frame.f_back.f_locals.values()
 | 
			
		||||
        return {
 | 
			
		||||
            instance for instance in locals_values
 | 
			
		||||
            if isinstance(instance, cls)
 | 
			
		||||
        }
 | 
			
		||||
							
								
								
									
										24
									
								
								lib/tfw/event_handler_base/fsm_aware_event_handler.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								lib/tfw/event_handler_base/fsm_aware_event_handler.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
# Copyright (C) 2018 Avatao.com Innovative Learning Kft.
 | 
			
		||||
# All Rights Reserved. See LICENSE file for details.
 | 
			
		||||
 | 
			
		||||
from abc import ABC
 | 
			
		||||
 | 
			
		||||
from tfw.event_handler_base.event_handler_base import EventHandlerBase
 | 
			
		||||
from tfw.networking.fsm_aware import FSMAware
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FSMAwareEventHandler(EventHandlerBase, FSMAware, ABC):
 | 
			
		||||
    # pylint: disable=abstract-method
 | 
			
		||||
    """
 | 
			
		||||
    Abstract base class for EventHandlers which automatically
 | 
			
		||||
    keep track of the state of the TFW FSM.
 | 
			
		||||
    """
 | 
			
		||||
    def __init__(self, key):
 | 
			
		||||
        EventHandlerBase.__init__(self, key)
 | 
			
		||||
        FSMAware.__init__(self)
 | 
			
		||||
        self.subscribe('fsm_update')
 | 
			
		||||
 | 
			
		||||
    def dispatch_handling(self, message):
 | 
			
		||||
        if self.update_fsm_data(message):
 | 
			
		||||
            return None
 | 
			
		||||
        return super().dispatch_handling(message)
 | 
			
		||||
		Reference in New Issue
	
	Block a user