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]
min-similarity-lines=6
min-similarity-lines=7
ignore-comments=yes
ignore-docstrings=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 .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

View File

@ -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)

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 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)

View File

@ -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')

View File

@ -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

View File

@ -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):

View File

@ -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()

View File

@ -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:

View File

@ -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(

View File

@ -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

View File

@ -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']

View File

@ -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

View File

@ -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

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.
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.

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)