aprsd 3.4.3__py3-none-any.whl → 3.4.4__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/client/aprsis.py +39 -10
- aprsd/client/base.py +47 -10
- aprsd/client/drivers/aprsis.py +5 -2
- aprsd/client/factory.py +6 -1
- aprsd/client/fake.py +5 -2
- aprsd/client/kiss.py +26 -5
- aprsd/client/stats.py +1 -19
- aprsd/cmds/admin.py +57 -0
- aprsd/cmds/dev.py +1 -1
- aprsd/cmds/fetch_stats.py +155 -0
- aprsd/cmds/healthcheck.py +2 -2
- aprsd/cmds/listen.py +93 -6
- aprsd/cmds/server.py +18 -10
- aprsd/cmds/webchat.py +41 -53
- aprsd/conf/common.py +11 -0
- aprsd/main.py +10 -6
- aprsd/packets/core.py +28 -27
- aprsd/packets/packet_list.py +13 -23
- aprsd/plugin.py +12 -5
- aprsd/plugins/email.py +6 -0
- aprsd/plugins/fortune.py +2 -2
- aprsd/plugins/location.py +6 -4
- aprsd/stats/__init__.py +0 -2
- aprsd/stats/collector.py +6 -1
- aprsd/threads/aprsd.py +47 -5
- aprsd/threads/keep_alive.py +8 -0
- aprsd/threads/rx.py +40 -12
- aprsd/threads/tx.py +31 -6
- aprsd/utils/__init__.py +20 -5
- aprsd/utils/counter.py +15 -12
- aprsd/utils/trace.py +4 -2
- aprsd/web/chat/static/js/send-message.js +48 -21
- aprsd/wsgi.py +8 -1
- {aprsd-3.4.3.dist-info → aprsd-3.4.4.dist-info}/METADATA +89 -33
- {aprsd-3.4.3.dist-info → aprsd-3.4.4.dist-info}/RECORD +40 -39
- {aprsd-3.4.3.dist-info → aprsd-3.4.4.dist-info}/WHEEL +1 -1
- {aprsd-3.4.3.dist-info → aprsd-3.4.4.dist-info}/AUTHORS +0 -0
- {aprsd-3.4.3.dist-info → aprsd-3.4.4.dist-info}/LICENSE +0 -0
- {aprsd-3.4.3.dist-info → aprsd-3.4.4.dist-info}/entry_points.txt +0 -0
- {aprsd-3.4.3.dist-info → aprsd-3.4.4.dist-info}/top_level.txt +0 -0
aprsd/client/aprsis.py
CHANGED
@@ -23,13 +23,24 @@ class APRSISClient(base.APRSClient):
|
|
23
23
|
max_timeout = {"hours": 0.0, "minutes": 2, "seconds": 0}
|
24
24
|
self.max_delta = datetime.timedelta(**max_timeout)
|
25
25
|
|
26
|
-
def stats(self) -> dict:
|
26
|
+
def stats(self, serializable=False) -> dict:
|
27
27
|
stats = {}
|
28
28
|
if self.is_configured():
|
29
|
+
if self._client:
|
30
|
+
keepalive = self._client.aprsd_keepalive
|
31
|
+
server_string = self._client.server_string
|
32
|
+
if serializable:
|
33
|
+
keepalive = keepalive.isoformat()
|
34
|
+
else:
|
35
|
+
keepalive = "None"
|
36
|
+
server_string = "None"
|
29
37
|
stats = {
|
30
|
-
"
|
31
|
-
"sever_keepalive": self._client.aprsd_keepalive,
|
38
|
+
"connected": self.is_connected,
|
32
39
|
"filter": self.filter,
|
40
|
+
"login_status": self.login_status,
|
41
|
+
"connection_keepalive": keepalive,
|
42
|
+
"server_string": server_string,
|
43
|
+
"transport": self.transport(),
|
33
44
|
}
|
34
45
|
|
35
46
|
return stats
|
@@ -99,22 +110,31 @@ class APRSISClient(base.APRSClient):
|
|
99
110
|
self.connected = False
|
100
111
|
backoff = 1
|
101
112
|
aprs_client = None
|
113
|
+
retries = 3
|
114
|
+
retry_count = 0
|
102
115
|
while not self.connected:
|
116
|
+
retry_count += 1
|
117
|
+
if retry_count >= retries:
|
118
|
+
break
|
103
119
|
try:
|
104
120
|
LOG.info(f"Creating aprslib client({host}:{port}) and logging in {user}.")
|
105
121
|
aprs_client = aprsis.Aprsdis(user, passwd=password, host=host, port=port)
|
106
122
|
# Force the log to be the same
|
107
123
|
aprs_client.logger = LOG
|
108
124
|
aprs_client.connect()
|
109
|
-
self.connected = True
|
125
|
+
self.connected = self.login_status["success"] = True
|
126
|
+
self.login_status["message"] = aprs_client.server_string
|
110
127
|
backoff = 1
|
111
128
|
except LoginError as e:
|
112
129
|
LOG.error(f"Failed to login to APRS-IS Server '{e}'")
|
113
|
-
self.connected = False
|
130
|
+
self.connected = self.login_status["success"] = False
|
131
|
+
self.login_status["message"] = e.message
|
132
|
+
LOG.error(e.message)
|
114
133
|
time.sleep(backoff)
|
115
134
|
except Exception as e:
|
116
135
|
LOG.error(f"Unable to connect to APRS-IS server. '{e}' ")
|
117
|
-
self.connected = False
|
136
|
+
self.connected = self.login_status["success"] = False
|
137
|
+
self.login_status["message"] = e.message
|
118
138
|
time.sleep(backoff)
|
119
139
|
# Don't allow the backoff to go to inifinity.
|
120
140
|
if backoff > 5:
|
@@ -126,7 +146,16 @@ class APRSISClient(base.APRSClient):
|
|
126
146
|
return aprs_client
|
127
147
|
|
128
148
|
def consumer(self, callback, blocking=False, immortal=False, raw=False):
|
129
|
-
self._client
|
130
|
-
|
131
|
-
|
132
|
-
|
149
|
+
if self._client:
|
150
|
+
try:
|
151
|
+
self._client.consumer(
|
152
|
+
callback, blocking=blocking,
|
153
|
+
immortal=immortal, raw=raw,
|
154
|
+
)
|
155
|
+
except Exception as e:
|
156
|
+
LOG.error(e)
|
157
|
+
LOG.info(e.__cause__)
|
158
|
+
raise e
|
159
|
+
else:
|
160
|
+
LOG.warning("client is None, might be resetting.")
|
161
|
+
self.connected = False
|
aprsd/client/base.py
CHANGED
@@ -19,6 +19,10 @@ class APRSClient:
|
|
19
19
|
_client = None
|
20
20
|
|
21
21
|
connected = False
|
22
|
+
login_status = {
|
23
|
+
"success": False,
|
24
|
+
"message": None,
|
25
|
+
}
|
22
26
|
filter = None
|
23
27
|
lock = threading.Lock()
|
24
28
|
|
@@ -32,7 +36,23 @@ class APRSClient:
|
|
32
36
|
|
33
37
|
@abc.abstractmethod
|
34
38
|
def stats(self) -> dict:
|
35
|
-
|
39
|
+
"""Return statistics about the client connection.
|
40
|
+
|
41
|
+
Returns:
|
42
|
+
dict: Statistics about the connection and packet handling
|
43
|
+
"""
|
44
|
+
|
45
|
+
@property
|
46
|
+
def is_connected(self):
|
47
|
+
return self.connected
|
48
|
+
|
49
|
+
@property
|
50
|
+
def login_success(self):
|
51
|
+
return self.login_status.get("success", False)
|
52
|
+
|
53
|
+
@property
|
54
|
+
def login_failure(self):
|
55
|
+
return self.login_status["message"]
|
36
56
|
|
37
57
|
def set_filter(self, filter):
|
38
58
|
self.filter = filter
|
@@ -46,22 +66,31 @@ class APRSClient:
|
|
46
66
|
return self._client
|
47
67
|
|
48
68
|
def _create_client(self):
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
69
|
+
try:
|
70
|
+
self._client = self.setup_connection()
|
71
|
+
if self.filter:
|
72
|
+
LOG.info("Creating APRS client filter")
|
73
|
+
self._client.set_filter(self.filter)
|
74
|
+
except Exception as e:
|
75
|
+
LOG.error(f"Failed to create APRS client: {e}")
|
76
|
+
self._client = None
|
77
|
+
raise
|
53
78
|
|
54
79
|
def stop(self):
|
55
80
|
if self._client:
|
56
81
|
LOG.info("Stopping client connection.")
|
57
82
|
self._client.stop()
|
58
83
|
|
59
|
-
def send(self, packet: core.Packet):
|
60
|
-
"""Send a packet to the network.
|
84
|
+
def send(self, packet: core.Packet) -> None:
|
85
|
+
"""Send a packet to the network.
|
86
|
+
|
87
|
+
Args:
|
88
|
+
packet: The APRS packet to send
|
89
|
+
"""
|
61
90
|
self.client.send(packet)
|
62
91
|
|
63
92
|
@wrapt.synchronized(lock)
|
64
|
-
def reset(self):
|
93
|
+
def reset(self) -> None:
|
65
94
|
"""Call this to force a rebuild/reconnect."""
|
66
95
|
LOG.info("Resetting client connection.")
|
67
96
|
if self._client:
|
@@ -76,7 +105,11 @@ class APRSClient:
|
|
76
105
|
|
77
106
|
@abc.abstractmethod
|
78
107
|
def setup_connection(self):
|
79
|
-
|
108
|
+
"""Initialize and return the underlying APRS connection.
|
109
|
+
|
110
|
+
Returns:
|
111
|
+
object: The initialized connection object
|
112
|
+
"""
|
80
113
|
|
81
114
|
@staticmethod
|
82
115
|
@abc.abstractmethod
|
@@ -90,7 +123,11 @@ class APRSClient:
|
|
90
123
|
|
91
124
|
@abc.abstractmethod
|
92
125
|
def decode_packet(self, *args, **kwargs):
|
93
|
-
|
126
|
+
"""Decode raw APRS packet data into a Packet object.
|
127
|
+
|
128
|
+
Returns:
|
129
|
+
Packet: Decoded APRS packet
|
130
|
+
"""
|
94
131
|
|
95
132
|
@abc.abstractmethod
|
96
133
|
def consumer(self, callback, blocking=False, immortal=False, raw=False):
|
aprsd/client/drivers/aprsis.py
CHANGED
@@ -27,6 +27,9 @@ class Aprsdis(aprslib.IS):
|
|
27
27
|
# date for last time we heard from the server
|
28
28
|
aprsd_keepalive = datetime.datetime.now()
|
29
29
|
|
30
|
+
# Which server we are connected to?
|
31
|
+
server_string = "None"
|
32
|
+
|
30
33
|
# timeout in seconds
|
31
34
|
select_timeout = 1
|
32
35
|
lock = threading.Lock()
|
@@ -193,14 +196,14 @@ class Aprsdis(aprslib.IS):
|
|
193
196
|
except ParseError as exp:
|
194
197
|
self.logger.log(
|
195
198
|
11,
|
196
|
-
"%s
|
199
|
+
"%s Packet: '%s'",
|
197
200
|
exp,
|
198
201
|
exp.packet,
|
199
202
|
)
|
200
203
|
except UnknownFormat as exp:
|
201
204
|
self.logger.log(
|
202
205
|
9,
|
203
|
-
"%s
|
206
|
+
"%s Packet: '%s'",
|
204
207
|
exp,
|
205
208
|
exp.packet,
|
206
209
|
)
|
aprsd/client/factory.py
CHANGED
@@ -42,6 +42,7 @@ class Client(Protocol):
|
|
42
42
|
class ClientFactory:
|
43
43
|
_instance = None
|
44
44
|
clients = []
|
45
|
+
client = None
|
45
46
|
|
46
47
|
def __new__(cls, *args, **kwargs):
|
47
48
|
"""This magic turns this into a singleton."""
|
@@ -62,9 +63,13 @@ class ClientFactory:
|
|
62
63
|
def create(self, key=None):
|
63
64
|
for client in self.clients:
|
64
65
|
if client.is_enabled():
|
65
|
-
|
66
|
+
self.client = client()
|
67
|
+
return self.client
|
66
68
|
raise Exception("No client is configured!!")
|
67
69
|
|
70
|
+
def client_exists(self):
|
71
|
+
return bool(self.client)
|
72
|
+
|
68
73
|
def is_client_enabled(self):
|
69
74
|
"""Make sure at least one client is enabled."""
|
70
75
|
enabled = False
|
aprsd/client/fake.py
CHANGED
@@ -14,8 +14,11 @@ LOG = logging.getLogger("APRSD")
|
|
14
14
|
|
15
15
|
class APRSDFakeClient(base.APRSClient, metaclass=trace.TraceWrapperMetaclass):
|
16
16
|
|
17
|
-
def stats(self) -> dict:
|
18
|
-
return {
|
17
|
+
def stats(self, serializable=False) -> dict:
|
18
|
+
return {
|
19
|
+
"transport": "Fake",
|
20
|
+
"connected": True,
|
21
|
+
}
|
19
22
|
|
20
23
|
@staticmethod
|
21
24
|
def is_enabled():
|
aprsd/client/kiss.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import datetime
|
1
2
|
import logging
|
2
3
|
|
3
4
|
import aprslib
|
@@ -16,13 +17,24 @@ LOG = logging.getLogger("APRSD")
|
|
16
17
|
class KISSClient(base.APRSClient):
|
17
18
|
|
18
19
|
_client = None
|
20
|
+
keepalive = datetime.datetime.now()
|
19
21
|
|
20
|
-
def stats(self) -> dict:
|
22
|
+
def stats(self, serializable=False) -> dict:
|
21
23
|
stats = {}
|
22
24
|
if self.is_configured():
|
23
|
-
|
25
|
+
keepalive = self.keepalive
|
26
|
+
if serializable:
|
27
|
+
keepalive = keepalive.isoformat()
|
28
|
+
stats = {
|
29
|
+
"connected": self.is_connected,
|
30
|
+
"connection_keepalive": keepalive,
|
24
31
|
"transport": self.transport(),
|
25
32
|
}
|
33
|
+
if self.transport() == client.TRANSPORT_TCPKISS:
|
34
|
+
stats["host"] = CONF.kiss_tcp.host
|
35
|
+
stats["port"] = CONF.kiss_tcp.port
|
36
|
+
elif self.transport() == client.TRANSPORT_SERIALKISS:
|
37
|
+
stats["device"] = CONF.kiss_serial.device
|
26
38
|
return stats
|
27
39
|
|
28
40
|
@staticmethod
|
@@ -95,9 +107,18 @@ class KISSClient(base.APRSClient):
|
|
95
107
|
return packet
|
96
108
|
|
97
109
|
def setup_connection(self):
|
98
|
-
|
99
|
-
|
110
|
+
try:
|
111
|
+
self._client = kiss.KISS3Client()
|
112
|
+
self.connected = self.login_status["success"] = True
|
113
|
+
except Exception as ex:
|
114
|
+
self.connected = self.login_status["success"] = False
|
115
|
+
self.login_status["message"] = str(ex)
|
100
116
|
return self._client
|
101
117
|
|
102
118
|
def consumer(self, callback, blocking=False, immortal=False, raw=False):
|
103
|
-
|
119
|
+
try:
|
120
|
+
self._client.consumer(callback)
|
121
|
+
self.keepalive = datetime.datetime.now()
|
122
|
+
except Exception as ex:
|
123
|
+
LOG.error(f"Consumer failed {ex}")
|
124
|
+
LOG.error(ex)
|
aprsd/client/stats.py
CHANGED
@@ -17,22 +17,4 @@ class APRSClientStats:
|
|
17
17
|
|
18
18
|
@wrapt.synchronized(lock)
|
19
19
|
def stats(self, serializable=False):
|
20
|
-
|
21
|
-
stats = {
|
22
|
-
"transport": cl.transport(),
|
23
|
-
"filter": cl.filter,
|
24
|
-
"connected": cl.connected,
|
25
|
-
}
|
26
|
-
|
27
|
-
if cl.transport() == client.TRANSPORT_APRSIS:
|
28
|
-
stats["server_string"] = cl.client.server_string
|
29
|
-
keepalive = cl.client.aprsd_keepalive
|
30
|
-
if serializable:
|
31
|
-
keepalive = keepalive.isoformat()
|
32
|
-
stats["server_keepalive"] = keepalive
|
33
|
-
elif cl.transport() == client.TRANSPORT_TCPKISS:
|
34
|
-
stats["host"] = CONF.kiss_tcp.host
|
35
|
-
stats["port"] = CONF.kiss_tcp.port
|
36
|
-
elif cl.transport() == client.TRANSPORT_SERIALKISS:
|
37
|
-
stats["device"] = CONF.kiss_serial.device
|
38
|
-
return stats
|
20
|
+
return client.client_factory.create().stats(serializable=serializable)
|
aprsd/cmds/admin.py
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
import logging
|
2
|
+
import os
|
3
|
+
import signal
|
4
|
+
|
5
|
+
import click
|
6
|
+
from oslo_config import cfg
|
7
|
+
import socketio
|
8
|
+
|
9
|
+
import aprsd
|
10
|
+
from aprsd import cli_helper
|
11
|
+
from aprsd import main as aprsd_main
|
12
|
+
from aprsd import utils
|
13
|
+
from aprsd.main import cli
|
14
|
+
|
15
|
+
|
16
|
+
os.environ["APRSD_ADMIN_COMMAND"] = "1"
|
17
|
+
# this import has to happen AFTER we set the
|
18
|
+
# above environment variable, so that the code
|
19
|
+
# inside the wsgi.py has the value
|
20
|
+
from aprsd import wsgi as aprsd_wsgi # noqa
|
21
|
+
|
22
|
+
|
23
|
+
CONF = cfg.CONF
|
24
|
+
LOG = logging.getLogger("APRSD")
|
25
|
+
|
26
|
+
|
27
|
+
# main() ###
|
28
|
+
@cli.command()
|
29
|
+
@cli_helper.add_options(cli_helper.common_options)
|
30
|
+
@click.pass_context
|
31
|
+
@cli_helper.process_standard_options
|
32
|
+
def admin(ctx):
|
33
|
+
"""Start the aprsd admin interface."""
|
34
|
+
signal.signal(signal.SIGINT, aprsd_main.signal_handler)
|
35
|
+
signal.signal(signal.SIGTERM, aprsd_main.signal_handler)
|
36
|
+
|
37
|
+
level, msg = utils._check_version()
|
38
|
+
if level:
|
39
|
+
LOG.warning(msg)
|
40
|
+
else:
|
41
|
+
LOG.info(msg)
|
42
|
+
LOG.info(f"APRSD Started version: {aprsd.__version__}")
|
43
|
+
# Dump all the config options now.
|
44
|
+
CONF.log_opt_values(LOG, logging.DEBUG)
|
45
|
+
|
46
|
+
async_mode = "threading"
|
47
|
+
sio = socketio.Server(logger=True, async_mode=async_mode)
|
48
|
+
aprsd_wsgi.app.wsgi_app = socketio.WSGIApp(sio, aprsd_wsgi.app.wsgi_app)
|
49
|
+
aprsd_wsgi.init_app()
|
50
|
+
sio.register_namespace(aprsd_wsgi.LoggingNamespace("/logs"))
|
51
|
+
CONF.log_opt_values(LOG, logging.DEBUG)
|
52
|
+
aprsd_wsgi.app.run(
|
53
|
+
threaded=True,
|
54
|
+
debug=False,
|
55
|
+
port=CONF.admin.web_port,
|
56
|
+
host=CONF.admin.web_ip,
|
57
|
+
)
|
aprsd/cmds/dev.py
CHANGED
@@ -101,7 +101,7 @@ def test_plugin(
|
|
101
101
|
|
102
102
|
pm = plugin.PluginManager()
|
103
103
|
if load_all:
|
104
|
-
pm.setup_plugins()
|
104
|
+
pm.setup_plugins(load_help_plugin=CONF.load_help_plugin)
|
105
105
|
obj = pm._create_class(plugin_path, plugin.APRSDPluginBase)
|
106
106
|
if not obj:
|
107
107
|
click.echo(ctx.get_help())
|
aprsd/cmds/fetch_stats.py
CHANGED
@@ -11,6 +11,7 @@ from rich.table import Table
|
|
11
11
|
import aprsd
|
12
12
|
from aprsd import cli_helper
|
13
13
|
from aprsd.main import cli
|
14
|
+
from aprsd.threads.stats import StatsStore
|
14
15
|
|
15
16
|
|
16
17
|
# setup the global logger
|
@@ -154,3 +155,157 @@ def fetch_stats(ctx, host, port):
|
|
154
155
|
watch_table.add_row(key, value["last"])
|
155
156
|
|
156
157
|
console.print(watch_table)
|
158
|
+
|
159
|
+
|
160
|
+
@cli.command()
|
161
|
+
@cli_helper.add_options(cli_helper.common_options)
|
162
|
+
@click.option(
|
163
|
+
"--raw",
|
164
|
+
is_flag=True,
|
165
|
+
default=False,
|
166
|
+
help="Dump raw stats instead of formatted output.",
|
167
|
+
)
|
168
|
+
@click.option(
|
169
|
+
"--show-section",
|
170
|
+
default=["All"],
|
171
|
+
help="Show specific sections of the stats. "
|
172
|
+
" Choices: All, APRSDStats, APRSDThreadList, APRSClientStats,"
|
173
|
+
" PacketList, SeenList, WatchList",
|
174
|
+
multiple=True,
|
175
|
+
type=click.Choice(
|
176
|
+
[
|
177
|
+
"All",
|
178
|
+
"APRSDStats",
|
179
|
+
"APRSDThreadList",
|
180
|
+
"APRSClientStats",
|
181
|
+
"PacketList",
|
182
|
+
"SeenList",
|
183
|
+
"WatchList",
|
184
|
+
],
|
185
|
+
case_sensitive=False,
|
186
|
+
),
|
187
|
+
)
|
188
|
+
@click.pass_context
|
189
|
+
@cli_helper.process_standard_options
|
190
|
+
def dump_stats(ctx, raw, show_section):
|
191
|
+
"""Dump the current stats from the running APRSD instance."""
|
192
|
+
console = Console()
|
193
|
+
console.print(f"APRSD Dump-Stats started version: {aprsd.__version__}")
|
194
|
+
|
195
|
+
with console.status("Dumping stats"):
|
196
|
+
ss = StatsStore()
|
197
|
+
ss.load()
|
198
|
+
stats = ss.data
|
199
|
+
if raw:
|
200
|
+
if "All" in show_section:
|
201
|
+
console.print(stats)
|
202
|
+
return
|
203
|
+
else:
|
204
|
+
for section in show_section:
|
205
|
+
console.print(f"Dumping {section} section:")
|
206
|
+
console.print(stats[section])
|
207
|
+
return
|
208
|
+
|
209
|
+
t = Table(title="APRSD Stats")
|
210
|
+
t.add_column("Key")
|
211
|
+
t.add_column("Value")
|
212
|
+
for key, value in stats["APRSDStats"].items():
|
213
|
+
t.add_row(key, str(value))
|
214
|
+
|
215
|
+
if "All" in show_section or "APRSDStats" in show_section:
|
216
|
+
console.print(t)
|
217
|
+
|
218
|
+
# Show the thread list
|
219
|
+
t = Table(title="Thread List")
|
220
|
+
t.add_column("Name")
|
221
|
+
t.add_column("Class")
|
222
|
+
t.add_column("Alive?")
|
223
|
+
t.add_column("Loop Count")
|
224
|
+
t.add_column("Age")
|
225
|
+
for name, value in stats["APRSDThreadList"].items():
|
226
|
+
t.add_row(
|
227
|
+
name,
|
228
|
+
value["class"],
|
229
|
+
str(value["alive"]),
|
230
|
+
str(value["loop_count"]),
|
231
|
+
str(value["age"]),
|
232
|
+
)
|
233
|
+
|
234
|
+
if "All" in show_section or "APRSDThreadList" in show_section:
|
235
|
+
console.print(t)
|
236
|
+
|
237
|
+
# Show the plugins
|
238
|
+
t = Table(title="Plugin List")
|
239
|
+
t.add_column("Name")
|
240
|
+
t.add_column("Enabled")
|
241
|
+
t.add_column("Version")
|
242
|
+
t.add_column("TX")
|
243
|
+
t.add_column("RX")
|
244
|
+
for name, value in stats["PluginManager"].items():
|
245
|
+
t.add_row(
|
246
|
+
name,
|
247
|
+
str(value["enabled"]),
|
248
|
+
value["version"],
|
249
|
+
str(value["tx"]),
|
250
|
+
str(value["rx"]),
|
251
|
+
)
|
252
|
+
|
253
|
+
if "All" in show_section or "PluginManager" in show_section:
|
254
|
+
console.print(t)
|
255
|
+
|
256
|
+
# Now show the client stats
|
257
|
+
t = Table(title="Client Stats")
|
258
|
+
t.add_column("Key")
|
259
|
+
t.add_column("Value")
|
260
|
+
for key, value in stats["APRSClientStats"].items():
|
261
|
+
t.add_row(key, str(value))
|
262
|
+
|
263
|
+
if "All" in show_section or "APRSClientStats" in show_section:
|
264
|
+
console.print(t)
|
265
|
+
|
266
|
+
# now show the packet list
|
267
|
+
packet_list = stats.get("PacketList")
|
268
|
+
t = Table(title="Packet List")
|
269
|
+
t.add_column("Key")
|
270
|
+
t.add_column("Value")
|
271
|
+
t.add_row("Total Received", str(packet_list["rx"]))
|
272
|
+
t.add_row("Total Sent", str(packet_list["tx"]))
|
273
|
+
|
274
|
+
if "All" in show_section or "PacketList" in show_section:
|
275
|
+
console.print(t)
|
276
|
+
|
277
|
+
# now show the seen list
|
278
|
+
seen_list = stats.get("SeenList")
|
279
|
+
sorted_seen_list = sorted(
|
280
|
+
seen_list.items(),
|
281
|
+
)
|
282
|
+
t = Table(title="Seen List")
|
283
|
+
t.add_column("Callsign")
|
284
|
+
t.add_column("Message Count")
|
285
|
+
t.add_column("Last Heard")
|
286
|
+
for key, value in sorted_seen_list:
|
287
|
+
t.add_row(
|
288
|
+
key,
|
289
|
+
str(value["count"]),
|
290
|
+
str(value["last"]),
|
291
|
+
)
|
292
|
+
|
293
|
+
if "All" in show_section or "SeenList" in show_section:
|
294
|
+
console.print(t)
|
295
|
+
|
296
|
+
# now show the watch list
|
297
|
+
watch_list = stats.get("WatchList")
|
298
|
+
sorted_watch_list = sorted(
|
299
|
+
watch_list.items(),
|
300
|
+
)
|
301
|
+
t = Table(title="Watch List")
|
302
|
+
t.add_column("Callsign")
|
303
|
+
t.add_column("Last Heard")
|
304
|
+
for key, value in sorted_watch_list:
|
305
|
+
t.add_row(
|
306
|
+
key,
|
307
|
+
str(value["last"]),
|
308
|
+
)
|
309
|
+
|
310
|
+
if "All" in show_section or "WatchList" in show_section:
|
311
|
+
console.print(t)
|
aprsd/cmds/healthcheck.py
CHANGED
@@ -63,7 +63,7 @@ def healthcheck(ctx, timeout):
|
|
63
63
|
|
64
64
|
if email_thread_last_update != "never":
|
65
65
|
d = now - email_thread_last_update
|
66
|
-
max_timeout = {"hours": 0.0, "minutes": 5, "seconds":
|
66
|
+
max_timeout = {"hours": 0.0, "minutes": 5, "seconds": 30}
|
67
67
|
max_delta = datetime.timedelta(**max_timeout)
|
68
68
|
if d > max_delta:
|
69
69
|
console.log(f"Email thread is very old! {d}")
|
@@ -74,7 +74,7 @@ def healthcheck(ctx, timeout):
|
|
74
74
|
console.log("No APRSClientStats")
|
75
75
|
sys.exit(-1)
|
76
76
|
else:
|
77
|
-
aprsis_last_update = client_stats["
|
77
|
+
aprsis_last_update = client_stats["connection_keepalive"]
|
78
78
|
d = now - aprsis_last_update
|
79
79
|
max_timeout = {"hours": 0.0, "minutes": 5, "seconds": 0}
|
80
80
|
max_delta = datetime.timedelta(**max_timeout)
|