diff --git a/.pylintrc b/.pylintrc index 1cbae5d..961a526 100644 --- a/.pylintrc +++ b/.pylintrc @@ -6,7 +6,7 @@ disable = missing-docstring, too-few-public-methods, invalid-name [SIMILARITIES] -min-similarity-lines=6 +min-similarity-lines=7 ignore-comments=yes ignore-docstrings=yes ignore-imports=yes diff --git a/lib/tfw/builtins/__init__.py b/lib/tfw/builtins/__init__.py index c554666..b4e7178 100644 --- a/lib/tfw/builtins/__init__.py +++ b/lib/tfw/builtins/__init__.py @@ -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 .frontend_event_handler import FrontendEventHandler from .fsm_managing_event_handler import FSMManagingEventHandler from .ide_event_handler import IdeEventHandler from .log_monitoring_event_handler import LogMonitoringEventHandler from .message_sender import MessageSender -from .pipe_io_event_handler import PipeIOEventHandlerBase, PipeIOEventHandler -from .pipe_io_event_handler import TransformerPipeIOEventHandler, CommandEventHandler +#from .pipe_io_event_handler import PipeIOEventHandlerBase, PipeIOEventHandler +#from .pipe_io_event_handler import TransformerPipeIOEventHandler, CommandEventHandler from .process_managing_event_handler import ProcessManagingEventHandler from .terminal_event_handler import TerminalEventHandler diff --git a/lib/tfw/builtins/directory_snapshotting_event_handler.py b/lib/tfw/builtins/directory_snapshotting_event_handler.py index 1e8c1ea..80b6b34 100644 --- a/lib/tfw/builtins/directory_snapshotting_event_handler.py +++ b/lib/tfw/builtins/directory_snapshotting_event_handler.py @@ -9,16 +9,18 @@ from datetime import datetime from dateutil import parser as dateparser -from tfw.event_handlers import FrontendEventHandlerBase from tfw.components.snapshot_provider import SnapshotProvider from tfw.config import TFWENV +from tfw.networking import Scope + +from .event_handler import EventHandler LOG = logging.getLogger(__name__) -class DirectorySnapshottingEventHandler(FrontendEventHandlerBase): +class DirectorySnapshottingEventHandler(EventHandler): def __init__(self, key, directories, exclude_unix_patterns=None): - super().__init__(key) + super().__init__(key, scope=Scope.WEBSOCKET) self.snapshot_providers = {} self._exclude_unix_patterns = exclude_unix_patterns self.init_snapshot_providers(directories) diff --git a/lib/tfw/builtins/event_handler.py b/lib/tfw/builtins/event_handler.py new file mode 100644 index 0000000..1732044 --- /dev/null +++ b/lib/tfw/builtins/event_handler.py @@ -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) diff --git a/lib/tfw/builtins/frontend_event_handler.py b/lib/tfw/builtins/frontend_event_handler.py index 1a76abe..9e46869 100644 --- a/lib/tfw/builtins/frontend_event_handler.py +++ b/lib/tfw/builtins/frontend_event_handler.py @@ -1,16 +1,17 @@ from abc import ABC, abstractmethod from contextlib import suppress -from tfw.event_handlers import FrontendEventHandlerBase +from tfw.networking import Scope from .message_sender import MessageSender +from .event_handler import EventHandler -class FrontendEventHandler(FrontendEventHandlerBase): +class FrontendEventHandler(EventHandler): def __init__(self): frontend_keys = ('message', 'queueMessages', 'dashboard', 'console') 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): self._frontend_message_storage.save_message(message) diff --git a/lib/tfw/event_handlers/fsm_aware_event_handler.py b/lib/tfw/builtins/fsm_aware_event_handler.py similarity index 66% rename from lib/tfw/event_handlers/fsm_aware_event_handler.py rename to lib/tfw/builtins/fsm_aware_event_handler.py index 60313df..01d8410 100644 --- a/lib/tfw/event_handlers/fsm_aware_event_handler.py +++ b/lib/tfw/builtins/fsm_aware_event_handler.py @@ -3,18 +3,20 @@ from abc import ABC -from .event_handler_base import EventHandlerBase -from .fsm_aware import FSMAware +from tfw.components 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 """ Abstract base class for EventHandlers which automatically keep track of the state of the TFW FSM. """ - def __init__(self, key): - EventHandlerBase.__init__(self, key) + def __init__(self, key, scope=Scope.ZMQ): + EventHandler.__init__(self, key, scope=scope) FSMAware.__init__(self) self.subscribe('fsm_update') diff --git a/lib/tfw/builtins/fsm_managing_event_handler.py b/lib/tfw/builtins/fsm_managing_event_handler.py index 4860f5a..a4814f9 100644 --- a/lib/tfw/builtins/fsm_managing_event_handler.py +++ b/lib/tfw/builtins/fsm_managing_event_handler.py @@ -3,14 +3,15 @@ import logging -from tfw.event_handlers import FrontendEventHandlerBase from tfw.crypto import KeyManager, sign_message, verify_message from tfw.networking import Scope +from .event_handler import EventHandler + LOG = logging.getLogger(__name__) -class FSMManagingEventHandler(FrontendEventHandlerBase): +class FSMManagingEventHandler(EventHandler): """ EventHandler responsible for managing the state machine of the framework (TFW FSM). @@ -26,7 +27,7 @@ class FSMManagingEventHandler(FrontendEventHandlerBase): command. """ def __init__(self, key, fsm_type, require_signature=False): - super().__init__(key) + super().__init__(key, scope=Scope.WEBSOCKET) self.fsm = fsm_type() self._fsm_updater = FSMUpdater(self.fsm) self.auth_key = KeyManager().auth_key diff --git a/lib/tfw/builtins/ide_event_handler.py b/lib/tfw/builtins/ide_event_handler.py index f83e27c..dd257d3 100644 --- a/lib/tfw/builtins/ide_event_handler.py +++ b/lib/tfw/builtins/ide_event_handler.py @@ -4,10 +4,11 @@ import logging from tfw.networking import Scope -from tfw.event_handlers import FrontendEventHandlerBase from tfw.components import FileManager from tfw.components.inotify import InotifyObserver +from .event_handler import EventHandler + LOG = logging.getLogger(__name__) BUILD_ARTIFACTS = ( @@ -34,7 +35,7 @@ BUILD_ARTIFACTS = ( ) -class IdeEventHandler(FrontendEventHandlerBase): +class IdeEventHandler(EventHandler): # pylint: disable=too-many-arguments,anomalous-backslash-in-string """ 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 exclude: list of filenames that should not appear between files (for .o, .pyc, etc.) """ - super().__init__(key) + super().__init__(key, scope=Scope.WEBSOCKET) try: self.filemanager = FileManager( allowed_directories=allowed_directories, @@ -70,7 +71,10 @@ class IdeEventHandler(FrontendEventHandlerBase): 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.start() @@ -82,7 +86,7 @@ class IdeEventHandler(FrontendEventHandlerBase): 'exclude': self.exclude } - def _reload_frontend(self, event): + def _reload_frontend(self, event): # pylint: disable=unused-argument self.server_connector.send_message({ 'key': 'ide', 'data': {'command': 'reload'} @@ -150,7 +154,10 @@ class IdeEventHandler(FrontendEventHandlerBase): except IndexError: data['content'] = 'No files in this directory :(' 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 def exclude(self, data): diff --git a/lib/tfw/builtins/log_monitoring_event_handler.py b/lib/tfw/builtins/log_monitoring_event_handler.py index 08f916c..85699c8 100644 --- a/lib/tfw/builtins/log_monitoring_event_handler.py +++ b/lib/tfw/builtins/log_monitoring_event_handler.py @@ -4,10 +4,11 @@ import logging from tfw.networking import Scope -from tfw.event_handlers import FrontendEventHandlerBase from tfw.components.inotify import InotifyObserver from tfw.mixins.supervisor_mixin import SupervisorLogMixin +from .event_handler import EventHandler + LOG = logging.getLogger(__name__) @@ -49,7 +50,7 @@ class LogInotifyObserver(InotifyObserver, SupervisorLogMixin): }, Scope.BROADCAST) -class LogMonitoringEventHandler(FrontendEventHandlerBase): +class LogMonitoringEventHandler(EventHandler): """ Monitors the output of a supervisor process (stdout, stderr) and sends the results to the frontend. @@ -60,7 +61,7 @@ class LogMonitoringEventHandler(FrontendEventHandlerBase): The API of each command is documented in their respective handler. """ def __init__(self, key, process_name, log_tail=0): - super().__init__(key) + super().__init__(key, scope=Scope.WEBSOCKET) self.process_name = process_name self._monitor = LogInotifyObserver(self.server_connector, process_name, log_tail) self._monitor.start() diff --git a/lib/tfw/builtins/message_sender.py b/lib/tfw/builtins/message_sender.py index 4f35baa..a4ee179 100644 --- a/lib/tfw/builtins/message_sender.py +++ b/lib/tfw/builtins/message_sender.py @@ -1,7 +1,7 @@ # Copyright (C) 2018 Avatao.com Innovative Learning Kft. # All Rights Reserved. See LICENSE file for details. -from tfw.event_handlers import TFWServerUplinkConnector +from .tfw_server_connector import TFWServerUplinkConnector class MessageSender: diff --git a/lib/tfw/builtins/pipe_io_event_handler.py b/lib/tfw/builtins/pipe_io_event_handler.py index 9ab4db5..96bff90 100644 --- a/lib/tfw/builtins/pipe_io_event_handler.py +++ b/lib/tfw/builtins/pipe_io_event_handler.py @@ -10,14 +10,15 @@ from secrets import token_urlsafe from threading import Thread from contextlib import suppress -from tfw.event_handlers import EventHandlerBase from tfw.components.pipe_io_server import PipeIOServer, terminate_process_on_failure +from .event_handler import EventHandler + LOG = logging.getLogger(__name__) DEFAULT_PERMISSIONS = 0o600 -class PipeIOEventHandlerBase(EventHandlerBase): +class PipeIOEventHandlerBase(EventHandler): def __init__(self, key, in_pipe_path, out_pipe_path, permissions=DEFAULT_PERMISSIONS): super().__init__(key) self.pipe_io = CallbackPipeIOServer( diff --git a/lib/tfw/builtins/process_managing_event_handler.py b/lib/tfw/builtins/process_managing_event_handler.py index 4c7daaa..0109e7a 100644 --- a/lib/tfw/builtins/process_managing_event_handler.py +++ b/lib/tfw/builtins/process_managing_event_handler.py @@ -4,9 +4,11 @@ import logging 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 .event_handler import EventHandler + LOG = logging.getLogger(__name__) @@ -22,7 +24,7 @@ class ProcessManager(SupervisorMixin, SupervisorLogMixin): return self.commands[command](process_name) -class ProcessManagingEventHandler(FrontendEventHandlerBase): +class ProcessManagingEventHandler(EventHandler): """ 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) """ def __init__(self, key, log_tail=0): - super().__init__(key) + super().__init__(key, scope=Scope.WEBSOCKET) self.processmanager = ProcessManager() self.log_tail = log_tail diff --git a/lib/tfw/builtins/terminal_event_handler.py b/lib/tfw/builtins/terminal_event_handler.py index 6d2a14a..68a6b78 100644 --- a/lib/tfw/builtins/terminal_event_handler.py +++ b/lib/tfw/builtins/terminal_event_handler.py @@ -3,16 +3,18 @@ import logging -from tfw.event_handlers import FrontendEventHandlerBase +from tfw.networking import Scope from tfw.components import BashMonitor from tfw.components.terminado_mini_server import TerminadoMiniServer from tfw.config import TFWENV from tao.config import TAOENV +from .event_handler import EventHandler + LOG = logging.getLogger(__name__) -class TerminalEventHandler(FrontendEventHandlerBase): +class TerminalEventHandler(EventHandler): """ Event handler responsible for managing terminal sessions for frontend xterm 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 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) bash_as_user_cmd = ['sudo', '-u', TAOENV.USER, 'bash'] diff --git a/lib/tfw/event_handlers/tfw_server_connector.py b/lib/tfw/builtins/tfw_server_connector.py similarity index 100% rename from lib/tfw/event_handlers/tfw_server_connector.py rename to lib/tfw/builtins/tfw_server_connector.py diff --git a/lib/tfw/components/__init__.py b/lib/tfw/components/__init__.py index 203f7e1..75e6531 100644 --- a/lib/tfw/components/__init__.py +++ b/lib/tfw/components/__init__.py @@ -6,3 +6,4 @@ from .file_manager import FileManager from .history_monitor import HistoryMonitor, BashMonitor, GDBMonitor from .snapshot_provider import SnapshotProvider from .terminal_commands import TerminalCommands +from .fsm_aware import FSMAware diff --git a/lib/tfw/event_handlers/fsm_aware.py b/lib/tfw/components/fsm_aware.py similarity index 100% rename from lib/tfw/event_handlers/fsm_aware.py rename to lib/tfw/components/fsm_aware.py diff --git a/lib/tfw/event_handlers/__init__.py b/lib/tfw/event_handlers/__init__.py index 0327aef..447f617 100644 --- a/lib/tfw/event_handlers/__init__.py +++ b/lib/tfw/event_handlers/__init__.py @@ -2,7 +2,3 @@ # All Rights Reserved. See LICENSE file for details. 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 diff --git a/lib/tfw/event_handlers/boradcasting_event_handler.py b/lib/tfw/event_handlers/boradcasting_event_handler.py deleted file mode 100644 index c6f61a9..0000000 --- a/lib/tfw/event_handlers/boradcasting_event_handler.py +++ /dev/null @@ -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) diff --git a/lib/tfw/event_handlers/event_handler_base.py b/lib/tfw/event_handlers/event_handler_base.py index d5bb20e..cc0be96 100644 --- a/lib/tfw/event_handlers/event_handler_base.py +++ b/lib/tfw/event_handlers/event_handler_base.py @@ -2,24 +2,24 @@ # All Rights Reserved. See LICENSE file for details. import logging -from abc import ABC, abstractmethod from inspect import currentframe from typing import Iterable -from .tfw_server_connector import TFWServerConnector +from tfw.networking import Scope LOG = logging.getLogger(__name__) -class EventHandlerBase(ABC): +class EventHandlerBase: """ 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 = TFWServerConnector() + def __init__(self, key, server_connector, scope=Scope.ZMQ): + self.server_connector = server_connector + self.scope = scope self.keys = [] if isinstance(key, str): self.keys.append(key) @@ -51,7 +51,7 @@ class EventHandlerBase(ABC): self.send_message(response) def send_message(self, message): - self.server_connector.send_message(message) + self.server_connector.send_message(message, self.scope) def check_key(self, message): """ @@ -76,7 +76,6 @@ class EventHandlerBase(ABC): """ return self.handle_event(message) - @abstractmethod def handle_event(self, message): """ Abstract method that implements the handling of messages. diff --git a/lib/tfw/event_handlers/frontend_event_handler_base.py b/lib/tfw/event_handlers/frontend_event_handler_base.py deleted file mode 100644 index 6990632..0000000 --- a/lib/tfw/event_handlers/frontend_event_handler_base.py +++ /dev/null @@ -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)