mirror of
https://github.com/craigerl/aprsd.git
synced 2024-10-01 09:36:35 -04:00
Added new HelpPlugin
This patch adds the always enabled HelpPlugin. This plugin now will respond to the 'help' or 'h' commands that will automatically build a help string based on the number of enabled plugins. It will also respond to help <plugin> with the plugin specific help
This commit is contained in:
parent
2bf85db21b
commit
3b7924b13d
19
aprsd/dev.py
19
aprsd/dev.py
@ -178,12 +178,22 @@ def setup_logging(config, loglevel, quiet):
|
|||||||
default="aprsd.plugins.wx.WxPlugin",
|
default="aprsd.plugins.wx.WxPlugin",
|
||||||
help="The plugin to run",
|
help="The plugin to run",
|
||||||
)
|
)
|
||||||
|
@click.option(
|
||||||
|
"-a",
|
||||||
|
"--all",
|
||||||
|
"load_all",
|
||||||
|
show_default=True,
|
||||||
|
is_flag=True,
|
||||||
|
default=False,
|
||||||
|
help="Load all the plugins in config?",
|
||||||
|
)
|
||||||
@click.argument("fromcall")
|
@click.argument("fromcall")
|
||||||
@click.argument("message", nargs=-1, required=True)
|
@click.argument("message", nargs=-1, required=True)
|
||||||
def test_plugin(
|
def test_plugin(
|
||||||
loglevel,
|
loglevel,
|
||||||
config_file,
|
config_file,
|
||||||
plugin_path,
|
plugin_path,
|
||||||
|
load_all,
|
||||||
fromcall,
|
fromcall,
|
||||||
message,
|
message,
|
||||||
):
|
):
|
||||||
@ -199,8 +209,12 @@ def test_plugin(
|
|||||||
client.Client(config)
|
client.Client(config)
|
||||||
|
|
||||||
pm = plugin.PluginManager(config)
|
pm = plugin.PluginManager(config)
|
||||||
pm._init()
|
if load_all:
|
||||||
|
pm.setup_plugins()
|
||||||
|
else:
|
||||||
|
pm._init()
|
||||||
obj = pm._create_class(plugin_path, plugin.APRSDPluginBase, config=config)
|
obj = pm._create_class(plugin_path, plugin.APRSDPluginBase, config=config)
|
||||||
|
# Register the plugin they wanted tested.
|
||||||
pm._pluggy_pm.register(obj)
|
pm._pluggy_pm.register(obj)
|
||||||
login = config["aprs"]["login"]
|
login = config["aprs"]["login"]
|
||||||
|
|
||||||
@ -212,8 +226,9 @@ def test_plugin(
|
|||||||
}
|
}
|
||||||
|
|
||||||
reply = pm.run(packet)
|
reply = pm.run(packet)
|
||||||
|
pm.stop()
|
||||||
# Plugin might have threads, so lets stop them so we can exit.
|
# Plugin might have threads, so lets stop them so we can exit.
|
||||||
obj.stop_threads()
|
# obj.stop_threads()
|
||||||
LOG.info(f"Result = '{reply}'")
|
LOG.info(f"Result = '{reply}'")
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import inspect
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import textwrap
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
import pluggy
|
import pluggy
|
||||||
@ -62,7 +63,7 @@ class APRSDPluginBase(metaclass=abc.ABCMeta):
|
|||||||
self.config = config
|
self.config = config
|
||||||
self.message_counter = 0
|
self.message_counter = 0
|
||||||
self.setup()
|
self.setup()
|
||||||
self.threads = self.create_threads()
|
self.threads = self.create_threads() or []
|
||||||
self.start_threads()
|
self.start_threads()
|
||||||
|
|
||||||
def start_threads(self):
|
def start_threads(self):
|
||||||
@ -93,6 +94,9 @@ class APRSDPluginBase(metaclass=abc.ABCMeta):
|
|||||||
def message_count(self):
|
def message_count(self):
|
||||||
return self.message_counter
|
return self.message_counter
|
||||||
|
|
||||||
|
def help(self):
|
||||||
|
return "Help!"
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def setup(self):
|
def setup(self):
|
||||||
"""Do any plugin setup here."""
|
"""Do any plugin setup here."""
|
||||||
@ -198,6 +202,12 @@ class APRSDRegexCommandPluginBase(APRSDPluginBase, metaclass=abc.ABCMeta):
|
|||||||
"""The regex to match from the caller"""
|
"""The regex to match from the caller"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def help(self):
|
||||||
|
return "{}: {}".format(
|
||||||
|
self.command_name.lower(),
|
||||||
|
self.command_regex,
|
||||||
|
)
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
"""Do any plugin setup here."""
|
"""Do any plugin setup here."""
|
||||||
self.enabled = True
|
self.enabled = True
|
||||||
@ -228,6 +238,7 @@ class APRSDRegexCommandPluginBase(APRSDPluginBase, metaclass=abc.ABCMeta):
|
|||||||
self.__class__, ex,
|
self.__class__, ex,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
LOG.exception(ex)
|
||||||
if result:
|
if result:
|
||||||
self.tx_inc()
|
self.tx_inc()
|
||||||
else:
|
else:
|
||||||
@ -236,6 +247,66 @@ class APRSDRegexCommandPluginBase(APRSDPluginBase, metaclass=abc.ABCMeta):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
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>"
|
||||||
|
|
||||||
|
def process(self, packet):
|
||||||
|
LOG.info("HelpPlugin")
|
||||||
|
# fromcall = packet.get("from")
|
||||||
|
message = packet.get("message_text", None)
|
||||||
|
# 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
|
||||||
|
|
||||||
|
|
||||||
class PluginManager:
|
class PluginManager:
|
||||||
# The singleton instance object for this class
|
# The singleton instance object for this class
|
||||||
_instance = None
|
_instance = None
|
||||||
@ -365,8 +436,12 @@ class PluginManager:
|
|||||||
"""Create the plugin manager and register plugins."""
|
"""Create the plugin manager and register plugins."""
|
||||||
|
|
||||||
LOG.info("Loading APRSD Plugins")
|
LOG.info("Loading APRSD Plugins")
|
||||||
enabled_plugins = self.config["aprsd"].get("enabled_plugins", None)
|
|
||||||
self._init()
|
self._init()
|
||||||
|
# Help plugin is always enabled.
|
||||||
|
_help = HelpPlugin(self.config)
|
||||||
|
self._pluggy_pm.register(_help)
|
||||||
|
|
||||||
|
enabled_plugins = self.config["aprsd"].get("enabled_plugins", None)
|
||||||
if enabled_plugins:
|
if enabled_plugins:
|
||||||
for p_name in enabled_plugins:
|
for p_name in enabled_plugins:
|
||||||
self._load_plugin(p_name)
|
self._load_plugin(p_name)
|
||||||
@ -392,6 +467,12 @@ class PluginManager:
|
|||||||
with self.lock:
|
with self.lock:
|
||||||
return self._pluggy_pm.hook.filter(packet=packet)
|
return self._pluggy_pm.hook.filter(packet=packet)
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
"""Stop all threads created by all plugins."""
|
||||||
|
with self.lock:
|
||||||
|
for p in self.get_plugins():
|
||||||
|
p.stop_threads()
|
||||||
|
|
||||||
def register_msg(self, obj):
|
def register_msg(self, obj):
|
||||||
"""Register the plugin."""
|
"""Register the plugin."""
|
||||||
self._pluggy_pm.register(obj)
|
self._pluggy_pm.register(obj)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from aprsd import messaging, packets, plugin
|
from aprsd import packets, plugin
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger("APRSD")
|
LOG = logging.getLogger("APRSD")
|
||||||
@ -46,4 +46,3 @@ class NotifySeenPlugin(plugin.APRSDWatchListPluginBase):
|
|||||||
wl.max_delta(),
|
wl.max_delta(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
return messaging.NULL_MESSAGE
|
|
||||||
|
@ -54,7 +54,7 @@ class TimeOpenCageDataPlugin(TimePlugin):
|
|||||||
|
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
command_regex = "^[tT]"
|
command_regex = "^[tT]"
|
||||||
command_name = "Time"
|
command_name = "time"
|
||||||
|
|
||||||
@trace.trace
|
@trace.trace
|
||||||
def process(self, packet):
|
def process(self, packet):
|
||||||
@ -120,7 +120,7 @@ class TimeOWMPlugin(TimePlugin):
|
|||||||
|
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
command_regex = "^[tT]"
|
command_regex = "^[tT]"
|
||||||
command_name = "Time"
|
command_name = "time"
|
||||||
|
|
||||||
@trace.trace
|
@trace.trace
|
||||||
def process(self, packet):
|
def process(self, packet):
|
||||||
|
@ -25,7 +25,7 @@ class USWeatherPlugin(plugin.APRSDRegexCommandPluginBase):
|
|||||||
|
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
command_regex = "^[wW]"
|
command_regex = "^[wW]"
|
||||||
command_name = "weather"
|
command_name = "USWeather"
|
||||||
|
|
||||||
@trace.trace
|
@trace.trace
|
||||||
def process(self, packet):
|
def process(self, packet):
|
||||||
@ -88,7 +88,7 @@ class USMetarPlugin(plugin.APRSDRegexCommandPluginBase):
|
|||||||
|
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
command_regex = "^[metar]"
|
command_regex = "^[metar]"
|
||||||
command_name = "Metar"
|
command_name = "USMetar"
|
||||||
|
|
||||||
@trace.trace
|
@trace.trace
|
||||||
def process(self, packet):
|
def process(self, packet):
|
||||||
@ -180,7 +180,16 @@ class OWMWeatherPlugin(plugin.APRSDRegexCommandPluginBase):
|
|||||||
|
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
command_regex = "^[wW]"
|
command_regex = "^[wW]"
|
||||||
command_name = "Weather"
|
command_name = "OpenWeatherMap"
|
||||||
|
|
||||||
|
def help(self):
|
||||||
|
_help = [
|
||||||
|
"openweathermap: Send {} to get weather "
|
||||||
|
"from your location".format(self.command_regex),
|
||||||
|
"openweathermap: Send {} <callsign> to get "
|
||||||
|
"weather from <callsign>".format(self.command_regex),
|
||||||
|
]
|
||||||
|
return _help
|
||||||
|
|
||||||
@trace.trace
|
@trace.trace
|
||||||
def process(self, packet):
|
def process(self, packet):
|
||||||
@ -301,7 +310,16 @@ class AVWXWeatherPlugin(plugin.APRSDRegexCommandPluginBase):
|
|||||||
|
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
command_regex = "^[mM]"
|
command_regex = "^[mM]"
|
||||||
command_name = "Weather"
|
command_name = "AVWXWeather"
|
||||||
|
|
||||||
|
def help(self):
|
||||||
|
_help = [
|
||||||
|
"avwxweather: Send {} to get weather "
|
||||||
|
"from your location".format(self.command_regex),
|
||||||
|
"avwxweather: Send {} <callsign> to get "
|
||||||
|
"weather from <callsign>".format(self.command_regex),
|
||||||
|
]
|
||||||
|
return _help
|
||||||
|
|
||||||
@trace.trace
|
@trace.trace
|
||||||
def process(self, packet):
|
def process(self, packet):
|
||||||
|
@ -302,12 +302,11 @@ class APRSDProcessPacketThread(APRSDThread):
|
|||||||
# If the message was for us and we didn't have a
|
# If the message was for us and we didn't have a
|
||||||
# response, then we send a usage statement.
|
# response, then we send a usage statement.
|
||||||
if tocall == self.config["aprs"]["login"] and not replied:
|
if tocall == self.config["aprs"]["login"] and not replied:
|
||||||
reply = "Usage: weather, locate [call], time, fortune, ping"
|
LOG.warning("Sending help!")
|
||||||
|
|
||||||
msg = messaging.TextMessage(
|
msg = messaging.TextMessage(
|
||||||
self.config["aprs"]["login"],
|
self.config["aprs"]["login"],
|
||||||
fromcall,
|
fromcall,
|
||||||
reply,
|
"Unknown command! Send 'help' message for help",
|
||||||
)
|
)
|
||||||
msg.send()
|
msg.send()
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
|
Loading…
Reference in New Issue
Block a user