2020-12-12 15:53:06 -05:00
|
|
|
# The base plugin class
|
|
|
|
import abc
|
|
|
|
import fnmatch
|
2020-12-17 10:00:47 -05:00
|
|
|
import importlib
|
2020-12-12 15:53:06 -05:00
|
|
|
import inspect
|
|
|
|
import logging
|
|
|
|
import os
|
|
|
|
import re
|
2021-10-08 12:01:04 -04:00
|
|
|
import textwrap
|
2021-02-18 16:31:52 -05:00
|
|
|
import threading
|
2020-12-12 15:53:06 -05:00
|
|
|
|
|
|
|
import pluggy
|
2020-12-15 07:50:10 -05:00
|
|
|
from thesmuggler import smuggle
|
2020-12-12 15:53:06 -05:00
|
|
|
|
2021-11-12 11:36:22 -05:00
|
|
|
import aprsd
|
2022-12-15 17:23:54 -05:00
|
|
|
from aprsd import client, messaging, threads
|
|
|
|
from aprsd.packets import watch_list
|
2021-08-23 14:08:14 -04:00
|
|
|
|
2021-08-23 12:14:19 -04:00
|
|
|
|
2020-12-12 15:53:06 -05:00
|
|
|
# setup the global logger
|
|
|
|
LOG = logging.getLogger("APRSD")
|
|
|
|
|
2021-07-14 20:50:41 -04:00
|
|
|
CORE_MESSAGE_PLUGINS = [
|
2021-01-09 09:58:56 -05:00
|
|
|
"aprsd.plugins.email.EmailPlugin",
|
|
|
|
"aprsd.plugins.fortune.FortunePlugin",
|
|
|
|
"aprsd.plugins.location.LocationPlugin",
|
|
|
|
"aprsd.plugins.ping.PingPlugin",
|
|
|
|
"aprsd.plugins.query.QueryPlugin",
|
|
|
|
"aprsd.plugins.time.TimePlugin",
|
2021-01-21 10:05:49 -05:00
|
|
|
"aprsd.plugins.weather.USWeatherPlugin",
|
2021-01-09 09:58:56 -05:00
|
|
|
"aprsd.plugins.version.VersionPlugin",
|
2020-12-12 15:53:06 -05:00
|
|
|
]
|
|
|
|
|
2021-07-14 20:50:41 -04:00
|
|
|
CORE_NOTIFY_PLUGINS = [
|
2021-07-17 14:30:29 -04:00
|
|
|
"aprsd.plugins.notify.NotifySeenPlugin",
|
2021-07-14 20:50:41 -04:00
|
|
|
]
|
|
|
|
|
2021-10-06 12:08:29 -04:00
|
|
|
hookspec = pluggy.HookspecMarker("aprsd")
|
|
|
|
hookimpl = pluggy.HookimplMarker("aprsd")
|
|
|
|
|
2020-12-12 15:53:06 -05:00
|
|
|
|
2021-10-06 12:08:29 -04:00
|
|
|
class APRSDPluginSpec:
|
2021-01-09 09:58:56 -05:00
|
|
|
"""A hook specification namespace."""
|
|
|
|
|
|
|
|
@hookspec
|
2021-08-19 11:39:29 -04:00
|
|
|
def filter(self, packet):
|
2021-01-09 09:58:56 -05:00
|
|
|
"""My special little hook that you can customize."""
|
|
|
|
|
|
|
|
|
2021-08-19 11:39:29 -04:00
|
|
|
class APRSDPluginBase(metaclass=abc.ABCMeta):
|
|
|
|
"""The base class for all APRSD Plugins."""
|
|
|
|
|
|
|
|
config = None
|
2021-08-20 16:25:54 -04:00
|
|
|
rx_count = 0
|
|
|
|
tx_count = 0
|
2021-11-12 11:36:22 -05:00
|
|
|
version = aprsd.__version__
|
2021-08-19 11:39:29 -04:00
|
|
|
|
2021-08-20 15:21:47 -04:00
|
|
|
# Holds the list of APRSDThreads that the plugin creates
|
|
|
|
threads = []
|
2021-09-08 14:18:49 -04:00
|
|
|
# Set this in setup()
|
|
|
|
enabled = False
|
2021-08-20 15:21:47 -04:00
|
|
|
|
2021-08-19 11:39:29 -04:00
|
|
|
def __init__(self, config):
|
|
|
|
self.config = config
|
|
|
|
self.message_counter = 0
|
|
|
|
self.setup()
|
2021-10-08 12:01:04 -04:00
|
|
|
self.threads = self.create_threads() or []
|
2021-10-06 12:08:29 -04:00
|
|
|
self.start_threads()
|
2021-08-20 15:21:47 -04:00
|
|
|
|
|
|
|
def start_threads(self):
|
2021-09-08 14:18:49 -04:00
|
|
|
if self.enabled and self.threads:
|
2021-08-20 15:21:47 -04:00
|
|
|
if not isinstance(self.threads, list):
|
|
|
|
self.threads = [self.threads]
|
|
|
|
|
|
|
|
try:
|
|
|
|
for thread in self.threads:
|
|
|
|
if isinstance(thread, threads.APRSDThread):
|
|
|
|
thread.start()
|
|
|
|
else:
|
|
|
|
LOG.error(
|
|
|
|
"Can't start thread {}:{}, Must be a child "
|
|
|
|
"of aprsd.threads.APRSDThread".format(
|
|
|
|
self,
|
|
|
|
thread,
|
|
|
|
),
|
|
|
|
)
|
|
|
|
except Exception:
|
|
|
|
LOG.error(
|
|
|
|
"Failed to start threads for plugin {}".format(
|
|
|
|
self,
|
|
|
|
),
|
|
|
|
)
|
2021-08-19 11:39:29 -04:00
|
|
|
|
|
|
|
@property
|
|
|
|
def message_count(self):
|
|
|
|
return self.message_counter
|
|
|
|
|
2021-10-08 12:01:04 -04:00
|
|
|
def help(self):
|
|
|
|
return "Help!"
|
|
|
|
|
2021-09-08 14:18:49 -04:00
|
|
|
@abc.abstractmethod
|
2021-08-19 11:39:29 -04:00
|
|
|
def setup(self):
|
|
|
|
"""Do any plugin setup here."""
|
2021-09-08 14:18:49 -04:00
|
|
|
self.enabled = True
|
2021-08-19 11:39:29 -04:00
|
|
|
|
2021-08-20 15:21:47 -04:00
|
|
|
def create_threads(self):
|
|
|
|
"""Gives the plugin writer the ability start a background thread."""
|
|
|
|
return []
|
|
|
|
|
2021-08-20 16:25:54 -04:00
|
|
|
def rx_inc(self):
|
|
|
|
self.rx_count += 1
|
|
|
|
|
|
|
|
def tx_inc(self):
|
|
|
|
self.tx_count += 1
|
|
|
|
|
2021-08-20 15:21:47 -04:00
|
|
|
def stop_threads(self):
|
|
|
|
"""Stop any threads this plugin might have created."""
|
|
|
|
for thread in self.threads:
|
|
|
|
if isinstance(thread, threads.APRSDThread):
|
|
|
|
thread.stop()
|
|
|
|
|
2021-08-19 11:39:29 -04:00
|
|
|
@abc.abstractmethod
|
2022-12-15 17:23:54 -05:00
|
|
|
def filter(self, packet):
|
2021-08-19 11:39:29 -04:00
|
|
|
pass
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
2022-12-15 17:23:54 -05:00
|
|
|
def process(self, packet):
|
2021-08-19 11:39:29 -04:00
|
|
|
"""This is called when the filter passes."""
|
|
|
|
|
|
|
|
|
|
|
|
class APRSDWatchListPluginBase(APRSDPluginBase, metaclass=abc.ABCMeta):
|
|
|
|
"""Base plugin class for all notification APRSD plugins.
|
2021-07-14 20:50:41 -04:00
|
|
|
|
|
|
|
All these plugins will get every packet seen by APRSD's
|
|
|
|
registered list of HAM callsigns in the config file's
|
|
|
|
watch_list.
|
|
|
|
|
|
|
|
When you want to 'notify' something when a packet is seen
|
|
|
|
by a particular HAM callsign, write a plugin based off of
|
|
|
|
this class.
|
|
|
|
"""
|
2021-08-24 13:31:33 -04:00
|
|
|
|
|
|
|
def setup(self):
|
|
|
|
# if we have a watch list enabled, we need to add filtering
|
|
|
|
# to enable seeing packets from the watch list.
|
|
|
|
if "watch_list" in self.config["aprsd"] and self.config["aprsd"][
|
|
|
|
"watch_list"
|
|
|
|
].get("enabled", False):
|
|
|
|
# watch list is enabled
|
|
|
|
self.enabled = True
|
|
|
|
watch_list = self.config["aprsd"]["watch_list"].get(
|
|
|
|
"callsigns",
|
|
|
|
[],
|
|
|
|
)
|
|
|
|
# make sure the timeout is set or this doesn't work
|
|
|
|
if watch_list:
|
2021-09-17 09:32:30 -04:00
|
|
|
aprs_client = client.factory.create().client
|
2021-08-24 13:31:33 -04:00
|
|
|
filter_str = "b/{}".format("/".join(watch_list))
|
|
|
|
aprs_client.set_filter(filter_str)
|
|
|
|
else:
|
|
|
|
LOG.warning("Watch list enabled, but no callsigns set.")
|
2021-07-14 20:50:41 -04:00
|
|
|
|
2021-10-06 12:08:29 -04:00
|
|
|
@hookimpl
|
2022-12-15 17:23:54 -05:00
|
|
|
def filter(self, packet):
|
2021-10-06 12:08:29 -04:00
|
|
|
result = messaging.NULL_MESSAGE
|
2021-09-08 14:18:49 -04:00
|
|
|
if self.enabled:
|
2022-12-15 17:23:54 -05:00
|
|
|
wl = watch_list.WatchList()
|
2022-12-14 22:03:21 -05:00
|
|
|
if wl.callsign_in_watchlist(packet.from_call):
|
2021-09-08 14:18:49 -04:00
|
|
|
# packet is from a callsign in the watch list
|
|
|
|
self.rx_inc()
|
2021-10-06 12:08:29 -04:00
|
|
|
try:
|
|
|
|
result = self.process(packet)
|
|
|
|
except Exception as ex:
|
|
|
|
LOG.error(
|
|
|
|
"Plugin {} failed to process packet {}".format(
|
|
|
|
self.__class__, ex,
|
|
|
|
),
|
|
|
|
)
|
2021-09-08 14:18:49 -04:00
|
|
|
if result:
|
|
|
|
self.tx_inc()
|
|
|
|
else:
|
|
|
|
LOG.warning(f"{self.__class__} plugin is not enabled")
|
2021-07-14 20:50:41 -04:00
|
|
|
|
2021-08-19 11:39:29 -04:00
|
|
|
return result
|
2021-07-14 20:50:41 -04:00
|
|
|
|
|
|
|
|
2021-08-19 11:39:29 -04:00
|
|
|
class APRSDRegexCommandPluginBase(APRSDPluginBase, metaclass=abc.ABCMeta):
|
2021-07-14 20:50:41 -04:00
|
|
|
"""Base Message plugin class.
|
|
|
|
|
|
|
|
When you want to search for a particular command in an
|
|
|
|
APRSD message and send a direct reply, write a plugin
|
|
|
|
based off of this class.
|
|
|
|
"""
|
|
|
|
|
2021-01-09 09:58:56 -05:00
|
|
|
@property
|
|
|
|
def command_name(self):
|
|
|
|
"""The usage string help."""
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
@property
|
|
|
|
def command_regex(self):
|
|
|
|
"""The regex to match from the caller"""
|
|
|
|
raise NotImplementedError
|
|
|
|
|
2021-10-08 12:01:04 -04:00
|
|
|
def help(self):
|
|
|
|
return "{}: {}".format(
|
|
|
|
self.command_name.lower(),
|
|
|
|
self.command_regex,
|
|
|
|
)
|
|
|
|
|
2021-09-08 14:18:49 -04:00
|
|
|
def setup(self):
|
|
|
|
"""Do any plugin setup here."""
|
|
|
|
self.enabled = True
|
|
|
|
|
2021-01-09 09:58:56 -05:00
|
|
|
@hookimpl
|
2022-12-15 17:23:54 -05:00
|
|
|
def filter(self, packet):
|
2021-09-08 14:45:15 -04:00
|
|
|
result = None
|
|
|
|
|
|
|
|
message = packet.get("message_text", None)
|
|
|
|
msg_format = packet.get("format", None)
|
|
|
|
tocall = packet.get("addresse", None)
|
|
|
|
|
|
|
|
# Only process messages destined for us
|
|
|
|
# and is an APRS message format and has a message.
|
|
|
|
if (
|
|
|
|
tocall == self.config["aprs"]["login"]
|
|
|
|
and msg_format == "message"
|
|
|
|
and message
|
|
|
|
):
|
|
|
|
if re.search(self.command_regex, message):
|
|
|
|
self.rx_inc()
|
|
|
|
if self.enabled:
|
2021-10-06 12:08:29 -04:00
|
|
|
try:
|
|
|
|
result = self.process(packet)
|
|
|
|
except Exception as ex:
|
|
|
|
LOG.error(
|
|
|
|
"Plugin {} failed to process packet {}".format(
|
|
|
|
self.__class__, ex,
|
|
|
|
),
|
|
|
|
)
|
2021-10-08 12:01:04 -04:00
|
|
|
LOG.exception(ex)
|
2021-09-08 14:18:49 -04:00
|
|
|
if result:
|
|
|
|
self.tx_inc()
|
2021-09-08 14:45:15 -04:00
|
|
|
else:
|
2021-11-10 11:01:10 -05:00
|
|
|
result = f"{self.__class__.__name__} isn't enabled"
|
|
|
|
LOG.warning(result)
|
2021-08-19 11:39:29 -04:00
|
|
|
|
|
|
|
return result
|
2021-01-09 09:58:56 -05:00
|
|
|
|
|
|
|
|
2021-11-10 11:01:10 -05:00
|
|
|
class APRSFIKEYMixin:
|
|
|
|
"""Mixin class to enable checking the existence of the aprs.fi apiKey."""
|
|
|
|
|
|
|
|
def ensure_aprs_fi_key(self):
|
|
|
|
try:
|
|
|
|
self.config.check_option(["services", "aprs.fi", "apiKey"])
|
|
|
|
self.enabled = True
|
|
|
|
except Exception as ex:
|
|
|
|
LOG.error(f"Failed to find config aprs.fi:apikey {ex}")
|
|
|
|
self.enabled = False
|
|
|
|
|
|
|
|
|
2021-10-08 12:01:04 -04:00
|
|
|
class HelpPlugin(APRSDRegexCommandPluginBase):
|
|
|
|
"""Help Plugin that is always enabled.
|
|
|
|
|
|
|
|
This plugin is in this file to prevent a circular import.
|
|
|
|
"""
|
|
|
|
|
|
|
|
version = "1.0"
|
|
|
|
command_regex = "^[hH]"
|
|
|
|
command_name = "help"
|
|
|
|
|
|
|
|
def help(self):
|
|
|
|
return "Help: send APRS help or help <plugin>"
|
|
|
|
|
2022-12-15 17:23:54 -05:00
|
|
|
def process(self, packet):
|
2021-10-08 12:01:04 -04:00
|
|
|
LOG.info("HelpPlugin")
|
|
|
|
# fromcall = packet.get("from")
|
2022-12-14 22:03:21 -05:00
|
|
|
message = packet.message_text
|
2021-10-08 12:01:04 -04:00
|
|
|
# ack = packet.get("msgNo", "0")
|
|
|
|
a = re.search(r"^.*\s+(.*)", message)
|
|
|
|
command_name = None
|
|
|
|
if a is not None:
|
|
|
|
command_name = a.group(1).lower()
|
|
|
|
|
|
|
|
pm = PluginManager()
|
|
|
|
|
|
|
|
if command_name and "?" not in command_name:
|
|
|
|
# user wants help for a specific plugin
|
|
|
|
reply = None
|
|
|
|
for p in pm.get_plugins():
|
|
|
|
if (
|
|
|
|
p.enabled and isinstance(p, APRSDRegexCommandPluginBase)
|
|
|
|
and p.command_name.lower() == command_name
|
|
|
|
):
|
|
|
|
reply = p.help()
|
|
|
|
|
|
|
|
if reply:
|
|
|
|
return reply
|
|
|
|
|
|
|
|
list = []
|
|
|
|
for p in pm.get_plugins():
|
|
|
|
LOG.debug(p)
|
|
|
|
if p.enabled and isinstance(p, APRSDRegexCommandPluginBase):
|
|
|
|
name = p.command_name.lower()
|
|
|
|
if name not in list and "help" not in name:
|
|
|
|
list.append(name)
|
|
|
|
|
|
|
|
list.sort()
|
|
|
|
reply = " ".join(list)
|
|
|
|
lines = textwrap.wrap(reply, 60)
|
|
|
|
replies = ["Send APRS MSG of 'help' or 'help <plugin>'"]
|
|
|
|
for line in lines:
|
|
|
|
replies.append(f"plugins: {line}")
|
|
|
|
|
|
|
|
for entry in replies:
|
|
|
|
LOG.debug(f"{len(entry)} {entry}")
|
|
|
|
|
|
|
|
LOG.debug(f"{replies}")
|
|
|
|
return replies
|
|
|
|
|
|
|
|
|
2021-01-08 15:47:30 -05:00
|
|
|
class PluginManager:
|
2020-12-17 10:00:47 -05:00
|
|
|
# The singleton instance object for this class
|
|
|
|
_instance = None
|
2020-12-12 15:53:06 -05:00
|
|
|
|
2021-07-14 20:50:41 -04:00
|
|
|
# the pluggy PluginManager for all Message plugins
|
2021-08-19 11:39:29 -04:00
|
|
|
_pluggy_pm = None
|
2020-12-12 15:53:06 -05:00
|
|
|
|
2020-12-17 10:00:47 -05:00
|
|
|
# aprsd config dict
|
|
|
|
config = None
|
2020-12-12 15:53:06 -05:00
|
|
|
|
2021-02-18 16:31:52 -05:00
|
|
|
lock = None
|
|
|
|
|
2020-12-17 10:00:47 -05:00
|
|
|
def __new__(cls, *args, **kwargs):
|
|
|
|
"""This magic turns this into a singleton."""
|
|
|
|
if cls._instance is None:
|
2021-01-08 15:47:30 -05:00
|
|
|
cls._instance = super().__new__(cls)
|
2020-12-17 10:00:47 -05:00
|
|
|
# Put any initialization here.
|
2021-02-18 16:31:52 -05:00
|
|
|
cls._instance.lock = threading.Lock()
|
2020-12-17 10:00:47 -05:00
|
|
|
return cls._instance
|
2020-12-12 15:53:06 -05:00
|
|
|
|
2020-12-17 10:00:47 -05:00
|
|
|
def __init__(self, config=None):
|
2020-12-12 15:53:06 -05:00
|
|
|
self.obj_list = []
|
2020-12-17 10:00:47 -05:00
|
|
|
if config:
|
|
|
|
self.config = config
|
|
|
|
|
2021-10-06 12:08:29 -04:00
|
|
|
def _init(self):
|
|
|
|
self._pluggy_pm = pluggy.PluginManager("aprsd")
|
|
|
|
self._pluggy_pm.add_hookspecs(APRSDPluginSpec)
|
|
|
|
|
2020-12-17 10:00:47 -05:00
|
|
|
def load_plugins_from_path(self, module_path):
|
|
|
|
if not os.path.exists(module_path):
|
2021-08-23 12:14:19 -04:00
|
|
|
LOG.error(f"plugin path '{module_path}' doesn't exist.")
|
2020-12-17 10:00:47 -05:00
|
|
|
return None
|
2020-12-12 15:53:06 -05:00
|
|
|
|
2020-12-15 09:30:10 -05:00
|
|
|
dir_path = os.path.realpath(module_path)
|
2020-12-12 15:53:06 -05:00
|
|
|
pattern = "*.py"
|
|
|
|
|
|
|
|
self.obj_list = []
|
|
|
|
|
2021-01-06 17:50:02 -05:00
|
|
|
for path, _subdirs, files in os.walk(dir_path):
|
2020-12-12 15:53:06 -05:00
|
|
|
for name in files:
|
|
|
|
if fnmatch.fnmatch(name, pattern):
|
2021-08-23 12:14:19 -04:00
|
|
|
LOG.debug(f"MODULE? '{name}' '{path}'")
|
|
|
|
module = smuggle(f"{path}/{name}")
|
2020-12-12 15:53:06 -05:00
|
|
|
for mem_name, obj in inspect.getmembers(module):
|
2020-12-15 07:50:10 -05:00
|
|
|
if inspect.isclass(obj) and self.is_plugin(obj):
|
2020-12-13 21:31:01 -05:00
|
|
|
self.obj_list.append(
|
2021-01-08 15:47:30 -05:00
|
|
|
{"name": mem_name, "obj": obj(self.config)},
|
2020-12-13 21:31:01 -05:00
|
|
|
)
|
2020-12-12 15:53:06 -05:00
|
|
|
|
|
|
|
return self.obj_list
|
|
|
|
|
|
|
|
def is_plugin(self, obj):
|
|
|
|
for c in inspect.getmro(obj):
|
2021-08-19 11:39:29 -04:00
|
|
|
if issubclass(c, APRSDPluginBase):
|
2020-12-12 15:53:06 -05:00
|
|
|
return True
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
2021-08-19 11:39:29 -04:00
|
|
|
def _create_class(
|
|
|
|
self,
|
|
|
|
module_class_string,
|
|
|
|
super_cls: type = None,
|
|
|
|
**kwargs,
|
|
|
|
):
|
2020-12-17 10:00:47 -05:00
|
|
|
"""
|
|
|
|
Method to create a class from a fqn python string.
|
2021-08-20 15:21:47 -04:00
|
|
|
:param module_class_string: full name of the class to create an object
|
2020-12-17 10:00:47 -05:00
|
|
|
:param super_cls: expected super class for validity, None if bypass
|
|
|
|
:param kwargs: parameters to pass
|
|
|
|
:return:
|
|
|
|
"""
|
|
|
|
module_name, class_name = module_class_string.rsplit(".", 1)
|
|
|
|
try:
|
|
|
|
module = importlib.import_module(module_name)
|
2021-02-18 16:31:52 -05:00
|
|
|
module = importlib.reload(module)
|
2020-12-17 10:00:47 -05:00
|
|
|
except Exception as ex:
|
2021-08-23 12:14:19 -04:00
|
|
|
LOG.error(f"Failed to load Plugin '{module_name}' : '{ex}'")
|
2020-12-17 10:00:47 -05:00
|
|
|
return
|
|
|
|
|
|
|
|
assert hasattr(module, class_name), "class {} is not in {}".format(
|
2021-01-08 15:47:30 -05:00
|
|
|
class_name,
|
|
|
|
module_name,
|
2020-12-17 10:00:47 -05:00
|
|
|
)
|
|
|
|
# click.echo('reading class {} from module {}'.format(
|
|
|
|
# class_name, module_name))
|
|
|
|
cls = getattr(module, class_name)
|
|
|
|
if super_cls is not None:
|
|
|
|
assert issubclass(cls, super_cls), "class {} should inherit from {}".format(
|
2021-01-08 15:47:30 -05:00
|
|
|
class_name,
|
|
|
|
super_cls.__name__,
|
2020-12-17 10:00:47 -05:00
|
|
|
)
|
|
|
|
# click.echo('initialising {} with params {}'.format(class_name, kwargs))
|
|
|
|
obj = cls(**kwargs)
|
|
|
|
return obj
|
|
|
|
|
2021-08-19 11:39:29 -04:00
|
|
|
def _load_plugin(self, plugin_name):
|
2021-07-14 20:50:41 -04:00
|
|
|
"""
|
|
|
|
Given a python fully qualified class path.name,
|
|
|
|
Try importing the path, then creating the object,
|
|
|
|
then registering it as a aprsd Command Plugin
|
|
|
|
"""
|
|
|
|
plugin_obj = None
|
|
|
|
try:
|
|
|
|
plugin_obj = self._create_class(
|
|
|
|
plugin_name,
|
2021-08-19 11:39:29 -04:00
|
|
|
APRSDPluginBase,
|
2021-07-14 20:50:41 -04:00
|
|
|
config=self.config,
|
|
|
|
)
|
|
|
|
if plugin_obj:
|
|
|
|
LOG.info(
|
2021-08-19 11:39:29 -04:00
|
|
|
"Registering plugin '{}'({})".format(
|
2021-07-14 20:50:41 -04:00
|
|
|
plugin_name,
|
|
|
|
plugin_obj.version,
|
|
|
|
),
|
|
|
|
)
|
2021-08-19 11:39:29 -04:00
|
|
|
self._pluggy_pm.register(plugin_obj)
|
2020-12-17 10:00:47 -05:00
|
|
|
except Exception as ex:
|
2022-01-26 14:29:37 -05:00
|
|
|
LOG.error(f"Couldn't load plugin '{plugin_name}'")
|
|
|
|
LOG.exception(ex)
|
2020-12-17 10:00:47 -05:00
|
|
|
|
2021-02-18 16:31:52 -05:00
|
|
|
def reload_plugins(self):
|
|
|
|
with self.lock:
|
2021-08-19 11:39:29 -04:00
|
|
|
del self._pluggy_pm
|
2021-02-18 16:31:52 -05:00
|
|
|
self.setup_plugins()
|
|
|
|
|
2020-12-17 10:00:47 -05:00
|
|
|
def setup_plugins(self):
|
|
|
|
"""Create the plugin manager and register plugins."""
|
|
|
|
|
2021-08-19 11:39:29 -04:00
|
|
|
LOG.info("Loading APRSD Plugins")
|
2021-10-06 12:08:29 -04:00
|
|
|
self._init()
|
2021-10-08 12:01:04 -04:00
|
|
|
# Help plugin is always enabled.
|
|
|
|
_help = HelpPlugin(self.config)
|
|
|
|
self._pluggy_pm.register(_help)
|
|
|
|
|
|
|
|
enabled_plugins = self.config["aprsd"].get("enabled_plugins", None)
|
2021-08-19 11:39:29 -04:00
|
|
|
if enabled_plugins:
|
|
|
|
for p_name in enabled_plugins:
|
|
|
|
self._load_plugin(p_name)
|
2020-12-17 10:00:47 -05:00
|
|
|
else:
|
|
|
|
# Enabled plugins isn't set, so we default to loading all of
|
|
|
|
# the core plugins.
|
2021-07-14 20:50:41 -04:00
|
|
|
for p_name in CORE_MESSAGE_PLUGINS:
|
2020-12-17 10:00:47 -05:00
|
|
|
self._load_plugin(p_name)
|
|
|
|
|
2021-07-14 20:50:41 -04:00
|
|
|
if self.config["aprsd"]["watch_list"].get("enabled", False):
|
2021-08-19 11:39:29 -04:00
|
|
|
LOG.info("Loading APRSD WatchList Plugins")
|
2021-07-14 20:50:41 -04:00
|
|
|
enabled_notify_plugins = self.config["aprsd"]["watch_list"].get(
|
|
|
|
"enabled_plugins",
|
|
|
|
None,
|
|
|
|
)
|
|
|
|
if enabled_notify_plugins:
|
|
|
|
for p_name in enabled_notify_plugins:
|
2021-08-19 11:39:29 -04:00
|
|
|
self._load_plugin(p_name)
|
2020-12-17 10:00:47 -05:00
|
|
|
LOG.info("Completed Plugin Loading.")
|
|
|
|
|
2022-12-15 17:23:54 -05:00
|
|
|
def run(self, packet):
|
2020-12-17 10:00:47 -05:00
|
|
|
"""Execute all the pluguns run method."""
|
2021-02-18 16:31:52 -05:00
|
|
|
with self.lock:
|
2021-08-19 11:39:29 -04:00
|
|
|
return self._pluggy_pm.hook.filter(packet=packet)
|
2020-12-17 10:00:47 -05:00
|
|
|
|
2021-10-08 12:01:04 -04:00
|
|
|
def stop(self):
|
|
|
|
"""Stop all threads created by all plugins."""
|
|
|
|
with self.lock:
|
|
|
|
for p in self.get_plugins():
|
2021-10-10 14:50:04 -04:00
|
|
|
if hasattr(p, "stop_threads"):
|
|
|
|
p.stop_threads()
|
2021-10-08 12:01:04 -04:00
|
|
|
|
2021-07-14 20:50:41 -04:00
|
|
|
def register_msg(self, obj):
|
2020-12-17 10:00:47 -05:00
|
|
|
"""Register the plugin."""
|
2021-08-19 11:39:29 -04:00
|
|
|
self._pluggy_pm.register(obj)
|
2020-12-17 10:00:47 -05:00
|
|
|
|
2021-08-19 11:39:29 -04:00
|
|
|
def get_plugins(self):
|
2022-07-20 08:43:57 -04:00
|
|
|
if self._pluggy_pm:
|
|
|
|
return self._pluggy_pm.get_plugins()
|