diff --git a/aprsd/aprsd.py b/aprsd/aprsd.py index 3530cd4..5d5587c 100644 --- a/aprsd/aprsd.py +++ b/aprsd/aprsd.py @@ -67,7 +67,8 @@ def main(): # First import all the possible commands for the CLI # The commands themselves live in the cmds directory from .cmds import ( # noqa - completion, dev, healthcheck, listen, send_message, server, + completion, dev, healthcheck, list_plugins, listen, send_message, + server, ) cli() diff --git a/aprsd/cmds/list_plugins.py b/aprsd/cmds/list_plugins.py new file mode 100644 index 0000000..94d51e9 --- /dev/null +++ b/aprsd/cmds/list_plugins.py @@ -0,0 +1,59 @@ +import inspect +import logging +from textwrap import indent + +import click +from tabulate import tabulate + +from aprsd import cli_helper, plugin +from aprsd.plugins import ( + email, fortune, location, notify, ping, query, time, version, weather, +) + +from ..aprsd import cli + + +LOG = logging.getLogger("APRSD") + + +@cli.command() +@cli_helper.add_options(cli_helper.common_options) +@click.pass_context +@cli_helper.process_standard_options_no_config +def list_plugins(ctx): + """List the built in plugins available to APRSD.""" + + modules = [email, fortune, location, notify, ping, query, time, version, weather] + plugins = [] + + for module in modules: + entries = inspect.getmembers(module, inspect.isclass) + for entry in entries: + cls = entry[1] + if issubclass(cls, plugin.APRSDPluginBase): + info = { + "name": cls.__qualname__, + "path": f"{cls.__module__}.{cls.__qualname__}", + "version": cls.version, + "docstring": cls.__doc__, + "short_desc": cls.short_description, + } + + if issubclass(cls, plugin.APRSDRegexCommandPluginBase): + info["command_regex"] = cls.command_regex + info["type"] = "RegexCommand" + + if issubclass(cls, plugin.APRSDWatchListPluginBase): + info["type"] = "WatchList" + + plugins.append(info) + + lines = [] + headers = ("Plugin Name", "Plugin Path", "Type", "Info") + + for entry in plugins: + lines.append( + (entry["name"], entry["path"], entry["type"], entry["short_desc"]), + ) + + click.echo(indent(tabulate(lines, headers, disable_numparse=True), " ")) diff --git a/aprsd/plugin.py b/aprsd/plugin.py index cc3b85c..53acec1 100644 --- a/aprsd/plugin.py +++ b/aprsd/plugin.py @@ -12,6 +12,7 @@ import threading import pluggy from thesmuggler import smuggle +import aprsd from aprsd import client, messaging, packets, threads @@ -51,7 +52,7 @@ class APRSDPluginBase(metaclass=abc.ABCMeta): config = None rx_count = 0 tx_count = 0 - version = "1.0" + version = aprsd.__version__ # Holds the list of APRSDThreads that the plugin creates threads = [] diff --git a/aprsd/plugins/email.py b/aprsd/plugins/email.py index 029be53..4a0d0f4 100644 --- a/aprsd/plugins/email.py +++ b/aprsd/plugins/email.py @@ -59,9 +59,9 @@ class EmailInfo: class EmailPlugin(plugin.APRSDRegexCommandPluginBase): """Email Plugin.""" - version = "1.0" command_regex = "^-.*" command_name = "email" + short_description = "Send and Receive email" # message_number:time combos so we don't resend the same email in # five mins {int:int} diff --git a/aprsd/plugins/fortune.py b/aprsd/plugins/fortune.py index f76ad56..b30fc73 100644 --- a/aprsd/plugins/fortune.py +++ b/aprsd/plugins/fortune.py @@ -11,9 +11,9 @@ LOG = logging.getLogger("APRSD") class FortunePlugin(plugin.APRSDRegexCommandPluginBase): """Fortune.""" - version = "1.0" command_regex = "^[fF]" command_name = "fortune" + short_description = "Give me a fortune" fortune_path = None diff --git a/aprsd/plugins/location.py b/aprsd/plugins/location.py index a0381d9..939661b 100644 --- a/aprsd/plugins/location.py +++ b/aprsd/plugins/location.py @@ -11,9 +11,9 @@ LOG = logging.getLogger("APRSD") class LocationPlugin(plugin.APRSDRegexCommandPluginBase, plugin.APRSFIKEYMixin): """Location!""" - version = "1.0" command_regex = "^[lL]" command_name = "location" + short_description = "Where in the world is a CALLSIGN's last GPS beacon?" def setup(self): self.ensure_aprs_fi_key() diff --git a/aprsd/plugins/notify.py b/aprsd/plugins/notify.py index 59adc5a..b7ae4c5 100644 --- a/aprsd/plugins/notify.py +++ b/aprsd/plugins/notify.py @@ -15,7 +15,7 @@ class NotifySeenPlugin(plugin.APRSDWatchListPluginBase): seen was older than the configured age limit. """ - version = "1.0" + short_description = "Notify me when a CALLSIGN is recently seen on APRS-IS" def process(self, packet): LOG.info("NotifySeenPlugin") diff --git a/aprsd/plugins/ping.py b/aprsd/plugins/ping.py index 77d78ec..b709574 100644 --- a/aprsd/plugins/ping.py +++ b/aprsd/plugins/ping.py @@ -10,9 +10,9 @@ LOG = logging.getLogger("APRSD") class PingPlugin(plugin.APRSDRegexCommandPluginBase): """Ping.""" - version = "1.0" command_regex = "^[pP]" command_name = "ping" + short_description = "reply with a Pong!" @trace.trace def process(self, packet): diff --git a/aprsd/plugins/query.py b/aprsd/plugins/query.py index a658e74..bdc273a 100644 --- a/aprsd/plugins/query.py +++ b/aprsd/plugins/query.py @@ -11,9 +11,9 @@ LOG = logging.getLogger("APRSD") class QueryPlugin(plugin.APRSDRegexCommandPluginBase): """Query command.""" - version = "1.0" command_regex = r"^\!.*" command_name = "query" + short_description = "APRSD Owner command to query messages in the MsgTrack" @trace.trace def process(self, packet): diff --git a/aprsd/plugins/time.py b/aprsd/plugins/time.py index faf9a5a..8cfdd83 100644 --- a/aprsd/plugins/time.py +++ b/aprsd/plugins/time.py @@ -14,9 +14,9 @@ LOG = logging.getLogger("APRSD") class TimePlugin(plugin.APRSDRegexCommandPluginBase): """Time command.""" - version = "1.0" command_regex = "^[tT]" command_name = "time" + short_description = "What is the current local time." def _get_local_tz(self): return pytz.timezone(time.strftime("%Z")) @@ -52,9 +52,9 @@ class TimePlugin(plugin.APRSDRegexCommandPluginBase): class TimeOpenCageDataPlugin(TimePlugin, plugin.APRSFIKEYMixin): """geocage based timezone fetching.""" - version = "1.0" command_regex = "^[tT]" command_name = "time" + short_description = "Current time of GPS beacon timezone. Uses OpenCage" def setup(self): self.ensure_aprs_fi_key() @@ -114,9 +114,9 @@ class TimeOpenCageDataPlugin(TimePlugin, plugin.APRSFIKEYMixin): class TimeOWMPlugin(TimePlugin, plugin.APRSFIKEYMixin): """OpenWeatherMap based timezone fetching.""" - version = "1.0" command_regex = "^[tT]" command_name = "time" + short_description = "Current time of GPS beacon's timezone. Uses OpenWeatherMap" def setup(self): self.ensure_aprs_fi_key() diff --git a/aprsd/plugins/version.py b/aprsd/plugins/version.py index 2a5e41a..6a05690 100644 --- a/aprsd/plugins/version.py +++ b/aprsd/plugins/version.py @@ -10,9 +10,9 @@ LOG = logging.getLogger("APRSD") class VersionPlugin(plugin.APRSDRegexCommandPluginBase): """Version of APRSD Plugin.""" - version = "1.0" command_regex = "^[vV]" command_name = "version" + short_description = "What is the APRSD Version" # message_number:time combos so we don't resend the same email in # five mins {int:int} diff --git a/aprsd/plugins/weather.py b/aprsd/plugins/weather.py index 0817c8e..c656073 100644 --- a/aprsd/plugins/weather.py +++ b/aprsd/plugins/weather.py @@ -23,9 +23,9 @@ class USWeatherPlugin(plugin.APRSDRegexCommandPluginBase): "weather" - returns weather near the calling callsign """ - version = "1.0" command_regex = "^[wW]" command_name = "USWeather" + short_description = "Provide USA only weather of GPS Beacon location" @trace.trace def process(self, packet): @@ -86,9 +86,9 @@ class USMetarPlugin(plugin.APRSDRegexCommandPluginBase): """ - version = "1.0" command_regex = "^[metar]" command_name = "USMetar" + short_description = "USA only METAR of GPS Beacon location" @trace.trace def process(self, packet): @@ -178,9 +178,9 @@ class OWMWeatherPlugin(plugin.APRSDRegexCommandPluginBase): """ - version = "1.0" command_regex = "^[wW]" command_name = "OpenWeatherMap" + short_description = "OpenWeatherMap weather of GPS Beacon location" def help(self): _help = [ @@ -308,9 +308,9 @@ class AVWXWeatherPlugin(plugin.APRSDRegexCommandPluginBase): docker build -f Dockerfile -t avwx-api:master . """ - version = "1.0" command_regex = "^[mM]" command_name = "AVWXWeather" + short_description = "AVWX weather of GPS Beacon location" def help(self): _help = [ diff --git a/requirements.in b/requirements.in index 1d23d98..94cc54b 100644 --- a/requirements.in +++ b/requirements.in @@ -20,3 +20,4 @@ thesmuggler update_checker flask-socketio eventlet +tabulate diff --git a/requirements.txt b/requirements.txt index 9560913..9bf8a0a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -104,6 +104,8 @@ six==1.16.0 # imapclient # pyopenssl # signalslot +tabulate==0.8.9 + # via -r requirements.in thesmuggler==1.0.1 # via -r requirements.in update-checker==0.18.0