changeset 1251:a1606e2a92eb

server: fixed watching a directory which is already watched: Twisted file watched is not adding a callback to a watched path when there is already one, but this can happens often in Libervia, as a whole site is recusively watched in dev mode, and tasks may want to add other watchers. To work around this, the new `_checkCallback` will recursively check that callback has been indeed added to the requested path.
author Goffi <goffi@goffi.org>
date Wed, 29 Apr 2020 14:54:33 +0200
parents 821b6ce57f99
children 80a92eb82b7f
files libervia/server/server.py
diffstat 1 files changed, 29 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/libervia/server/server.py	Mon Apr 27 10:55:23 2020 +0200
+++ b/libervia/server/server.py	Wed Apr 29 14:54:33 2020 +0200
@@ -90,14 +90,40 @@
             notifier.startReading()
         return self._notifier
 
+    def _checkCallback(self, dir_path, callback, recursive):
+        # Twisted doesn't add callback if a watcher was already set on a path
+        # but in dev mode Libervia watches whole sites + internal path can be watched
+        # by tasks, so several callbacks must be called on some paths.
+        # This method check that the new callback is indeed present in the desired path
+        # and add it otherwise.
+        # FIXME: this should probably be fixed upstream
+        if recursive:
+            for child in dir_path.walk():
+                if child.isdir():
+                    self._checkCallback(child, callback, recursive=False)
+        else:
+            watch_id = self.notifier._isWatched(dir_path)
+            if watch_id is None:
+                log.warning(
+                    f"There is no watch ID for path {dir_path}, this should not happen"
+                )
+            else:
+                watch_point = self.notifier._watchpoints[watch_id]
+                if callback not in watch_point.callbacks:
+                    watch_point.callbacks.append(callback)
+
     def watchDir(self, dir_path, callback, mask=DEFAULT_MASK, auto_add=False,
                  recursive=False, **kwargs):
+        dir_path = str(dir_path)
         log.info(_("Watching directory {dir_path}").format(dir_path=dir_path))
-        callbacks = [lambda __, filepath, mask: callback(self.host, filepath,
-                     inotify.humanReadableMask(mask), **kwargs)]
+        wrapped_callback = lambda __, filepath, mask: callback(
+            self.host, filepath, inotify.humanReadableMask(mask), **kwargs)
+        callbacks = [wrapped_callback]
+        dir_path = filepath.FilePath(dir_path)
         self.notifier.watch(
-            filepath.FilePath(dir_path), mask=mask, autoAdd=auto_add, recursive=recursive,
+            dir_path, mask=mask, autoAdd=auto_add, recursive=recursive,
             callbacks=callbacks)
+        self._checkCallback(dir_path, wrapped_callback, recursive)
 
 
 class LiberviaSession(server.Session):