mirror of
https://github.com/craigerl/aprsd.git
synced 2026-08-17 00:54:03 -04:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bda2ef00dd | |||
| 446484e631 | |||
| a8a6b1aa07 | |||
| 8842fb1b44 | |||
| 152132b0ed | |||
| 7787dc1be4 | |||
| 10e34d8634 |
@@ -1,9 +1,26 @@
|
|||||||
CHANGES
|
CHANGES
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
v2.5.2
|
||||||
|
------
|
||||||
|
|
||||||
|
* Added new list-plugins command
|
||||||
|
* Don't require check-version command to have a config
|
||||||
|
* Healthcheck command doesn't need the aprsd.yml config
|
||||||
|
* Fix test failures
|
||||||
|
* Removed requirement for aprs.fi key
|
||||||
|
* Updated Changelog
|
||||||
|
|
||||||
|
v2.5.1
|
||||||
|
------
|
||||||
|
|
||||||
|
* Removed stock plugin
|
||||||
|
* Removed the stock plugin
|
||||||
|
|
||||||
v2.5.0
|
v2.5.0
|
||||||
------
|
------
|
||||||
|
|
||||||
|
* Updated for v2.5.0
|
||||||
* Updated Dockerfile's and build script for docker
|
* Updated Dockerfile's and build script for docker
|
||||||
* Cleaned up some verbose output & colorized output
|
* Cleaned up some verbose output & colorized output
|
||||||
* Reworked all the common arguments
|
* Reworked all the common arguments
|
||||||
|
|||||||
+3
-2
@@ -67,7 +67,8 @@ def main():
|
|||||||
# First import all the possible commands for the CLI
|
# First import all the possible commands for the CLI
|
||||||
# The commands themselves live in the cmds directory
|
# The commands themselves live in the cmds directory
|
||||||
from .cmds import ( # noqa
|
from .cmds import ( # noqa
|
||||||
completion, dev, healthcheck, listen, send_message, server,
|
completion, dev, healthcheck, list_plugins, listen, send_message,
|
||||||
|
server,
|
||||||
)
|
)
|
||||||
cli()
|
cli()
|
||||||
|
|
||||||
@@ -97,7 +98,7 @@ def signal_handler(sig, frame):
|
|||||||
@cli.command()
|
@cli.command()
|
||||||
@cli_helper.add_options(cli_helper.common_options)
|
@cli_helper.add_options(cli_helper.common_options)
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
@cli_helper.process_standard_options
|
@cli_helper.process_standard_options_no_config
|
||||||
def check_version(ctx):
|
def check_version(ctx):
|
||||||
"""Check this version against the latest in pypi.org."""
|
"""Check this version against the latest in pypi.org."""
|
||||||
level, msg = utils._check_version()
|
level, msg = utils._check_version()
|
||||||
|
|||||||
@@ -65,3 +65,24 @@ def process_standard_options(f: F) -> F:
|
|||||||
return f(*args, **kwargs)
|
return f(*args, **kwargs)
|
||||||
|
|
||||||
return update_wrapper(t.cast(F, new_func), f)
|
return update_wrapper(t.cast(F, new_func), f)
|
||||||
|
|
||||||
|
|
||||||
|
def process_standard_options_no_config(f: F) -> F:
|
||||||
|
"""Use this as a decorator when config isn't needed."""
|
||||||
|
def new_func(*args, **kwargs):
|
||||||
|
ctx = args[0]
|
||||||
|
ctx.ensure_object(dict)
|
||||||
|
ctx.obj["loglevel"] = kwargs["loglevel"]
|
||||||
|
ctx.obj["config_file"] = kwargs["config_file"]
|
||||||
|
ctx.obj["quiet"] = kwargs["quiet"]
|
||||||
|
log.setup_logging_no_config(
|
||||||
|
ctx.obj["loglevel"],
|
||||||
|
ctx.obj["quiet"],
|
||||||
|
)
|
||||||
|
|
||||||
|
del kwargs["loglevel"]
|
||||||
|
del kwargs["config_file"]
|
||||||
|
del kwargs["quiet"]
|
||||||
|
return f(*args, **kwargs)
|
||||||
|
|
||||||
|
return update_wrapper(t.cast(F, new_func), f)
|
||||||
|
|||||||
@@ -40,10 +40,9 @@ LOG = logging.getLogger("APRSD")
|
|||||||
help="How long to wait for healtcheck url to come back",
|
help="How long to wait for healtcheck url to come back",
|
||||||
)
|
)
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
@cli_helper.process_standard_options
|
@cli_helper.process_standard_options_no_config
|
||||||
def healthcheck(ctx, health_url, timeout):
|
def healthcheck(ctx, health_url, timeout):
|
||||||
"""Check the health of the running aprsd server."""
|
"""Check the health of the running aprsd server."""
|
||||||
ctx.obj["config"]
|
|
||||||
LOG.debug(f"APRSD HealthCheck version: {aprsd.__version__}")
|
LOG.debug(f"APRSD HealthCheck version: {aprsd.__version__}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -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), " "))
|
||||||
@@ -327,12 +327,6 @@ def parse_config(config_file):
|
|||||||
"ham.callsign",
|
"ham.callsign",
|
||||||
default_fail=DEFAULT_CONFIG_DICT["ham"]["callsign"],
|
default_fail=DEFAULT_CONFIG_DICT["ham"]["callsign"],
|
||||||
)
|
)
|
||||||
|
|
||||||
check_option(
|
|
||||||
config,
|
|
||||||
["services", "aprs.fi", "apiKey"],
|
|
||||||
default_fail=DEFAULT_CONFIG_DICT["services"]["aprs.fi"]["apiKey"],
|
|
||||||
)
|
|
||||||
check_option(
|
check_option(
|
||||||
config,
|
config,
|
||||||
"aprs.login",
|
"aprs.login",
|
||||||
|
|||||||
+2
-2
@@ -19,7 +19,7 @@ from werkzeug.security import check_password_hash, generate_password_hash
|
|||||||
import aprsd
|
import aprsd
|
||||||
from aprsd import client
|
from aprsd import client
|
||||||
from aprsd import config as aprsd_config
|
from aprsd import config as aprsd_config
|
||||||
from aprsd import messaging, packets, plugin, stats, threads, utils
|
from aprsd import log, messaging, packets, plugin, stats, threads, utils
|
||||||
from aprsd.clients import aprsis
|
from aprsd.clients import aprsis
|
||||||
|
|
||||||
|
|
||||||
@@ -500,7 +500,7 @@ class LogMonitorThread(threads.APRSDThread):
|
|||||||
def loop(self):
|
def loop(self):
|
||||||
global socketio
|
global socketio
|
||||||
try:
|
try:
|
||||||
record = threads.logging_queue.get(block=True, timeout=5)
|
record = log.logging_queue.get(block=True, timeout=5)
|
||||||
json_record = self.json_record(record)
|
json_record = self.json_record(record)
|
||||||
socketio.emit(
|
socketio.emit(
|
||||||
"log_entry", json_record,
|
"log_entry", json_record,
|
||||||
|
|||||||
@@ -51,3 +51,20 @@ def setup_logging(config, loglevel, quiet):
|
|||||||
LOG.addHandler(sh)
|
LOG.addHandler(sh)
|
||||||
if imap_logger:
|
if imap_logger:
|
||||||
imap_logger.addHandler(sh)
|
imap_logger.addHandler(sh)
|
||||||
|
|
||||||
|
|
||||||
|
def setup_logging_no_config(loglevel, quiet):
|
||||||
|
log_level = aprsd_config.LOG_LEVELS[loglevel]
|
||||||
|
LOG.setLevel(log_level)
|
||||||
|
log_format = aprsd_config.DEFAULT_LOG_FORMAT
|
||||||
|
date_format = aprsd_config.DEFAULT_DATE_FORMAT
|
||||||
|
log_formatter = logging.Formatter(fmt=log_format, datefmt=date_format)
|
||||||
|
fh = NullHandler()
|
||||||
|
|
||||||
|
fh.setFormatter(log_formatter)
|
||||||
|
LOG.addHandler(fh)
|
||||||
|
|
||||||
|
if not quiet:
|
||||||
|
sh = logging.StreamHandler(sys.stdout)
|
||||||
|
sh.setFormatter(log_formatter)
|
||||||
|
LOG.addHandler(sh)
|
||||||
|
|||||||
+16
-2
@@ -12,6 +12,7 @@ import threading
|
|||||||
import pluggy
|
import pluggy
|
||||||
from thesmuggler import smuggle
|
from thesmuggler import smuggle
|
||||||
|
|
||||||
|
import aprsd
|
||||||
from aprsd import client, messaging, packets, threads
|
from aprsd import client, messaging, packets, threads
|
||||||
|
|
||||||
|
|
||||||
@@ -51,7 +52,7 @@ class APRSDPluginBase(metaclass=abc.ABCMeta):
|
|||||||
config = None
|
config = None
|
||||||
rx_count = 0
|
rx_count = 0
|
||||||
tx_count = 0
|
tx_count = 0
|
||||||
version = "1.0"
|
version = aprsd.__version__
|
||||||
|
|
||||||
# Holds the list of APRSDThreads that the plugin creates
|
# Holds the list of APRSDThreads that the plugin creates
|
||||||
threads = []
|
threads = []
|
||||||
@@ -241,11 +242,24 @@ class APRSDRegexCommandPluginBase(APRSDPluginBase, metaclass=abc.ABCMeta):
|
|||||||
if result:
|
if result:
|
||||||
self.tx_inc()
|
self.tx_inc()
|
||||||
else:
|
else:
|
||||||
LOG.warning(f"{self.__class__} isn't enabled.")
|
result = f"{self.__class__.__name__} isn't enabled"
|
||||||
|
LOG.warning(result)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
class HelpPlugin(APRSDRegexCommandPluginBase):
|
class HelpPlugin(APRSDRegexCommandPluginBase):
|
||||||
"""Help Plugin that is always enabled.
|
"""Help Plugin that is always enabled.
|
||||||
|
|
||||||
|
|||||||
@@ -59,9 +59,9 @@ class EmailInfo:
|
|||||||
class EmailPlugin(plugin.APRSDRegexCommandPluginBase):
|
class EmailPlugin(plugin.APRSDRegexCommandPluginBase):
|
||||||
"""Email Plugin."""
|
"""Email Plugin."""
|
||||||
|
|
||||||
version = "1.0"
|
|
||||||
command_regex = "^-.*"
|
command_regex = "^-.*"
|
||||||
command_name = "email"
|
command_name = "email"
|
||||||
|
short_description = "Send and Receive email"
|
||||||
|
|
||||||
# message_number:time combos so we don't resend the same email in
|
# message_number:time combos so we don't resend the same email in
|
||||||
# five mins {int:int}
|
# five mins {int:int}
|
||||||
|
|||||||
@@ -11,9 +11,18 @@ LOG = logging.getLogger("APRSD")
|
|||||||
class FortunePlugin(plugin.APRSDRegexCommandPluginBase):
|
class FortunePlugin(plugin.APRSDRegexCommandPluginBase):
|
||||||
"""Fortune."""
|
"""Fortune."""
|
||||||
|
|
||||||
version = "1.0"
|
|
||||||
command_regex = "^[fF]"
|
command_regex = "^[fF]"
|
||||||
command_name = "fortune"
|
command_name = "fortune"
|
||||||
|
short_description = "Give me a fortune"
|
||||||
|
|
||||||
|
fortune_path = None
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
self.fortune_path = shutil.which("fortune")
|
||||||
|
if not self.fortune_path:
|
||||||
|
self.enabled = False
|
||||||
|
else:
|
||||||
|
self.enabled = True
|
||||||
|
|
||||||
@trace.trace
|
@trace.trace
|
||||||
def process(self, packet):
|
def process(self, packet):
|
||||||
@@ -25,13 +34,8 @@ class FortunePlugin(plugin.APRSDRegexCommandPluginBase):
|
|||||||
|
|
||||||
reply = None
|
reply = None
|
||||||
|
|
||||||
fortune_path = shutil.which("fortune")
|
|
||||||
if not fortune_path:
|
|
||||||
reply = "Fortune command not installed"
|
|
||||||
return reply
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cmnd = [fortune_path, "-s", "-n 60"]
|
cmnd = [self.fortune_path, "-s", "-n 60"]
|
||||||
command = " ".join(cmnd)
|
command = " ".join(cmnd)
|
||||||
output = subprocess.check_output(
|
output = subprocess.check_output(
|
||||||
command,
|
command,
|
||||||
|
|||||||
@@ -8,12 +8,15 @@ from aprsd import plugin, plugin_utils, trace
|
|||||||
LOG = logging.getLogger("APRSD")
|
LOG = logging.getLogger("APRSD")
|
||||||
|
|
||||||
|
|
||||||
class LocationPlugin(plugin.APRSDRegexCommandPluginBase):
|
class LocationPlugin(plugin.APRSDRegexCommandPluginBase, plugin.APRSFIKEYMixin):
|
||||||
"""Location!"""
|
"""Location!"""
|
||||||
|
|
||||||
version = "1.0"
|
|
||||||
command_regex = "^[lL]"
|
command_regex = "^[lL]"
|
||||||
command_name = "location"
|
command_name = "location"
|
||||||
|
short_description = "Where in the world is a CALLSIGN's last GPS beacon?"
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
self.ensure_aprs_fi_key()
|
||||||
|
|
||||||
@trace.trace
|
@trace.trace
|
||||||
def process(self, packet):
|
def process(self, packet):
|
||||||
@@ -22,13 +25,6 @@ class LocationPlugin(plugin.APRSDRegexCommandPluginBase):
|
|||||||
message = packet.get("message_text", None)
|
message = packet.get("message_text", None)
|
||||||
# ack = packet.get("msgNo", "0")
|
# ack = packet.get("msgNo", "0")
|
||||||
|
|
||||||
# get last location of a callsign, get descriptive name from weather service
|
|
||||||
try:
|
|
||||||
self.config.check_option(["services", "aprs.fi", "apiKey"])
|
|
||||||
except Exception as ex:
|
|
||||||
LOG.error(f"Failed to find config aprs.fi:apikey {ex}")
|
|
||||||
return "No aprs.fi apikey found"
|
|
||||||
|
|
||||||
api_key = self.config["services"]["aprs.fi"]["apiKey"]
|
api_key = self.config["services"]["aprs.fi"]["apiKey"]
|
||||||
|
|
||||||
# optional second argument is a callsign to search
|
# optional second argument is a callsign to search
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class NotifySeenPlugin(plugin.APRSDWatchListPluginBase):
|
|||||||
seen was older than the configured age limit.
|
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):
|
def process(self, packet):
|
||||||
LOG.info("NotifySeenPlugin")
|
LOG.info("NotifySeenPlugin")
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ LOG = logging.getLogger("APRSD")
|
|||||||
class PingPlugin(plugin.APRSDRegexCommandPluginBase):
|
class PingPlugin(plugin.APRSDRegexCommandPluginBase):
|
||||||
"""Ping."""
|
"""Ping."""
|
||||||
|
|
||||||
version = "1.0"
|
|
||||||
command_regex = "^[pP]"
|
command_regex = "^[pP]"
|
||||||
command_name = "ping"
|
command_name = "ping"
|
||||||
|
short_description = "reply with a Pong!"
|
||||||
|
|
||||||
@trace.trace
|
@trace.trace
|
||||||
def process(self, packet):
|
def process(self, packet):
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ LOG = logging.getLogger("APRSD")
|
|||||||
class QueryPlugin(plugin.APRSDRegexCommandPluginBase):
|
class QueryPlugin(plugin.APRSDRegexCommandPluginBase):
|
||||||
"""Query command."""
|
"""Query command."""
|
||||||
|
|
||||||
version = "1.0"
|
|
||||||
command_regex = r"^\!.*"
|
command_regex = r"^\!.*"
|
||||||
command_name = "query"
|
command_name = "query"
|
||||||
|
short_description = "APRSD Owner command to query messages in the MsgTrack"
|
||||||
|
|
||||||
@trace.trace
|
@trace.trace
|
||||||
def process(self, packet):
|
def process(self, packet):
|
||||||
|
|||||||
+11
-19
@@ -14,9 +14,9 @@ LOG = logging.getLogger("APRSD")
|
|||||||
class TimePlugin(plugin.APRSDRegexCommandPluginBase):
|
class TimePlugin(plugin.APRSDRegexCommandPluginBase):
|
||||||
"""Time command."""
|
"""Time command."""
|
||||||
|
|
||||||
version = "1.0"
|
|
||||||
command_regex = "^[tT]"
|
command_regex = "^[tT]"
|
||||||
command_name = "time"
|
command_name = "time"
|
||||||
|
short_description = "What is the current local time."
|
||||||
|
|
||||||
def _get_local_tz(self):
|
def _get_local_tz(self):
|
||||||
return pytz.timezone(time.strftime("%Z"))
|
return pytz.timezone(time.strftime("%Z"))
|
||||||
@@ -49,12 +49,15 @@ class TimePlugin(plugin.APRSDRegexCommandPluginBase):
|
|||||||
return self.build_date_str(localzone)
|
return self.build_date_str(localzone)
|
||||||
|
|
||||||
|
|
||||||
class TimeOpenCageDataPlugin(TimePlugin):
|
class TimeOpenCageDataPlugin(TimePlugin, plugin.APRSFIKEYMixin):
|
||||||
"""geocage based timezone fetching."""
|
"""geocage based timezone fetching."""
|
||||||
|
|
||||||
version = "1.0"
|
|
||||||
command_regex = "^[tT]"
|
command_regex = "^[tT]"
|
||||||
command_name = "time"
|
command_name = "time"
|
||||||
|
short_description = "Current time of GPS beacon timezone. Uses OpenCage"
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
self.ensure_aprs_fi_key()
|
||||||
|
|
||||||
@trace.trace
|
@trace.trace
|
||||||
def process(self, packet):
|
def process(self, packet):
|
||||||
@@ -62,13 +65,6 @@ class TimeOpenCageDataPlugin(TimePlugin):
|
|||||||
message = packet.get("message_text", None)
|
message = packet.get("message_text", None)
|
||||||
# ack = packet.get("msgNo", "0")
|
# ack = packet.get("msgNo", "0")
|
||||||
|
|
||||||
# get last location of a callsign, get descriptive name from weather service
|
|
||||||
try:
|
|
||||||
self.config.exists(["services", "aprs.fi", "apiKey"])
|
|
||||||
except Exception as ex:
|
|
||||||
LOG.error(f"Failed to find config aprs.fi:apikey {ex}")
|
|
||||||
return "No aprs.fi apikey found"
|
|
||||||
|
|
||||||
api_key = self.config["services"]["aprs.fi"]["apiKey"]
|
api_key = self.config["services"]["aprs.fi"]["apiKey"]
|
||||||
|
|
||||||
# optional second argument is a callsign to search
|
# optional second argument is a callsign to search
|
||||||
@@ -115,12 +111,15 @@ class TimeOpenCageDataPlugin(TimePlugin):
|
|||||||
return self.build_date_str(localzone)
|
return self.build_date_str(localzone)
|
||||||
|
|
||||||
|
|
||||||
class TimeOWMPlugin(TimePlugin):
|
class TimeOWMPlugin(TimePlugin, plugin.APRSFIKEYMixin):
|
||||||
"""OpenWeatherMap based timezone fetching."""
|
"""OpenWeatherMap based timezone fetching."""
|
||||||
|
|
||||||
version = "1.0"
|
|
||||||
command_regex = "^[tT]"
|
command_regex = "^[tT]"
|
||||||
command_name = "time"
|
command_name = "time"
|
||||||
|
short_description = "Current time of GPS beacon's timezone. Uses OpenWeatherMap"
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
self.ensure_aprs_fi_key()
|
||||||
|
|
||||||
@trace.trace
|
@trace.trace
|
||||||
def process(self, packet):
|
def process(self, packet):
|
||||||
@@ -128,13 +127,6 @@ class TimeOWMPlugin(TimePlugin):
|
|||||||
message = packet.get("message_text", None)
|
message = packet.get("message_text", None)
|
||||||
# ack = packet.get("msgNo", "0")
|
# ack = packet.get("msgNo", "0")
|
||||||
|
|
||||||
# get last location of a callsign, get descriptive name from weather service
|
|
||||||
try:
|
|
||||||
self.config.exists(["services", "aprs.fi", "apiKey"])
|
|
||||||
except Exception as ex:
|
|
||||||
LOG.error(f"Failed to find config aprs.fi:apikey {ex}")
|
|
||||||
return "No aprs.fi apikey found"
|
|
||||||
|
|
||||||
# optional second argument is a callsign to search
|
# optional second argument is a callsign to search
|
||||||
a = re.search(r"^.*\s+(.*)", message)
|
a = re.search(r"^.*\s+(.*)", message)
|
||||||
if a is not None:
|
if a is not None:
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ LOG = logging.getLogger("APRSD")
|
|||||||
class VersionPlugin(plugin.APRSDRegexCommandPluginBase):
|
class VersionPlugin(plugin.APRSDRegexCommandPluginBase):
|
||||||
"""Version of APRSD Plugin."""
|
"""Version of APRSD Plugin."""
|
||||||
|
|
||||||
version = "1.0"
|
|
||||||
command_regex = "^[vV]"
|
command_regex = "^[vV]"
|
||||||
command_name = "version"
|
command_name = "version"
|
||||||
|
short_description = "What is the APRSD Version"
|
||||||
|
|
||||||
# message_number:time combos so we don't resend the same email in
|
# message_number:time combos so we don't resend the same email in
|
||||||
# five mins {int:int}
|
# five mins {int:int}
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ class USWeatherPlugin(plugin.APRSDRegexCommandPluginBase):
|
|||||||
"weather" - returns weather near the calling callsign
|
"weather" - returns weather near the calling callsign
|
||||||
"""
|
"""
|
||||||
|
|
||||||
version = "1.0"
|
|
||||||
command_regex = "^[wW]"
|
command_regex = "^[wW]"
|
||||||
command_name = "USWeather"
|
command_name = "USWeather"
|
||||||
|
short_description = "Provide USA only weather of GPS Beacon location"
|
||||||
|
|
||||||
@trace.trace
|
@trace.trace
|
||||||
def process(self, packet):
|
def process(self, packet):
|
||||||
@@ -86,9 +86,9 @@ class USMetarPlugin(plugin.APRSDRegexCommandPluginBase):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
version = "1.0"
|
|
||||||
command_regex = "^[metar]"
|
command_regex = "^[metar]"
|
||||||
command_name = "USMetar"
|
command_name = "USMetar"
|
||||||
|
short_description = "USA only METAR of GPS Beacon location"
|
||||||
|
|
||||||
@trace.trace
|
@trace.trace
|
||||||
def process(self, packet):
|
def process(self, packet):
|
||||||
@@ -178,9 +178,9 @@ class OWMWeatherPlugin(plugin.APRSDRegexCommandPluginBase):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
version = "1.0"
|
|
||||||
command_regex = "^[wW]"
|
command_regex = "^[wW]"
|
||||||
command_name = "OpenWeatherMap"
|
command_name = "OpenWeatherMap"
|
||||||
|
short_description = "OpenWeatherMap weather of GPS Beacon location"
|
||||||
|
|
||||||
def help(self):
|
def help(self):
|
||||||
_help = [
|
_help = [
|
||||||
@@ -308,9 +308,9 @@ class AVWXWeatherPlugin(plugin.APRSDRegexCommandPluginBase):
|
|||||||
docker build -f Dockerfile -t avwx-api:master .
|
docker build -f Dockerfile -t avwx-api:master .
|
||||||
"""
|
"""
|
||||||
|
|
||||||
version = "1.0"
|
|
||||||
command_regex = "^[mM]"
|
command_regex = "^[mM]"
|
||||||
command_name = "AVWXWeather"
|
command_name = "AVWXWeather"
|
||||||
|
short_description = "AVWX weather of GPS Beacon location"
|
||||||
|
|
||||||
def help(self):
|
def help(self):
|
||||||
_help = [
|
_help = [
|
||||||
|
|||||||
@@ -20,3 +20,4 @@ thesmuggler
|
|||||||
update_checker
|
update_checker
|
||||||
flask-socketio
|
flask-socketio
|
||||||
eventlet
|
eventlet
|
||||||
|
tabulate
|
||||||
|
|||||||
@@ -104,6 +104,8 @@ six==1.16.0
|
|||||||
# imapclient
|
# imapclient
|
||||||
# pyopenssl
|
# pyopenssl
|
||||||
# signalslot
|
# signalslot
|
||||||
|
tabulate==0.8.9
|
||||||
|
# via -r requirements.in
|
||||||
thesmuggler==1.0.1
|
thesmuggler==1.0.1
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
update-checker==0.18.0
|
update-checker==0.18.0
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ class TestPlugin(unittest.TestCase):
|
|||||||
self.config = config.DEFAULT_CONFIG_DICT
|
self.config = config.DEFAULT_CONFIG_DICT
|
||||||
self.config["ham"]["callsign"] = self.fromcall
|
self.config["ham"]["callsign"] = self.fromcall
|
||||||
self.config["aprs"]["login"] = fake.FAKE_TO_CALLSIGN
|
self.config["aprs"]["login"] = fake.FAKE_TO_CALLSIGN
|
||||||
|
self.config["services"]["aprs.fi"]["apiKey"] = "something"
|
||||||
# Inintialize the stats object with the config
|
# Inintialize the stats object with the config
|
||||||
stats.APRSDStats(self.config)
|
stats.APRSDStats(self.config)
|
||||||
packets.WatchList(config=self.config)
|
packets.WatchList(config=self.config)
|
||||||
@@ -127,9 +128,9 @@ class TestPlugin(unittest.TestCase):
|
|||||||
class TestFortunePlugin(TestPlugin):
|
class TestFortunePlugin(TestPlugin):
|
||||||
@mock.patch("shutil.which")
|
@mock.patch("shutil.which")
|
||||||
def test_fortune_fail(self, mock_which):
|
def test_fortune_fail(self, mock_which):
|
||||||
fortune = fortune_plugin.FortunePlugin(self.config)
|
|
||||||
mock_which.return_value = None
|
mock_which.return_value = None
|
||||||
expected = "Fortune command not installed"
|
fortune = fortune_plugin.FortunePlugin(self.config)
|
||||||
|
expected = "FortunePlugin isn't enabled"
|
||||||
packet = fake.fake_packet(message="fortune")
|
packet = fake.fake_packet(message="fortune")
|
||||||
actual = fortune.filter(packet)
|
actual = fortune.filter(packet)
|
||||||
self.assertEqual(expected, actual)
|
self.assertEqual(expected, actual)
|
||||||
@@ -137,10 +138,9 @@ class TestFortunePlugin(TestPlugin):
|
|||||||
@mock.patch("subprocess.check_output")
|
@mock.patch("subprocess.check_output")
|
||||||
@mock.patch("shutil.which")
|
@mock.patch("shutil.which")
|
||||||
def test_fortune_success(self, mock_which, mock_output):
|
def test_fortune_success(self, mock_which, mock_output):
|
||||||
fortune = fortune_plugin.FortunePlugin(self.config)
|
mock_which.return_value = "/usr/bin/games/fortune"
|
||||||
mock_which.return_value = "/usr/bin/games"
|
|
||||||
|
|
||||||
mock_output.return_value = "Funny fortune"
|
mock_output.return_value = "Funny fortune"
|
||||||
|
fortune = fortune_plugin.FortunePlugin(self.config)
|
||||||
|
|
||||||
expected = "Funny fortune"
|
expected = "Funny fortune"
|
||||||
packet = fake.fake_packet(message="fortune")
|
packet = fake.fake_packet(message="fortune")
|
||||||
|
|||||||
Reference in New Issue
Block a user