mirror of
				https://github.com/avatao-content/baseimage-tutorial-framework
				synced 2025-11-04 12:52:54 +00:00 
			
		
		
		
	Replace mixins with inotify based observers
This commit is contained in:
		@@ -2,20 +2,29 @@
 | 
			
		||||
# All Rights Reserved. See LICENSE file for details.
 | 
			
		||||
 | 
			
		||||
import logging
 | 
			
		||||
from os.path import isfile, join, relpath, exists, isdir, realpath
 | 
			
		||||
from glob import glob
 | 
			
		||||
from fnmatch import fnmatchcase
 | 
			
		||||
from typing import Iterable
 | 
			
		||||
 | 
			
		||||
from tfw.event_handlers import FrontendEventHandlerBase
 | 
			
		||||
from tfw.mixins.monitor_manager_mixin import MonitorManagerMixin
 | 
			
		||||
from tfw.networking import Scope
 | 
			
		||||
from tfw.event_handlers import FrontendEventHandlerBase, TFWServerUplinkConnector
 | 
			
		||||
from tfw.components import FileManager
 | 
			
		||||
from tfw.components.directory_monitor import DirectoryMonitor
 | 
			
		||||
from tfw.components.inotify import InotifyObserver
 | 
			
		||||
 | 
			
		||||
LOG = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class IdeEventHandler(FrontendEventHandlerBase, MonitorManagerMixin):
 | 
			
		||||
class IdeInotifyObserver(InotifyObserver):
 | 
			
		||||
    def __init__(self, paths):
 | 
			
		||||
        self.uplink = TFWServerUplinkConnector()
 | 
			
		||||
        super().__init__(paths)
 | 
			
		||||
 | 
			
		||||
    def on_modified(self, event):
 | 
			
		||||
        LOG.debug(event)
 | 
			
		||||
        self.uplink.send_message({
 | 
			
		||||
            'key': 'ide',
 | 
			
		||||
            'data': {'command': 'reload'}
 | 
			
		||||
        }, Scope.WEBSOCKET)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class IdeEventHandler(FrontendEventHandlerBase):
 | 
			
		||||
    # pylint: disable=too-many-arguments,anomalous-backslash-in-string
 | 
			
		||||
    """
 | 
			
		||||
    Event handler implementing the backend of our browser based IDE.
 | 
			
		||||
@@ -51,12 +60,8 @@ class IdeEventHandler(FrontendEventHandlerBase, MonitorManagerMixin):
 | 
			
		||||
                f'No file(s) in IdeEventHandler working_directory "{directory}"!'
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        MonitorManagerMixin.__init__(
 | 
			
		||||
            self,
 | 
			
		||||
            DirectoryMonitor,
 | 
			
		||||
            self.key,
 | 
			
		||||
            self.filemanager.allowed_directories
 | 
			
		||||
        )
 | 
			
		||||
        self.monitor = IdeInotifyObserver(self.filemanager.allowed_directories)
 | 
			
		||||
        self.monitor.start()
 | 
			
		||||
 | 
			
		||||
        self.commands = {
 | 
			
		||||
            'read':      self.read,
 | 
			
		||||
@@ -91,7 +96,6 @@ class IdeEventHandler(FrontendEventHandlerBase, MonitorManagerMixin):
 | 
			
		||||
                     (new file content)
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        self.monitor.ignore = self.monitor.ignore + 1
 | 
			
		||||
        try:
 | 
			
		||||
            self.filemanager.file_contents = data['content']
 | 
			
		||||
        except Exception: # pylint: disable=broad-except
 | 
			
		||||
@@ -123,7 +127,6 @@ class IdeEventHandler(FrontendEventHandlerBase, MonitorManagerMixin):
 | 
			
		||||
        """
 | 
			
		||||
        try:
 | 
			
		||||
            self.filemanager.workdir = data['directory']
 | 
			
		||||
            self.reload_monitor()
 | 
			
		||||
            try:
 | 
			
		||||
                self.filemanager.filename = self.filemanager.files[0]
 | 
			
		||||
                self.read(data)
 | 
			
		||||
 
 | 
			
		||||
@@ -3,14 +3,57 @@
 | 
			
		||||
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
from tfw.event_handlers import FrontendEventHandlerBase
 | 
			
		||||
from tfw.mixins.monitor_manager_mixin import MonitorManagerMixin
 | 
			
		||||
from tfw.components.log_monitor import LogMonitor
 | 
			
		||||
from os.path import dirname
 | 
			
		||||
from tfw.networking import Scope
 | 
			
		||||
from tfw.event_handlers import FrontendEventHandlerBase, TFWServerUplinkConnector
 | 
			
		||||
from tfw.components.inotify import InotifyObserver
 | 
			
		||||
from tfw.mixins.supervisor_mixin import SupervisorLogMixin
 | 
			
		||||
 | 
			
		||||
LOG = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LogMonitoringEventHandler(FrontendEventHandlerBase, MonitorManagerMixin):
 | 
			
		||||
class LogInotifyObserver(InotifyObserver, SupervisorLogMixin):
 | 
			
		||||
    def __init__(self, process_name, log_tail=0):
 | 
			
		||||
        self.prevent_log_recursion()
 | 
			
		||||
        self.uplink = TFWServerUplinkConnector()
 | 
			
		||||
        self.process_name = process_name
 | 
			
		||||
        self.log_tail = log_tail
 | 
			
		||||
        self.procinfo = self.supervisor.getProcessInfo(self.process_name)
 | 
			
		||||
        super().__init__(
 | 
			
		||||
            [dirname(self.procinfo['stdout_logfile']), dirname(self.procinfo['stderr_logfile'])],
 | 
			
		||||
            [self.procinfo['stdout_logfile'], self.procinfo['stderr_logfile']]
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def reset(self, process_name, log_tail):
 | 
			
		||||
        self.process_name = process_name
 | 
			
		||||
        self.log_tail = log_tail
 | 
			
		||||
        self.procinfo = self.supervisor.getProcessInfo(self.process_name)
 | 
			
		||||
        self.paths = [
 | 
			
		||||
            dirname(self.procinfo['stdout_logfile']),
 | 
			
		||||
            dirname(self.procinfo['stderr_logfile'])
 | 
			
		||||
        ]
 | 
			
		||||
        self.patterns = [
 | 
			
		||||
            self.procinfo['stdout_logfile'],
 | 
			
		||||
            self.procinfo['stderr_logfile']
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
    def on_modified(self, event):
 | 
			
		||||
        self.uplink.send_message({
 | 
			
		||||
            'key': 'processlog',
 | 
			
		||||
            'data': {
 | 
			
		||||
                'command': 'new_log',
 | 
			
		||||
                'stdout': self.read_stdout(self.process_name, tail=self.log_tail),
 | 
			
		||||
                'stderr': self.read_stderr(self.process_name, tail=self.log_tail)
 | 
			
		||||
            }
 | 
			
		||||
        }, Scope.BROADCAST)
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def prevent_log_recursion():
 | 
			
		||||
        # This is done to prevent inotify event logs triggering themselves (infinite log recursion)
 | 
			
		||||
        logging.getLogger('watchdog.observers.inotify_buffer').propagate = False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LogMonitoringEventHandler(FrontendEventHandlerBase):
 | 
			
		||||
    """
 | 
			
		||||
    Monitors the output of a supervisor process (stdout, stderr) and
 | 
			
		||||
    sends the results to the frontend.
 | 
			
		||||
@@ -24,12 +67,8 @@ class LogMonitoringEventHandler(FrontendEventHandlerBase, MonitorManagerMixin):
 | 
			
		||||
        super().__init__(key)
 | 
			
		||||
        self.process_name = process_name
 | 
			
		||||
        self.log_tail = log_tail
 | 
			
		||||
        MonitorManagerMixin.__init__(
 | 
			
		||||
            self,
 | 
			
		||||
            LogMonitor,
 | 
			
		||||
            self.process_name,
 | 
			
		||||
            self.log_tail
 | 
			
		||||
        )
 | 
			
		||||
        self.monitor = LogInotifyObserver(process_name, log_tail)
 | 
			
		||||
        self.monitor.start()
 | 
			
		||||
 | 
			
		||||
        self.command_handlers = {
 | 
			
		||||
            'process_name': self.handle_process_name,
 | 
			
		||||
@@ -40,7 +79,6 @@ class LogMonitoringEventHandler(FrontendEventHandlerBase, MonitorManagerMixin):
 | 
			
		||||
        try:
 | 
			
		||||
            data = message['data']
 | 
			
		||||
            self.command_handlers[data['command']](data)
 | 
			
		||||
            self.reload_monitor()
 | 
			
		||||
        except KeyError:
 | 
			
		||||
            LOG.error('IGNORING MESSAGE: Invalid message received: %s', message)
 | 
			
		||||
 | 
			
		||||
@@ -51,7 +89,7 @@ class LogMonitoringEventHandler(FrontendEventHandlerBase, MonitorManagerMixin):
 | 
			
		||||
        :param data: TFW message data containing 'value'
 | 
			
		||||
                     (name of the process to monitor)
 | 
			
		||||
        """
 | 
			
		||||
        self.set_monitor_args(data['value'], self.log_tail)
 | 
			
		||||
        self.monitor.reset(data['value'], self.log_tail)
 | 
			
		||||
 | 
			
		||||
    def handle_log_tail(self, data):
 | 
			
		||||
        """
 | 
			
		||||
@@ -62,7 +100,7 @@ class LogMonitoringEventHandler(FrontendEventHandlerBase, MonitorManagerMixin):
 | 
			
		||||
        :param data: TFW message data containing 'value'
 | 
			
		||||
                     (new tail length)
 | 
			
		||||
        """
 | 
			
		||||
        self.set_monitor_args(self.process_name, data['value'])
 | 
			
		||||
        self.monitor.reset(self.process_name, data['value'])
 | 
			
		||||
 | 
			
		||||
    def cleanup(self):
 | 
			
		||||
        self.monitor.stop()
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,6 @@ from xmlrpc.client import Fault as SupervisorFault
 | 
			
		||||
 | 
			
		||||
from tfw.event_handlers import FrontendEventHandlerBase
 | 
			
		||||
from tfw.mixins.supervisor_mixin import SupervisorMixin, SupervisorLogMixin
 | 
			
		||||
from tfw.components.directory_monitor import with_monitor_paused
 | 
			
		||||
 | 
			
		||||
LOG = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
@@ -36,13 +35,11 @@ class ProcessManagingEventHandler(FrontendEventHandlerBase):
 | 
			
		||||
    Commands available: start, stop, restart, readlog
 | 
			
		||||
    (the names are as self-documenting as it gets)
 | 
			
		||||
    """
 | 
			
		||||
    def __init__(self, key, dirmonitor=None, log_tail=0):
 | 
			
		||||
    def __init__(self, key, log_tail=0):
 | 
			
		||||
        super().__init__(key)
 | 
			
		||||
        self.monitor = dirmonitor
 | 
			
		||||
        self.processmanager = ProcessManager()
 | 
			
		||||
        self.log_tail = log_tail
 | 
			
		||||
 | 
			
		||||
    @with_monitor_paused
 | 
			
		||||
    def handle_event(self, message):
 | 
			
		||||
        try:
 | 
			
		||||
            data = message['data']
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user