aprsd 3.4.4__py3-none-any.whl → 4.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aprsd/cli_helper.py +12 -5
- aprsd/client/aprsis.py +31 -9
- aprsd/client/base.py +13 -2
- aprsd/client/drivers/aprsis.py +6 -3
- aprsd/client/drivers/fake.py +15 -20
- aprsd/client/factory.py +0 -2
- aprsd/client/fake.py +0 -2
- aprsd/client/kiss.py +17 -2
- aprsd/client/stats.py +1 -3
- aprsd/cmds/completion.py +7 -4
- aprsd/cmds/dev.py +38 -42
- aprsd/cmds/fetch_stats.py +140 -143
- aprsd/cmds/healthcheck.py +5 -3
- aprsd/cmds/list_plugins.py +140 -134
- aprsd/cmds/listen.py +13 -9
- aprsd/cmds/server.py +53 -27
- aprsd/conf/__init__.py +1 -2
- aprsd/conf/client.py +3 -4
- aprsd/conf/common.py +19 -93
- aprsd/conf/log.py +2 -4
- aprsd/conf/opts.py +5 -4
- aprsd/conf/plugin_common.py +11 -121
- aprsd/exception.py +2 -0
- aprsd/log/log.py +7 -46
- aprsd/main.py +10 -4
- aprsd/packets/__init__.py +14 -4
- aprsd/packets/core.py +57 -67
- aprsd/packets/log.py +8 -8
- aprsd/packets/packet_list.py +9 -6
- aprsd/plugin.py +22 -11
- aprsd/plugins/notify.py +1 -4
- aprsd/plugins/weather.py +10 -8
- aprsd/stats/collector.py +5 -2
- aprsd/threads/__init__.py +3 -2
- aprsd/threads/aprsd.py +12 -7
- aprsd/threads/{keep_alive.py → keepalive.py} +14 -45
- aprsd/threads/registry.py +3 -3
- aprsd/threads/rx.py +9 -6
- aprsd/threads/stats.py +2 -2
- aprsd/threads/tx.py +3 -4
- aprsd/utils/__init__.py +42 -10
- aprsd/utils/json.py +9 -4
- aprsd/utils/keepalive_collector.py +55 -0
- aprsd/utils/trace.py +0 -2
- aprsd-4.0.0.dist-info/AUTHORS +1 -0
- aprsd-4.0.0.dist-info/METADATA +293 -0
- aprsd-4.0.0.dist-info/RECORD +74 -0
- {aprsd-3.4.4.dist-info → aprsd-4.0.0.dist-info}/WHEEL +1 -1
- aprsd/cmds/admin.py +0 -57
- aprsd/cmds/webchat.py +0 -662
- aprsd/conf/plugin_email.py +0 -105
- aprsd/plugins/email.py +0 -715
- aprsd/plugins/location.py +0 -181
- aprsd/threads/log_monitor.py +0 -121
- aprsd/web/__init__.py +0 -0
- aprsd/web/admin/__init__.py +0 -0
- aprsd/web/admin/static/css/index.css +0 -84
- aprsd/web/admin/static/css/prism.css +0 -4
- aprsd/web/admin/static/css/tabs.css +0 -35
- aprsd/web/admin/static/images/Untitled.png +0 -0
- aprsd/web/admin/static/images/aprs-symbols-16-0.png +0 -0
- aprsd/web/admin/static/images/aprs-symbols-16-1.png +0 -0
- aprsd/web/admin/static/images/aprs-symbols-64-0.png +0 -0
- aprsd/web/admin/static/images/aprs-symbols-64-1.png +0 -0
- aprsd/web/admin/static/images/aprs-symbols-64-2.png +0 -0
- aprsd/web/admin/static/js/charts.js +0 -235
- aprsd/web/admin/static/js/echarts.js +0 -465
- aprsd/web/admin/static/js/logs.js +0 -26
- aprsd/web/admin/static/js/main.js +0 -231
- aprsd/web/admin/static/js/prism.js +0 -12
- aprsd/web/admin/static/js/send-message.js +0 -114
- aprsd/web/admin/static/js/tabs.js +0 -28
- aprsd/web/admin/templates/index.html +0 -196
- aprsd/web/chat/static/css/chat.css +0 -115
- aprsd/web/chat/static/css/index.css +0 -66
- aprsd/web/chat/static/css/style.css.map +0 -1
- aprsd/web/chat/static/css/tabs.css +0 -41
- aprsd/web/chat/static/css/upstream/bootstrap.min.css +0 -6
- aprsd/web/chat/static/css/upstream/font.woff2 +0 -0
- aprsd/web/chat/static/css/upstream/google-fonts.css +0 -23
- aprsd/web/chat/static/css/upstream/jquery-ui.css +0 -1311
- aprsd/web/chat/static/css/upstream/jquery.toast.css +0 -28
- aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Bold.woff +0 -0
- aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Bold.woff2 +0 -0
- aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Regular.woff +0 -0
- aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Regular.woff2 +0 -0
- aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/icons.woff +0 -0
- aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/icons.woff2 +0 -0
- aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/outline-icons.woff +0 -0
- aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/outline-icons.woff2 +0 -0
- aprsd/web/chat/static/images/Untitled.png +0 -0
- aprsd/web/chat/static/images/aprs-symbols-16-0.png +0 -0
- aprsd/web/chat/static/images/aprs-symbols-16-1.png +0 -0
- aprsd/web/chat/static/images/aprs-symbols-64-0.png +0 -0
- aprsd/web/chat/static/images/aprs-symbols-64-1.png +0 -0
- aprsd/web/chat/static/images/aprs-symbols-64-2.png +0 -0
- aprsd/web/chat/static/images/globe.svg +0 -3
- aprsd/web/chat/static/js/gps.js +0 -84
- aprsd/web/chat/static/js/main.js +0 -45
- aprsd/web/chat/static/js/send-message.js +0 -612
- aprsd/web/chat/static/js/tabs.js +0 -28
- aprsd/web/chat/static/js/upstream/bootstrap.bundle.min.js +0 -7
- aprsd/web/chat/static/js/upstream/jquery-3.7.1.min.js +0 -2
- aprsd/web/chat/static/js/upstream/jquery-ui.min.js +0 -13
- aprsd/web/chat/static/js/upstream/jquery.toast.js +0 -374
- aprsd/web/chat/static/js/upstream/semantic.min.js +0 -11
- aprsd/web/chat/static/js/upstream/socket.io.min.js +0 -7
- aprsd/web/chat/templates/index.html +0 -139
- aprsd/wsgi.py +0 -322
- aprsd-3.4.4.dist-info/AUTHORS +0 -13
- aprsd-3.4.4.dist-info/METADATA +0 -849
- aprsd-3.4.4.dist-info/RECORD +0 -134
- {aprsd-3.4.4.dist-info → aprsd-4.0.0.dist-info}/LICENSE +0 -0
- {aprsd-3.4.4.dist-info → aprsd-4.0.0.dist-info}/entry_points.txt +0 -0
- {aprsd-3.4.4.dist-info → aprsd-4.0.0.dist-info}/top_level.txt +0 -0
aprsd/cli_helper.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
from functools import update_wrapper
|
2
1
|
import logging
|
3
|
-
from pathlib import Path
|
4
2
|
import typing as t
|
3
|
+
from functools import update_wrapper
|
4
|
+
from pathlib import Path
|
5
5
|
|
6
6
|
import click
|
7
7
|
from oslo_config import cfg
|
@@ -11,7 +11,6 @@ from aprsd import conf # noqa: F401
|
|
11
11
|
from aprsd.log import log
|
12
12
|
from aprsd.utils import trace
|
13
13
|
|
14
|
-
|
15
14
|
CONF = cfg.CONF
|
16
15
|
home = str(Path.home())
|
17
16
|
DEFAULT_CONFIG_DIR = f"{home}/.config/aprsd/"
|
@@ -58,6 +57,7 @@ class AliasedGroup(click.Group):
|
|
58
57
|
calling into :meth:`add_command`.
|
59
58
|
Copied from `click` and extended for `aliases`.
|
60
59
|
"""
|
60
|
+
|
61
61
|
def decorator(f):
|
62
62
|
aliases = kwargs.pop("aliases", [])
|
63
63
|
cmd = click.decorators.command(*args, **kwargs)(f)
|
@@ -65,6 +65,7 @@ class AliasedGroup(click.Group):
|
|
65
65
|
for alias in aliases:
|
66
66
|
self.add_command(cmd, name=alias)
|
67
67
|
return cmd
|
68
|
+
|
68
69
|
return decorator
|
69
70
|
|
70
71
|
def group(self, *args, **kwargs):
|
@@ -74,6 +75,7 @@ class AliasedGroup(click.Group):
|
|
74
75
|
calling into :meth:`add_command`.
|
75
76
|
Copied from `click` and extended for `aliases`.
|
76
77
|
"""
|
78
|
+
|
77
79
|
def decorator(f):
|
78
80
|
aliases = kwargs.pop("aliases", [])
|
79
81
|
cmd = click.decorators.group(*args, **kwargs)(f)
|
@@ -81,6 +83,7 @@ class AliasedGroup(click.Group):
|
|
81
83
|
for alias in aliases:
|
82
84
|
self.add_command(cmd, name=alias)
|
83
85
|
return cmd
|
86
|
+
|
84
87
|
return decorator
|
85
88
|
|
86
89
|
|
@@ -89,6 +92,7 @@ def add_options(options):
|
|
89
92
|
for option in reversed(options):
|
90
93
|
func = option(func)
|
91
94
|
return func
|
95
|
+
|
92
96
|
return _add_options
|
93
97
|
|
94
98
|
|
@@ -103,7 +107,9 @@ def process_standard_options(f: F) -> F:
|
|
103
107
|
default_config_files = None
|
104
108
|
try:
|
105
109
|
CONF(
|
106
|
-
[],
|
110
|
+
[],
|
111
|
+
project="aprsd",
|
112
|
+
version=aprsd.__version__,
|
107
113
|
default_config_files=default_config_files,
|
108
114
|
)
|
109
115
|
except cfg.ConfigFilesNotFoundError:
|
@@ -119,7 +125,7 @@ def process_standard_options(f: F) -> F:
|
|
119
125
|
trace.setup_tracing(["method", "api"])
|
120
126
|
|
121
127
|
if not config_file_found:
|
122
|
-
LOG = logging.getLogger("APRSD")
|
128
|
+
LOG = logging.getLogger("APRSD") # noqa: N806
|
123
129
|
LOG.error("No config file found!! run 'aprsd sample-config'")
|
124
130
|
|
125
131
|
del kwargs["loglevel"]
|
@@ -132,6 +138,7 @@ def process_standard_options(f: F) -> F:
|
|
132
138
|
|
133
139
|
def process_standard_options_no_config(f: F) -> F:
|
134
140
|
"""Use this as a decorator when config isn't needed."""
|
141
|
+
|
135
142
|
def new_func(*args, **kwargs):
|
136
143
|
ctx = args[0]
|
137
144
|
ctx.ensure_object(dict)
|
aprsd/client/aprsis.py
CHANGED
@@ -2,7 +2,9 @@ import datetime
|
|
2
2
|
import logging
|
3
3
|
import time
|
4
4
|
|
5
|
+
import timeago
|
5
6
|
from aprslib.exceptions import LoginError
|
7
|
+
from loguru import logger
|
6
8
|
from oslo_config import cfg
|
7
9
|
|
8
10
|
from aprsd import client, exception
|
@@ -10,14 +12,14 @@ from aprsd.client import base
|
|
10
12
|
from aprsd.client.drivers import aprsis
|
11
13
|
from aprsd.packets import core
|
12
14
|
|
13
|
-
|
14
15
|
CONF = cfg.CONF
|
15
16
|
LOG = logging.getLogger("APRSD")
|
17
|
+
LOGU = logger
|
16
18
|
|
17
19
|
|
18
20
|
class APRSISClient(base.APRSClient):
|
19
|
-
|
20
21
|
_client = None
|
22
|
+
_checks = False
|
21
23
|
|
22
24
|
def __init__(self):
|
23
25
|
max_timeout = {"hours": 0.0, "minutes": 2, "seconds": 0}
|
@@ -45,6 +47,20 @@ class APRSISClient(base.APRSClient):
|
|
45
47
|
|
46
48
|
return stats
|
47
49
|
|
50
|
+
def keepalive_check(self):
|
51
|
+
# Don't check the first time through.
|
52
|
+
if not self.is_alive() and self._checks:
|
53
|
+
LOG.warning("Resetting client. It's not alive.")
|
54
|
+
self.reset()
|
55
|
+
self._checks = True
|
56
|
+
|
57
|
+
def keepalive_log(self):
|
58
|
+
if ka := self._client.aprsd_keepalive:
|
59
|
+
keepalive = timeago.format(ka)
|
60
|
+
else:
|
61
|
+
keepalive = "N/A"
|
62
|
+
LOGU.opt(colors=True).info(f"<green>Client keepalive {keepalive}</green>")
|
63
|
+
|
48
64
|
@staticmethod
|
49
65
|
def is_enabled():
|
50
66
|
# Defaults to True if the enabled flag is non existent
|
@@ -81,13 +97,13 @@ class APRSISClient(base.APRSClient):
|
|
81
97
|
if delta > self.max_delta:
|
82
98
|
LOG.error(f"Connection is stale, last heard {delta} ago.")
|
83
99
|
return True
|
100
|
+
return False
|
84
101
|
|
85
102
|
def is_alive(self):
|
86
|
-
if self._client:
|
87
|
-
return self._client.is_alive() and not self._is_stale_connection()
|
88
|
-
else:
|
103
|
+
if not self._client:
|
89
104
|
LOG.warning(f"APRS_CLIENT {self._client} alive? NO!!!")
|
90
105
|
return False
|
106
|
+
return self._client.is_alive() and not self._is_stale_connection()
|
91
107
|
|
92
108
|
def close(self):
|
93
109
|
if self._client:
|
@@ -117,8 +133,12 @@ class APRSISClient(base.APRSClient):
|
|
117
133
|
if retry_count >= retries:
|
118
134
|
break
|
119
135
|
try:
|
120
|
-
LOG.info(
|
121
|
-
|
136
|
+
LOG.info(
|
137
|
+
f"Creating aprslib client({host}:{port}) and logging in {user}."
|
138
|
+
)
|
139
|
+
aprs_client = aprsis.Aprsdis(
|
140
|
+
user, passwd=password, host=host, port=port
|
141
|
+
)
|
122
142
|
# Force the log to be the same
|
123
143
|
aprs_client.logger = LOG
|
124
144
|
aprs_client.connect()
|
@@ -149,8 +169,10 @@ class APRSISClient(base.APRSClient):
|
|
149
169
|
if self._client:
|
150
170
|
try:
|
151
171
|
self._client.consumer(
|
152
|
-
callback,
|
153
|
-
|
172
|
+
callback,
|
173
|
+
blocking=blocking,
|
174
|
+
immortal=immortal,
|
175
|
+
raw=raw,
|
154
176
|
)
|
155
177
|
except Exception as e:
|
156
178
|
LOG.error(e)
|
aprsd/client/base.py
CHANGED
@@ -2,11 +2,11 @@ import abc
|
|
2
2
|
import logging
|
3
3
|
import threading
|
4
4
|
|
5
|
-
from oslo_config import cfg
|
6
5
|
import wrapt
|
6
|
+
from oslo_config import cfg
|
7
7
|
|
8
8
|
from aprsd.packets import core
|
9
|
-
|
9
|
+
from aprsd.utils import keepalive_collector
|
10
10
|
|
11
11
|
CONF = cfg.CONF
|
12
12
|
LOG = logging.getLogger("APRSD")
|
@@ -30,6 +30,7 @@ class APRSClient:
|
|
30
30
|
"""This magic turns this into a singleton."""
|
31
31
|
if cls._instance is None:
|
32
32
|
cls._instance = super().__new__(cls)
|
33
|
+
keepalive_collector.KeepAliveCollector().register(cls)
|
33
34
|
# Put any initialization here.
|
34
35
|
cls._instance._create_client()
|
35
36
|
return cls._instance
|
@@ -42,6 +43,16 @@ class APRSClient:
|
|
42
43
|
dict: Statistics about the connection and packet handling
|
43
44
|
"""
|
44
45
|
|
46
|
+
@abc.abstractmethod
|
47
|
+
def keepalive_check(self) -> None:
|
48
|
+
"""Called during keepalive run to check status."""
|
49
|
+
...
|
50
|
+
|
51
|
+
@abc.abstractmethod
|
52
|
+
def keepalive_log(self) -> None:
|
53
|
+
"""Log any keepalive information."""
|
54
|
+
...
|
55
|
+
|
45
56
|
@property
|
46
57
|
def is_connected(self):
|
47
58
|
return self.connected
|
aprsd/client/drivers/aprsis.py
CHANGED
@@ -4,17 +4,20 @@ import select
|
|
4
4
|
import threading
|
5
5
|
|
6
6
|
import aprslib
|
7
|
+
import wrapt
|
7
8
|
from aprslib import is_py3
|
8
9
|
from aprslib.exceptions import (
|
9
|
-
ConnectionDrop,
|
10
|
+
ConnectionDrop,
|
11
|
+
ConnectionError,
|
12
|
+
GenericError,
|
13
|
+
LoginError,
|
14
|
+
ParseError,
|
10
15
|
UnknownFormat,
|
11
16
|
)
|
12
|
-
import wrapt
|
13
17
|
|
14
18
|
import aprsd
|
15
19
|
from aprsd.packets import core
|
16
20
|
|
17
|
-
|
18
21
|
LOG = logging.getLogger("APRSD")
|
19
22
|
|
20
23
|
|
aprsd/client/drivers/fake.py
CHANGED
@@ -3,20 +3,19 @@ import threading
|
|
3
3
|
import time
|
4
4
|
|
5
5
|
import aprslib
|
6
|
-
from oslo_config import cfg
|
7
6
|
import wrapt
|
7
|
+
from oslo_config import cfg
|
8
8
|
|
9
9
|
from aprsd import conf # noqa
|
10
10
|
from aprsd.packets import core
|
11
11
|
from aprsd.utils import trace
|
12
12
|
|
13
|
-
|
14
13
|
CONF = cfg.CONF
|
15
|
-
LOG = logging.getLogger(
|
14
|
+
LOG = logging.getLogger('APRSD')
|
16
15
|
|
17
16
|
|
18
17
|
class APRSDFakeClient(metaclass=trace.TraceWrapperMetaclass):
|
19
|
-
|
18
|
+
"""Fake client for testing."""
|
20
19
|
|
21
20
|
# flag to tell us to stop
|
22
21
|
thread_stop = False
|
@@ -25,12 +24,12 @@ class APRSDFakeClient(metaclass=trace.TraceWrapperMetaclass):
|
|
25
24
|
path = []
|
26
25
|
|
27
26
|
def __init__(self):
|
28
|
-
LOG.info(
|
29
|
-
self.path = [
|
27
|
+
LOG.info('Starting APRSDFakeClient client.')
|
28
|
+
self.path = ['WIDE1-1', 'WIDE2-1']
|
30
29
|
|
31
30
|
def stop(self):
|
32
31
|
self.thread_stop = True
|
33
|
-
LOG.info(
|
32
|
+
LOG.info('Shutdown APRSDFakeClient client.')
|
34
33
|
|
35
34
|
def is_alive(self):
|
36
35
|
"""If the connection is alive or not."""
|
@@ -39,35 +38,31 @@ class APRSDFakeClient(metaclass=trace.TraceWrapperMetaclass):
|
|
39
38
|
@wrapt.synchronized(lock)
|
40
39
|
def send(self, packet: core.Packet):
|
41
40
|
"""Send an APRS Message object."""
|
42
|
-
LOG.info(f
|
41
|
+
LOG.info(f'Sending packet: {packet}')
|
43
42
|
payload = None
|
44
43
|
if isinstance(packet, core.Packet):
|
45
44
|
packet.prepare()
|
46
|
-
payload = packet.payload.encode(
|
47
|
-
if packet.path:
|
48
|
-
packet.path
|
49
|
-
else:
|
50
|
-
self.path
|
45
|
+
payload = packet.payload.encode('US-ASCII')
|
51
46
|
else:
|
52
|
-
msg_payload = f
|
47
|
+
msg_payload = f'{packet.raw}{{{str(packet.msgNo)}'
|
53
48
|
payload = (
|
54
|
-
|
49
|
+
':{:<9}:{}'.format(
|
55
50
|
packet.to_call,
|
56
51
|
msg_payload,
|
57
52
|
)
|
58
|
-
).encode(
|
53
|
+
).encode('US-ASCII')
|
59
54
|
|
60
55
|
LOG.debug(
|
61
56
|
f"FAKE::Send '{payload}' TO '{packet.to_call}' From "
|
62
|
-
f
|
57
|
+
f'\'{packet.from_call}\' with PATH "{self.path}"',
|
63
58
|
)
|
64
59
|
|
65
60
|
def consumer(self, callback, blocking=False, immortal=False, raw=False):
|
66
|
-
LOG.debug(
|
61
|
+
LOG.debug('Start non blocking FAKE consumer')
|
67
62
|
# Generate packets here?
|
68
|
-
raw =
|
63
|
+
raw = 'GTOWN>APDW16,WIDE1-1,WIDE2-1:}KM6LYW-9>APZ100,TCPIP,GTOWN*::KM6LYW :KM6LYW: 19 Miles SW'
|
69
64
|
pkt_raw = aprslib.parse(raw)
|
70
65
|
pkt = core.factory(pkt_raw)
|
71
66
|
callback(packet=pkt)
|
72
|
-
LOG.debug(f
|
67
|
+
LOG.debug(f'END blocking FAKE consumer {self}')
|
73
68
|
time.sleep(8)
|
aprsd/client/factory.py
CHANGED
aprsd/client/fake.py
CHANGED
@@ -7,13 +7,11 @@ from aprsd.client import base
|
|
7
7
|
from aprsd.client.drivers import fake as fake_driver
|
8
8
|
from aprsd.utils import trace
|
9
9
|
|
10
|
-
|
11
10
|
CONF = cfg.CONF
|
12
11
|
LOG = logging.getLogger("APRSD")
|
13
12
|
|
14
13
|
|
15
14
|
class APRSDFakeClient(base.APRSClient, metaclass=trace.TraceWrapperMetaclass):
|
16
|
-
|
17
15
|
def stats(self, serializable=False) -> dict:
|
18
16
|
return {
|
19
17
|
"transport": "Fake",
|
aprsd/client/kiss.py
CHANGED
@@ -2,6 +2,8 @@ import datetime
|
|
2
2
|
import logging
|
3
3
|
|
4
4
|
import aprslib
|
5
|
+
import timeago
|
6
|
+
from loguru import logger
|
5
7
|
from oslo_config import cfg
|
6
8
|
|
7
9
|
from aprsd import client, exception
|
@@ -9,13 +11,12 @@ from aprsd.client import base
|
|
9
11
|
from aprsd.client.drivers import kiss
|
10
12
|
from aprsd.packets import core
|
11
13
|
|
12
|
-
|
13
14
|
CONF = cfg.CONF
|
14
15
|
LOG = logging.getLogger("APRSD")
|
16
|
+
LOGU = logger
|
15
17
|
|
16
18
|
|
17
19
|
class KISSClient(base.APRSClient):
|
18
|
-
|
19
20
|
_client = None
|
20
21
|
keepalive = datetime.datetime.now()
|
21
22
|
|
@@ -79,6 +80,20 @@ class KISSClient(base.APRSClient):
|
|
79
80
|
if self._client:
|
80
81
|
self._client.stop()
|
81
82
|
|
83
|
+
def keepalive_check(self):
|
84
|
+
# Don't check the first time through.
|
85
|
+
if not self.is_alive() and self._checks:
|
86
|
+
LOG.warning("Resetting client. It's not alive.")
|
87
|
+
self.reset()
|
88
|
+
self._checks = True
|
89
|
+
|
90
|
+
def keepalive_log(self):
|
91
|
+
if ka := self._client.aprsd_keepalive:
|
92
|
+
keepalive = timeago.format(ka)
|
93
|
+
else:
|
94
|
+
keepalive = "N/A"
|
95
|
+
LOGU.opt(colors=True).info(f"<green>Client keepalive {keepalive}</green>")
|
96
|
+
|
82
97
|
@staticmethod
|
83
98
|
def transport():
|
84
99
|
if CONF.kiss_serial.enabled:
|
aprsd/client/stats.py
CHANGED
@@ -1,18 +1,16 @@
|
|
1
1
|
import threading
|
2
2
|
|
3
|
-
from oslo_config import cfg
|
4
3
|
import wrapt
|
4
|
+
from oslo_config import cfg
|
5
5
|
|
6
6
|
from aprsd import client
|
7
7
|
from aprsd.utils import singleton
|
8
8
|
|
9
|
-
|
10
9
|
CONF = cfg.CONF
|
11
10
|
|
12
11
|
|
13
12
|
@singleton
|
14
13
|
class APRSClientStats:
|
15
|
-
|
16
14
|
lock = threading.Lock()
|
17
15
|
|
18
16
|
@wrapt.synchronized(lock)
|
aprsd/cmds/completion.py
CHANGED
@@ -3,12 +3,13 @@ import click.shell_completion
|
|
3
3
|
|
4
4
|
from aprsd.main import cli
|
5
5
|
|
6
|
-
|
7
6
|
CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])
|
8
7
|
|
9
8
|
|
10
9
|
@cli.command()
|
11
|
-
@click.argument(
|
10
|
+
@click.argument(
|
11
|
+
"shell", type=click.Choice(list(click.shell_completion._available_shells))
|
12
|
+
)
|
12
13
|
def completion(shell):
|
13
14
|
"""Show the shell completion code"""
|
14
15
|
from click.utils import _detect_program_name
|
@@ -17,6 +18,8 @@ def completion(shell):
|
|
17
18
|
prog_name = _detect_program_name()
|
18
19
|
complete_var = f"_{prog_name}_COMPLETE".replace("-", "_").upper()
|
19
20
|
print(cls(cli, {}, prog_name, complete_var).source())
|
20
|
-
print(
|
21
|
+
print(
|
22
|
+
"# Add the following line to your shell configuration file to have aprsd command line completion"
|
23
|
+
)
|
21
24
|
print("# but remove the leading '#' character.")
|
22
|
-
print(f
|
25
|
+
print(f'# eval "$(aprsd completion {shell})"')
|
aprsd/cmds/dev.py
CHANGED
@@ -9,18 +9,18 @@ import click
|
|
9
9
|
from oslo_config import cfg
|
10
10
|
|
11
11
|
from aprsd import cli_helper, conf, packets, plugin
|
12
|
+
|
12
13
|
# local imports here
|
13
14
|
from aprsd.client import base
|
14
15
|
from aprsd.main import cli
|
15
16
|
from aprsd.utils import trace
|
16
17
|
|
17
|
-
|
18
18
|
CONF = cfg.CONF
|
19
|
-
LOG = logging.getLogger(
|
20
|
-
CONTEXT_SETTINGS = dict(help_option_names=[
|
19
|
+
LOG = logging.getLogger('APRSD')
|
20
|
+
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
|
21
21
|
|
22
22
|
|
23
|
-
@cli.group(help=
|
23
|
+
@cli.group(help='Development type subcommands', context_settings=CONTEXT_SETTINGS)
|
24
24
|
@click.pass_context
|
25
25
|
def dev(ctx):
|
26
26
|
pass
|
@@ -29,37 +29,37 @@ def dev(ctx):
|
|
29
29
|
@dev.command()
|
30
30
|
@cli_helper.add_options(cli_helper.common_options)
|
31
31
|
@click.option(
|
32
|
-
|
33
|
-
envvar=
|
32
|
+
'--aprs-login',
|
33
|
+
envvar='APRS_LOGIN',
|
34
34
|
show_envvar=True,
|
35
|
-
help=
|
35
|
+
help='What callsign to send the message from.',
|
36
36
|
)
|
37
37
|
@click.option(
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
'-p',
|
39
|
+
'--plugin',
|
40
|
+
'plugin_path',
|
41
41
|
show_default=True,
|
42
42
|
default=None,
|
43
|
-
help=
|
43
|
+
help='The plugin to run. Ex: aprsd.plugins.ping.PingPlugin',
|
44
44
|
)
|
45
45
|
@click.option(
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
'-a',
|
47
|
+
'--all',
|
48
|
+
'load_all',
|
49
49
|
show_default=True,
|
50
50
|
is_flag=True,
|
51
51
|
default=False,
|
52
|
-
help=
|
52
|
+
help='Load all the plugins in config?',
|
53
53
|
)
|
54
54
|
@click.option(
|
55
|
-
|
56
|
-
|
57
|
-
|
55
|
+
'-n',
|
56
|
+
'--num',
|
57
|
+
'number',
|
58
58
|
show_default=True,
|
59
59
|
default=1,
|
60
|
-
help=
|
60
|
+
help='Number of times to call the plugin',
|
61
61
|
)
|
62
|
-
@click.argument(
|
62
|
+
@click.argument('message', nargs=-1, required=True)
|
63
63
|
@click.pass_context
|
64
64
|
@cli_helper.process_standard_options
|
65
65
|
def test_plugin(
|
@@ -76,7 +76,7 @@ def test_plugin(
|
|
76
76
|
|
77
77
|
if not aprs_login:
|
78
78
|
if CONF.aprs_network.login == conf.client.DEFAULT_LOGIN:
|
79
|
-
click.echo(
|
79
|
+
click.echo('Must set --aprs_login or APRS_LOGIN')
|
80
80
|
ctx.exit(-1)
|
81
81
|
return
|
82
82
|
else:
|
@@ -86,16 +86,16 @@ def test_plugin(
|
|
86
86
|
|
87
87
|
if not plugin_path:
|
88
88
|
click.echo(ctx.get_help())
|
89
|
-
click.echo(
|
90
|
-
click.echo(
|
89
|
+
click.echo('')
|
90
|
+
click.echo('Failed to provide -p option to test a plugin')
|
91
91
|
ctx.exit(-1)
|
92
92
|
return
|
93
93
|
|
94
94
|
if type(message) is tuple:
|
95
|
-
message =
|
95
|
+
message = ' '.join(message)
|
96
96
|
|
97
97
|
if CONF.trace_enabled:
|
98
|
-
trace.setup_tracing([
|
98
|
+
trace.setup_tracing(['method', 'api'])
|
99
99
|
|
100
100
|
base.APRSClient()
|
101
101
|
|
@@ -105,14 +105,15 @@ def test_plugin(
|
|
105
105
|
obj = pm._create_class(plugin_path, plugin.APRSDPluginBase)
|
106
106
|
if not obj:
|
107
107
|
click.echo(ctx.get_help())
|
108
|
-
click.echo(
|
108
|
+
click.echo('')
|
109
109
|
ctx.fail(f"Failed to create object from plugin path '{plugin_path}'")
|
110
110
|
ctx.exit()
|
111
111
|
|
112
112
|
# Register the plugin they wanted tested.
|
113
113
|
LOG.info(
|
114
|
-
|
115
|
-
obj.__class__,
|
114
|
+
'Testing plugin {} Version {}'.format(
|
115
|
+
obj.__class__,
|
116
|
+
obj.version,
|
116
117
|
),
|
117
118
|
)
|
118
119
|
pm.register_msg(obj)
|
@@ -125,7 +126,7 @@ def test_plugin(
|
|
125
126
|
)
|
126
127
|
LOG.info(f"P'{plugin_path}' F'{fromcall}' C'{message}'")
|
127
128
|
|
128
|
-
for
|
129
|
+
for _ in range(number):
|
129
130
|
replies = pm.run(packet)
|
130
131
|
# Plugin might have threads, so lets stop them so we can exit.
|
131
132
|
# obj.stop_threads()
|
@@ -146,17 +147,12 @@ def test_plugin(
|
|
146
147
|
elif isinstance(reply, packets.Packet):
|
147
148
|
# We have a message based object.
|
148
149
|
LOG.info(reply)
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
from_call=CONF.callsign,
|
158
|
-
to_call=fromcall,
|
159
|
-
message_text=reply,
|
160
|
-
),
|
161
|
-
)
|
150
|
+
elif reply is not packets.NULL_MESSAGE:
|
151
|
+
LOG.info(
|
152
|
+
packets.MessagePacket(
|
153
|
+
from_call=CONF.callsign,
|
154
|
+
to_call=fromcall,
|
155
|
+
message_text=reply,
|
156
|
+
),
|
157
|
+
)
|
162
158
|
pm.stop()
|