Rework EventHandler situation

This commit is contained in:
Kristóf Tóth 2019-06-28 15:11:02 +02:00
parent 28c3e68b5a
commit 78bd97493a
20 changed files with 74 additions and 86 deletions

View File

@ -6,7 +6,7 @@ disable = missing-docstring, too-few-public-methods, invalid-name
[SIMILARITIES] [SIMILARITIES]
min-similarity-lines=6 min-similarity-lines=7
ignore-comments=yes ignore-comments=yes
ignore-docstrings=yes ignore-docstrings=yes
ignore-imports=yes ignore-imports=yes

View File

@ -1,10 +1,13 @@
from .tfw_server_connector import TFWServerUplinkConnector, TFWServerConnector
from .event_handler import EventHandler
from .fsm_aware_event_handler import FSMAwareEventHandler
from .directory_snapshotting_event_handler import DirectorySnapshottingEventHandler from .directory_snapshotting_event_handler import DirectorySnapshottingEventHandler
from .frontend_event_handler import FrontendEventHandler from .frontend_event_handler import FrontendEventHandler
from .fsm_managing_event_handler import FSMManagingEventHandler from .fsm_managing_event_handler import FSMManagingEventHandler
from .ide_event_handler import IdeEventHandler from .ide_event_handler import IdeEventHandler
from .log_monitoring_event_handler import LogMonitoringEventHandler from .log_monitoring_event_handler import LogMonitoringEventHandler
from .message_sender import MessageSender from .message_sender import MessageSender
from .pipe_io_event_handler import PipeIOEventHandlerBase, PipeIOEventHandler #from .pipe_io_event_handler import PipeIOEventHandlerBase, PipeIOEventHandler
from .pipe_io_event_handler import TransformerPipeIOEventHandler, CommandEventHandler #from .pipe_io_event_handler import TransformerPipeIOEventHandler, CommandEventHandler
from .process_managing_event_handler import ProcessManagingEventHandler from .process_managing_event_handler import ProcessManagingEventHandler
from .terminal_event_handler import TerminalEventHandler from .terminal_event_handler import TerminalEventHandler

View File

@ -9,16 +9,18 @@ from datetime import datetime
from dateutil import parser as dateparser from dateutil import parser as dateparser
from tfw.event_handlers import FrontendEventHandlerBase
from tfw.components.snapshot_provider import SnapshotProvider from tfw.components.snapshot_provider import SnapshotProvider
from tfw.config import TFWENV from tfw.config import TFWENV
from tfw.networking import Scope
from .event_handler import EventHandler
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
class DirectorySnapshottingEventHandler(FrontendEventHandlerBase): class DirectorySnapshottingEventHandler(EventHandler):
def __init__(self, key, directories, exclude_unix_patterns=None): def __init__(self, key, directories, exclude_unix_patterns=None):
super().__init__(key) super().__init__(key, scope=Scope.WEBSOCKET)
self.snapshot_providers = {} self.snapshot_providers = {}
self._exclude_unix_patterns = exclude_unix_patterns self._exclude_unix_patterns = exclude_unix_patterns
self.init_snapshot_providers(directories) self.init_snapshot_providers(directories)

View File

@ -0,0 +1,10 @@
from tfw.event_handlers import EventHandlerBase
from tfw.networking import Scope
from .tfw_server_connector import TFWServerConnector
class EventHandler(EventHandlerBase):
# pylint: disable=abstract-method
def __init__(self, key, scope=Scope.ZMQ):
super().__init__(key, TFWServerConnector(), scope=scope)

View File

@ -1,16 +1,17 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from contextlib import suppress from contextlib import suppress
from tfw.event_handlers import FrontendEventHandlerBase from tfw.networking import Scope
from .message_sender import MessageSender from .message_sender import MessageSender
from .event_handler import EventHandler
class FrontendEventHandler(FrontendEventHandlerBase): class FrontendEventHandler(EventHandler):
def __init__(self): def __init__(self):
frontend_keys = ('message', 'queueMessages', 'dashboard', 'console') frontend_keys = ('message', 'queueMessages', 'dashboard', 'console')
self._frontend_message_storage = FrontendMessageStorage(frontend_keys) self._frontend_message_storage = FrontendMessageStorage(frontend_keys)
super().__init__((*frontend_keys, 'recover')) super().__init__((*frontend_keys, 'recover'), scope=Scope.WEBSOCKET)
def handle_event(self, message): def handle_event(self, message):
self._frontend_message_storage.save_message(message) self._frontend_message_storage.save_message(message)

View File

@ -3,18 +3,20 @@
from abc import ABC from abc import ABC
from .event_handler_base import EventHandlerBase from tfw.components import FSMAware
from .fsm_aware import FSMAware from tfw.networking import Scope
from .event_handler import EventHandler
class FSMAwareEventHandler(EventHandlerBase, FSMAware, ABC): class FSMAwareEventHandler(EventHandler, FSMAware, ABC):
# pylint: disable=abstract-method # pylint: disable=abstract-method
""" """
Abstract base class for EventHandlers which automatically Abstract base class for EventHandlers which automatically
keep track of the state of the TFW FSM. keep track of the state of the TFW FSM.
""" """
def __init__(self, key): def __init__(self, key, scope=Scope.ZMQ):
EventHandlerBase.__init__(self, key) EventHandler.__init__(self, key, scope=scope)
FSMAware.__init__(self) FSMAware.__init__(self)
self.subscribe('fsm_update') self.subscribe('fsm_update')

View File

@ -3,14 +3,15 @@
import logging import logging
from tfw.event_handlers import FrontendEventHandlerBase
from tfw.crypto import KeyManager, sign_message, verify_message from tfw.crypto import KeyManager, sign_message, verify_message
from tfw.networking import Scope from tfw.networking import Scope
from .event_handler import EventHandler
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
class FSMManagingEventHandler(FrontendEventHandlerBase): class FSMManagingEventHandler(EventHandler):
""" """
EventHandler responsible for managing the state machine of EventHandler responsible for managing the state machine of
the framework (TFW FSM). the framework (TFW FSM).
@ -26,7 +27,7 @@ class FSMManagingEventHandler(FrontendEventHandlerBase):
command. command.
""" """
def __init__(self, key, fsm_type, require_signature=False): def __init__(self, key, fsm_type, require_signature=False):
super().__init__(key) super().__init__(key, scope=Scope.WEBSOCKET)
self.fsm = fsm_type() self.fsm = fsm_type()
self._fsm_updater = FSMUpdater(self.fsm) self._fsm_updater = FSMUpdater(self.fsm)
self.auth_key = KeyManager().auth_key self.auth_key = KeyManager().auth_key

View File

@ -4,10 +4,11 @@
import logging import logging
from tfw.networking import Scope from tfw.networking import Scope
from tfw.event_handlers import FrontendEventHandlerBase
from tfw.components import FileManager from tfw.components import FileManager
from tfw.components.inotify import InotifyObserver from tfw.components.inotify import InotifyObserver
from .event_handler import EventHandler
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
BUILD_ARTIFACTS = ( BUILD_ARTIFACTS = (
@ -34,7 +35,7 @@ BUILD_ARTIFACTS = (
) )
class IdeEventHandler(FrontendEventHandlerBase): class IdeEventHandler(EventHandler):
# pylint: disable=too-many-arguments,anomalous-backslash-in-string # pylint: disable=too-many-arguments,anomalous-backslash-in-string
""" """
Event handler implementing the backend of our browser based IDE. Event handler implementing the backend of our browser based IDE.
@ -57,7 +58,7 @@ class IdeEventHandler(FrontendEventHandlerBase):
:param selected_file: file that is selected by default :param selected_file: file that is selected by default
:param exclude: list of filenames that should not appear between files (for .o, .pyc, etc.) :param exclude: list of filenames that should not appear between files (for .o, .pyc, etc.)
""" """
super().__init__(key) super().__init__(key, scope=Scope.WEBSOCKET)
try: try:
self.filemanager = FileManager( self.filemanager = FileManager(
allowed_directories=allowed_directories, allowed_directories=allowed_directories,
@ -70,7 +71,10 @@ class IdeEventHandler(FrontendEventHandlerBase):
f'No file(s) in IdeEventHandler working_directory "{directory}"!' f'No file(s) in IdeEventHandler working_directory "{directory}"!'
) )
self.monitor = InotifyObserver(self.filemanager.allowed_directories, exclude=BUILD_ARTIFACTS) self.monitor = InotifyObserver(
self.filemanager.allowed_directories,
exclude=BUILD_ARTIFACTS
)
self.monitor.on_modified = self._reload_frontend self.monitor.on_modified = self._reload_frontend
self.monitor.start() self.monitor.start()
@ -82,7 +86,7 @@ class IdeEventHandler(FrontendEventHandlerBase):
'exclude': self.exclude 'exclude': self.exclude
} }
def _reload_frontend(self, event): def _reload_frontend(self, event): # pylint: disable=unused-argument
self.server_connector.send_message({ self.server_connector.send_message({
'key': 'ide', 'key': 'ide',
'data': {'command': 'reload'} 'data': {'command': 'reload'}
@ -150,7 +154,10 @@ class IdeEventHandler(FrontendEventHandlerBase):
except IndexError: except IndexError:
data['content'] = 'No files in this directory :(' data['content'] = 'No files in this directory :('
except EnvironmentError as err: except EnvironmentError as err:
LOG.error('Failed to select directory "%s". Reason: %s', data['directory'], str(err)) LOG.error(
'Failed to select directory "%s". Reason: %s',
data['directory'], str(err)
)
return data return data
def exclude(self, data): def exclude(self, data):

View File

@ -4,10 +4,11 @@
import logging import logging
from tfw.networking import Scope from tfw.networking import Scope
from tfw.event_handlers import FrontendEventHandlerBase
from tfw.components.inotify import InotifyObserver from tfw.components.inotify import InotifyObserver
from tfw.mixins.supervisor_mixin import SupervisorLogMixin from tfw.mixins.supervisor_mixin import SupervisorLogMixin
from .event_handler import EventHandler
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -49,7 +50,7 @@ class LogInotifyObserver(InotifyObserver, SupervisorLogMixin):
}, Scope.BROADCAST) }, Scope.BROADCAST)
class LogMonitoringEventHandler(FrontendEventHandlerBase): class LogMonitoringEventHandler(EventHandler):
""" """
Monitors the output of a supervisor process (stdout, stderr) and Monitors the output of a supervisor process (stdout, stderr) and
sends the results to the frontend. sends the results to the frontend.
@ -60,7 +61,7 @@ class LogMonitoringEventHandler(FrontendEventHandlerBase):
The API of each command is documented in their respective handler. The API of each command is documented in their respective handler.
""" """
def __init__(self, key, process_name, log_tail=0): def __init__(self, key, process_name, log_tail=0):
super().__init__(key) super().__init__(key, scope=Scope.WEBSOCKET)
self.process_name = process_name self.process_name = process_name
self._monitor = LogInotifyObserver(self.server_connector, process_name, log_tail) self._monitor = LogInotifyObserver(self.server_connector, process_name, log_tail)
self._monitor.start() self._monitor.start()

View File

@ -1,7 +1,7 @@
# Copyright (C) 2018 Avatao.com Innovative Learning Kft. # Copyright (C) 2018 Avatao.com Innovative Learning Kft.
# All Rights Reserved. See LICENSE file for details. # All Rights Reserved. See LICENSE file for details.
from tfw.event_handlers import TFWServerUplinkConnector from .tfw_server_connector import TFWServerUplinkConnector
class MessageSender: class MessageSender:

View File

@ -10,14 +10,15 @@ from secrets import token_urlsafe
from threading import Thread from threading import Thread
from contextlib import suppress from contextlib import suppress
from tfw.event_handlers import EventHandlerBase
from tfw.components.pipe_io_server import PipeIOServer, terminate_process_on_failure from tfw.components.pipe_io_server import PipeIOServer, terminate_process_on_failure
from .event_handler import EventHandler
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
DEFAULT_PERMISSIONS = 0o600 DEFAULT_PERMISSIONS = 0o600
class PipeIOEventHandlerBase(EventHandlerBase): class PipeIOEventHandlerBase(EventHandler):
def __init__(self, key, in_pipe_path, out_pipe_path, permissions=DEFAULT_PERMISSIONS): def __init__(self, key, in_pipe_path, out_pipe_path, permissions=DEFAULT_PERMISSIONS):
super().__init__(key) super().__init__(key)
self.pipe_io = CallbackPipeIOServer( self.pipe_io = CallbackPipeIOServer(

View File

@ -4,9 +4,11 @@
import logging import logging
from xmlrpc.client import Fault as SupervisorFault from xmlrpc.client import Fault as SupervisorFault
from tfw.event_handlers import FrontendEventHandlerBase from tfw.networking import Scope
from tfw.mixins.supervisor_mixin import SupervisorMixin, SupervisorLogMixin from tfw.mixins.supervisor_mixin import SupervisorMixin, SupervisorLogMixin
from .event_handler import EventHandler
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -22,7 +24,7 @@ class ProcessManager(SupervisorMixin, SupervisorLogMixin):
return self.commands[command](process_name) return self.commands[command](process_name)
class ProcessManagingEventHandler(FrontendEventHandlerBase): class ProcessManagingEventHandler(EventHandler):
""" """
Event handler that can manage processes managed by supervisor. Event handler that can manage processes managed by supervisor.
@ -36,7 +38,7 @@ class ProcessManagingEventHandler(FrontendEventHandlerBase):
(the names are as self-documenting as it gets) (the names are as self-documenting as it gets)
""" """
def __init__(self, key, log_tail=0): def __init__(self, key, log_tail=0):
super().__init__(key) super().__init__(key, scope=Scope.WEBSOCKET)
self.processmanager = ProcessManager() self.processmanager = ProcessManager()
self.log_tail = log_tail self.log_tail = log_tail

View File

@ -3,16 +3,18 @@
import logging import logging
from tfw.event_handlers import FrontendEventHandlerBase from tfw.networking import Scope
from tfw.components import BashMonitor from tfw.components import BashMonitor
from tfw.components.terminado_mini_server import TerminadoMiniServer from tfw.components.terminado_mini_server import TerminadoMiniServer
from tfw.config import TFWENV from tfw.config import TFWENV
from tao.config import TAOENV from tao.config import TAOENV
from .event_handler import EventHandler
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
class TerminalEventHandler(FrontendEventHandlerBase): class TerminalEventHandler(EventHandler):
""" """
Event handler responsible for managing terminal sessions for frontend xterm Event handler responsible for managing terminal sessions for frontend xterm
sessions to connect to. You need to instanciate this in order for frontend sessions to connect to. You need to instanciate this in order for frontend
@ -27,7 +29,7 @@ class TerminalEventHandler(FrontendEventHandlerBase):
:param key: key this EventHandler listens to :param key: key this EventHandler listens to
:param monitor: tfw.components.HistoryMonitor instance to read command history from :param monitor: tfw.components.HistoryMonitor instance to read command history from
""" """
super().__init__(key) super().__init__(key, scope=Scope.WEBSOCKET)
self._historymonitor = BashMonitor(self.server_connector, TFWENV.HISTFILE) self._historymonitor = BashMonitor(self.server_connector, TFWENV.HISTFILE)
bash_as_user_cmd = ['sudo', '-u', TAOENV.USER, 'bash'] bash_as_user_cmd = ['sudo', '-u', TAOENV.USER, 'bash']

View File

@ -6,3 +6,4 @@ from .file_manager import FileManager
from .history_monitor import HistoryMonitor, BashMonitor, GDBMonitor from .history_monitor import HistoryMonitor, BashMonitor, GDBMonitor
from .snapshot_provider import SnapshotProvider from .snapshot_provider import SnapshotProvider
from .terminal_commands import TerminalCommands from .terminal_commands import TerminalCommands
from .fsm_aware import FSMAware

View File

@ -2,7 +2,3 @@
# All Rights Reserved. See LICENSE file for details. # All Rights Reserved. See LICENSE file for details.
from .event_handler_base import EventHandlerBase from .event_handler_base import EventHandlerBase
from .frontend_event_handler_base import FrontendEventHandlerBase
from .boradcasting_event_handler import BroadcastingEventHandler
from .fsm_aware_event_handler import FSMAwareEventHandler
from .tfw_server_connector import TFWServerUplinkConnector, TFWServerConnector

View File

@ -1,32 +0,0 @@
# Copyright (C) 2018 Avatao.com Innovative Learning Kft.
# All Rights Reserved. See LICENSE file for details.
from abc import ABC
from tfw.networking import Scope
from tfw.crypto import message_checksum
from .event_handler_base import EventHandlerBase
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.send_message(response, Scope.BROADCAST)

View File

@ -2,24 +2,24 @@
# All Rights Reserved. See LICENSE file for details. # All Rights Reserved. See LICENSE file for details.
import logging import logging
from abc import ABC, abstractmethod
from inspect import currentframe from inspect import currentframe
from typing import Iterable from typing import Iterable
from .tfw_server_connector import TFWServerConnector from tfw.networking import Scope
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
class EventHandlerBase(ABC): class EventHandlerBase:
""" """
Abstract base class for all Python based EventHandlers. Useful implementation template Abstract base class for all Python based EventHandlers. Useful implementation template
for other languages. for other languages.
Derived classes must implement the handle_event() method Derived classes must implement the handle_event() method
""" """
def __init__(self, key): def __init__(self, key, server_connector, scope=Scope.ZMQ):
self.server_connector = TFWServerConnector() self.server_connector = server_connector
self.scope = scope
self.keys = [] self.keys = []
if isinstance(key, str): if isinstance(key, str):
self.keys.append(key) self.keys.append(key)
@ -51,7 +51,7 @@ class EventHandlerBase(ABC):
self.send_message(response) self.send_message(response)
def send_message(self, message): def send_message(self, message):
self.server_connector.send_message(message) self.server_connector.send_message(message, self.scope)
def check_key(self, message): def check_key(self, message):
""" """
@ -76,7 +76,6 @@ class EventHandlerBase(ABC):
""" """
return self.handle_event(message) return self.handle_event(message)
@abstractmethod
def handle_event(self, message): def handle_event(self, message):
""" """
Abstract method that implements the handling of messages. Abstract method that implements the handling of messages.

View File

@ -1,8 +0,0 @@
from tfw.networking import Scope
from .event_handler_base import EventHandlerBase
class FrontendEventHandlerBase(EventHandlerBase): # pylint: disable=abstract-method
def send_message(self, message):
self.server_connector.send_message(message, Scope.WEBSOCKET)