Merge pull request #8 from avatao-content/watchdog

Watchdog
This commit is contained in:
Bokros Bálint 2018-02-13 16:32:50 +01:00 committed by GitHub
commit ddffb666be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 74 additions and 3 deletions

View File

@ -0,0 +1,35 @@
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
from tfw.networking.event_handlers.server_connector import ServerUplinkConnector
from tfw.util import RateLimiter
from tfw.config.logs import logging
log = logging.getLogger(__name__)
class WebideReloadEventHandler(FileSystemEventHandler):
def __init__(self):
super().__init__()
self.uplink = ServerUplinkConnector()
@RateLimiter(rate_per_second=5)
def on_modified(self, event):
log.debug(event)
anchor = 'anchor_webide'
self.uplink.send(anchor, {'anchor': anchor,
'data': {'command': 'reload'}})
class DirectoryMonitor:
def __init__(self, directory):
self.observer = Observer()
self.observer.schedule(WebideReloadEventHandler(), directory, recursive=True)
def watch(self):
self.observer.start()
def stop(self):
self.observer.stop()
self.observer.join()

View File

@ -3,6 +3,7 @@ from glob import glob
from tfw.util import SupervisorMixin from tfw.util import SupervisorMixin
from tfw.event_handler_base import EventHandlerBase from tfw.event_handler_base import EventHandlerBase
from tfw.components.directory_monitor import DirectoryMonitor
from tfw.config.logs import logging from tfw.config.logs import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -56,6 +57,9 @@ class SourceCodeEventHandler(EventHandlerBase, SupervisorMixin):
'select': self.select 'select': self.select
} }
self.monitor = DirectoryMonitor(directory)
self.monitor.watch() # This runs on a separate thread
def read(self, data): def read(self, data):
try: data['content'] = self.filemanager.file_contents try: data['content'] = self.filemanager.file_contents
except PermissionError: data['content'] = 'You have no permission to open that file :(' except PermissionError: data['content'] = 'You have no permission to open that file :('
@ -85,6 +89,9 @@ class SourceCodeEventHandler(EventHandlerBase, SupervisorMixin):
self.attach_fileinfo(data) self.attach_fileinfo(data)
return data_json return data_json
def cleanup(self):
self.monitor.stop()
def map_file_extension_to_language(filename): def map_file_extension_to_language(filename):
language_map = { language_map = {

View File

@ -23,6 +23,9 @@ class EventHandlerBase:
def handle_reset(self, data_json): def handle_reset(self, data_json):
return None return None
def cleanup(self):
pass
def message_other(self, anchor, data): def message_other(self, anchor, data):
message = { message = {
'anchor': anchor, 'anchor': anchor,

View File

@ -1,6 +1,8 @@
import xmlrpc.client, zmq import xmlrpc.client, zmq
from contextlib import suppress from contextlib import suppress
from xmlrpc.client import Fault as SupervisorFault from xmlrpc.client import Fault as SupervisorFault
from time import time, sleep
from functools import wraps
from tfw.config import tfwenv from tfw.config import tfwenv
@ -31,3 +33,23 @@ class SupervisorMixin:
class ZMQConnectorBase: class ZMQConnectorBase:
def __init__(self, zmq_context=None): def __init__(self, zmq_context=None):
self._zmq_context = zmq_context or zmq.Context.instance() self._zmq_context = zmq_context or zmq.Context.instance()
class RateLimiter:
def __init__(self, rate_per_second):
self.min_interval = 1 / float(rate_per_second)
self.last_call = time()
def __call__(self, fun):
@wraps(fun)
def wrapper(*args, **kwargs):
self._limit_rate()
fun(*args, **kwargs)
return wrapper
def _limit_rate(self):
since_last_call = time() - self.last_call
to_next_call = self.min_interval - since_last_call
self.last_call = time()
if to_next_call > 0:
sleep(to_next_call)

View File

@ -2,3 +2,4 @@ tornado==4.5.3
pyzmq==16.0.4 pyzmq==16.0.4
transitions==0.6.4 transitions==0.6.4
terminado==0.8.1 terminado==0.8.1
watchdog==0.8.3

View File

@ -6,6 +6,9 @@ from tfw.config import tfwenv
if __name__ == '__main__': if __name__ == '__main__':
anchor_webide = SourceCodeEventHandler('anchor_webide', tfwenv.WEBIDE_WD, 'login') eventhandlers = {SourceCodeEventHandler('anchor_webide', tfwenv.WEBIDE_WD, 'login'),
anchor_terminado = TerminadoEventHandler('anchor_terminado', 'terminado') TerminadoEventHandler('anchor_terminado', 'terminado')}
try:
IOLoop.instance().start() IOLoop.instance().start()
finally:
for eh in eventhandlers: eh.cleanup()