import logging import os from pathlib import Path import requests from watchdog.events import PatternMatchingEventHandler from watchdog.observers.polling import PollingObserver class Watcher(PatternMatchingEventHandler): def __init__(self, watchdir: Path, notify_url: str): super().__init__(ignore_directories=True) self.watchdir = watchdir self.notify_url = notify_url self.watcher = PollingObserver() self.watcher.schedule(self, self.watchdir, recursive=True) self.logger = logging.getLogger('arec-watcher.Watcher') def start(self) -> None: self.logger.debug('Starting') self.logger.info("Montoring '%s' for new uploads, notifying to '%s'", self.watchdir, self.notify_url) self._pickup_existing() return self.watcher.start() def shutdown(self) -> None: self.logger.debug('Stopping') return self.watcher.stop() def is_datfile(self, path: Path) -> bool: return path.match('*.dat') def _pickup_existing(self): for subdir in self.watchdir.iterdir(): if not subdir.is_dir(): continue for child in subdir.iterdir(): self._process(child) def _process(self, path: Path) -> None: if not self.is_datfile(path): return basedir = path.parent sentinel = basedir / 'arec-watcher-notified' if sentinel.exists(): self.logger.debug('Ignored %s due to sentinel file present', basedir) return self.logger.info('Picked up %s', basedir) # The arec upload fails to respect the parent's ACL, # so we have to fix the permissions here. self._make_group_writable(basedir) try: result = requests.post(self.notify_url, data={'upload_dir': basedir}) result.raise_for_status() sentinel.touch(exist_ok=False) self.logger.info('Successfully notified %s about %s', self.notify_url, basedir) except requests.HTTPError as e: self.logger.error('Failed to notify %s about %s', self.notify_url, basedir, exc_info=e) def on_created(self, event): self._process(Path(event.src_path)) def on_moved(self, event): self._process(Path(event.dest_path)) def _make_group_writable(self, path: Path): # Python doesn't have any good tools for recursive permissions, # so we lean on the OS. os.system(f'chmod -R g+w {path}')