From 5823dd0e2102a75e1fe568dbab1d0ce4521a2d38 Mon Sep 17 00:00:00 2001
From: Fabio Manganiello <fabio@manganiello.tech>
Date: Mon, 4 Dec 2023 03:02:25 +0100
Subject: [PATCH] [#292] Converted `backend.log.http` to a runnable plugin.

Closes: #292
---
 docs/source/backends.rst                      |  1 -
 docs/source/platypush/backend/log.http.rst    |  5 --
 docs/source/platypush/plugins/log.http.rst    |  5 ++
 docs/source/plugins.rst                       |  1 +
 platypush/plugins/file/monitor/__init__.py    | 58 ++++++++++---------
 .../{backend => plugins}/log/__init__.py      |  0
 .../{backend => plugins}/log/http/__init__.py | 42 ++++++++------
 .../log/http/manifest.yaml                    |  6 +-
 8 files changed, 62 insertions(+), 56 deletions(-)
 delete mode 100644 docs/source/platypush/backend/log.http.rst
 create mode 100644 docs/source/platypush/plugins/log.http.rst
 rename platypush/{backend => plugins}/log/__init__.py (100%)
 rename platypush/{backend => plugins}/log/http/__init__.py (82%)
 rename platypush/{backend => plugins}/log/http/manifest.yaml (58%)

diff --git a/docs/source/backends.rst b/docs/source/backends.rst
index 2ac97b1c4..57ccfc188 100644
--- a/docs/source/backends.rst
+++ b/docs/source/backends.rst
@@ -18,7 +18,6 @@ Backends
     platypush/backend/gps.rst
     platypush/backend/http.rst
     platypush/backend/kafka.rst
-    platypush/backend/log.http.rst
     platypush/backend/mail.rst
     platypush/backend/midi.rst
     platypush/backend/music.mopidy.rst
diff --git a/docs/source/platypush/backend/log.http.rst b/docs/source/platypush/backend/log.http.rst
deleted file mode 100644
index d4504b0cd..000000000
--- a/docs/source/platypush/backend/log.http.rst
+++ /dev/null
@@ -1,5 +0,0 @@
-``log.http``
-==============================
-
-.. automodule:: platypush.backend.log.http
-    :members:
diff --git a/docs/source/platypush/plugins/log.http.rst b/docs/source/platypush/plugins/log.http.rst
new file mode 100644
index 000000000..4dbd3d67d
--- /dev/null
+++ b/docs/source/platypush/plugins/log.http.rst
@@ -0,0 +1,5 @@
+``log.http``
+============
+
+.. automodule:: platypush.plugins.log.http
+    :members:
diff --git a/docs/source/plugins.rst b/docs/source/plugins.rst
index 1b9a0cd8b..8f39bf6ef 100644
--- a/docs/source/plugins.rst
+++ b/docs/source/plugins.rst
@@ -58,6 +58,7 @@ Plugins
     platypush/plugins/lcd.i2c.rst
     platypush/plugins/light.hue.rst
     platypush/plugins/linode.rst
+    platypush/plugins/log.http.rst
     platypush/plugins/logger.rst
     platypush/plugins/luma.oled.rst
     platypush/plugins/mail.imap.rst
diff --git a/platypush/plugins/file/monitor/__init__.py b/platypush/plugins/file/monitor/__init__.py
index f8b6411c0..741658d64 100644
--- a/platypush/plugins/file/monitor/__init__.py
+++ b/platypush/plugins/file/monitor/__init__.py
@@ -8,33 +8,6 @@ from .entities.handlers import EventHandler
 from .entities.resources import MonitoredResource, MonitoredPattern, MonitoredRegex
 
 
-def event_handler_from_resource(
-    resource: Union[str, Dict[str, Any], MonitoredResource]
-) -> Optional[EventHandler]:
-    """
-    Create a file system event handler from a string, dictionary or
-    ``MonitoredResource`` resource.
-    """
-
-    if isinstance(resource, str):
-        res = MonitoredResource(resource)
-    elif isinstance(resource, dict):
-        if 'regexes' in resource or 'ignore_regexes' in resource:
-            res = MonitoredRegex(**resource)
-        elif (
-            'patterns' in resource
-            or 'ignore_patterns' in resource
-            or 'ignore_directories' in resource
-        ):
-            res = MonitoredPattern(**resource)
-        else:
-            res = MonitoredResource(**resource)
-    else:
-        return None
-
-    return EventHandler.from_resource(res)
-
-
 class FileMonitorPlugin(RunnablePlugin):
     """
     A plugin to monitor changes to files and directories.
@@ -120,16 +93,45 @@ class FileMonitorPlugin(RunnablePlugin):
 
         super().__init__(**kwargs)
         self._observer = Observer()
+        self.paths = set()
 
         for path in paths:
-            handler = event_handler_from_resource(path)
+            handler = self.event_handler_from_resource(path)
             if not handler:
                 continue
 
+            self.paths.add(handler.resource.path)
             self._observer.schedule(
                 handler, handler.resource.path, recursive=handler.resource.recursive
             )
 
+    @staticmethod
+    def event_handler_from_resource(
+        resource: Union[str, Dict[str, Any], MonitoredResource]
+    ) -> Optional[EventHandler]:
+        """
+        Create a file system event handler from a string, dictionary or
+        ``MonitoredResource`` resource.
+        """
+
+        if isinstance(resource, str):
+            res = MonitoredResource(resource)
+        elif isinstance(resource, dict):
+            if 'regexes' in resource or 'ignore_regexes' in resource:
+                res = MonitoredRegex(**resource)
+            elif (
+                'patterns' in resource
+                or 'ignore_patterns' in resource
+                or 'ignore_directories' in resource
+            ):
+                res = MonitoredPattern(**resource)
+            else:
+                res = MonitoredResource(**resource)
+        else:
+            return None
+
+        return EventHandler.from_resource(res)
+
     def stop(self):
         self._observer.stop()
         self._observer.join()
diff --git a/platypush/backend/log/__init__.py b/platypush/plugins/log/__init__.py
similarity index 100%
rename from platypush/backend/log/__init__.py
rename to platypush/plugins/log/__init__.py
diff --git a/platypush/backend/log/http/__init__.py b/platypush/plugins/log/http/__init__.py
similarity index 82%
rename from platypush/backend/log/http/__init__.py
rename to platypush/plugins/log/http/__init__.py
index 4ba1fad61..108be1b2b 100644
--- a/platypush/backend/log/http/__init__.py
+++ b/platypush/plugins/log/http/__init__.py
@@ -5,10 +5,10 @@ import re
 from dataclasses import dataclass
 from logging import getLogger
 from threading import RLock
-from typing import List, Optional, Iterable
+from typing import Optional, Iterable
 
-from platypush.backend.file.monitor import (
-    FileMonitorBackend,
+from platypush.plugins.file.monitor import (
+    FileMonitorPlugin,
     EventHandler,
     MonitoredResource,
 )
@@ -152,28 +152,32 @@ class LogEventHandler(EventHandler):
         return HttpLogEvent(logfile=file, **info)
 
 
-class LogHttpBackend(FileMonitorBackend):
+class LogHttpPlugin(FileMonitorPlugin):
     """
-    This backend can be used to monitor one or more HTTP log files (tested on Apache and Nginx) and trigger events
-    whenever a new log line is added.
+    This plugin can be used to monitor one or more HTTP log files (tested on
+    Apache and Nginx) and trigger events whenever a new log line is added.
     """
 
-    class EventHandlerFactory:
-        @staticmethod
-        def from_resource(resource: str) -> LogEventHandler:
-            resource = MonitoredResource(resource)
-            return LogEventHandler.from_resource(resource)
+    def __init__(
+        self, paths: Iterable[str], log_files: Optional[Iterable[str]] = None, **kwargs
+    ):
+        """
+        :param paths: List of log files to be monitored.
+        """
+        if log_files:
+            self.logger.warning(
+                'The log_files parameter is deprecated, use paths instead'
+            )
 
-    def __init__(self, log_files: List[str], **kwargs):
-        """
-        :param log_files: List of log files to be monitored.
-        """
-        self.log_files = {os.path.expanduser(log) for log in log_files}
-        directories = {os.path.dirname(log) for log in self.log_files}
+        paths = {os.path.expanduser(log) for log in {*paths, *(log_files or [])}}
+        directories = {os.path.dirname(log) for log in paths}
         super().__init__(paths=directories, **kwargs)
 
-        # noinspection PyProtectedMember
         handlers = self._observer._handlers
         for hndls in handlers.values():
             for hndl in hndls:
-                hndl.monitor_files(self.log_files)
+                hndl.monitor_files(paths)
+
+    @staticmethod
+    def event_handler_from_resource(resource: str) -> LogEventHandler:
+        return LogEventHandler.from_resource(MonitoredResource(resource))
diff --git a/platypush/backend/log/http/manifest.yaml b/platypush/plugins/log/http/manifest.yaml
similarity index 58%
rename from platypush/backend/log/http/manifest.yaml
rename to platypush/plugins/log/http/manifest.yaml
index 0b9cfa2c9..35d41b09c 100644
--- a/platypush/backend/log/http/manifest.yaml
+++ b/platypush/plugins/log/http/manifest.yaml
@@ -1,6 +1,6 @@
 manifest:
   events:
-    platypush.message.event.log.http.HttpLogEvent: when a new log line is created.
+    - platypush.message.event.log.http.HttpLogEvent
   install:
     apk:
       - py3-watchdog
@@ -12,5 +12,5 @@ manifest:
       - python-watchdog
     pip:
       - watchdog
-  package: platypush.backend.log.http
-  type: backend
+  package: platypush.plugins.log.http
+  type: plugin