mirror of
https://github.com/avatao-content/baseimage-tutorial-framework
synced 2024-12-22 12:41:55 +00:00
Rework EventHandler situation
This commit is contained in:
parent
28c3e68b5a
commit
78bd97493a
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
10
lib/tfw/builtins/event_handler.py
Normal file
10
lib/tfw/builtins/event_handler.py
Normal 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)
|
@ -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)
|
||||
|
@ -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')
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
@ -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()
|
||||
|
@ -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:
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
|
||||
|
@ -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']
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
@ -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.
|
||||
|
@ -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)
|
Loading…
Reference in New Issue
Block a user