aprsd 4.0.1__py3-none-any.whl → 4.1.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/client/drivers/aprsis.py +87 -35
- aprsd/client/drivers/fake.py +5 -0
- aprsd/client/drivers/kiss.py +45 -20
- aprsd/client/kiss.py +29 -25
- aprsd/cmds/listen.py +84 -91
- aprsd/cmds/server.py +1 -1
- aprsd/conf/common.py +100 -101
- aprsd/conf/log.py +27 -22
- aprsd/log/log.py +24 -14
- aprsd/packets/__init__.py +6 -0
- aprsd/packets/core.py +5 -2
- aprsd/packets/filter.py +58 -0
- aprsd/packets/filters/__init__.py +0 -0
- aprsd/packets/filters/dupe_filter.py +68 -0
- aprsd/packets/filters/packet_type.py +53 -0
- aprsd/packets/packet_list.py +33 -27
- aprsd/plugins/fortune.py +21 -15
- aprsd/threads/__init__.py +1 -2
- aprsd/threads/rx.py +83 -75
- aprsd/threads/stats.py +4 -9
- aprsd/utils/objectstore.py +12 -13
- {aprsd-4.0.1.dist-info → aprsd-4.1.0.dist-info}/METADATA +1 -1
- {aprsd-4.0.1.dist-info → aprsd-4.1.0.dist-info}/RECORD +28 -24
- {aprsd-4.0.1.dist-info → aprsd-4.1.0.dist-info}/AUTHORS +0 -0
- {aprsd-4.0.1.dist-info → aprsd-4.1.0.dist-info}/LICENSE +0 -0
- {aprsd-4.0.1.dist-info → aprsd-4.1.0.dist-info}/WHEEL +0 -0
- {aprsd-4.0.1.dist-info → aprsd-4.1.0.dist-info}/entry_points.txt +0 -0
- {aprsd-4.0.1.dist-info → aprsd-4.1.0.dist-info}/top_level.txt +0 -0
aprsd/cmds/listen.py
CHANGED
@@ -20,8 +20,10 @@ from aprsd import cli_helper, packets, plugin, threads, utils
|
|
20
20
|
from aprsd.client import client_factory
|
21
21
|
from aprsd.main import cli
|
22
22
|
from aprsd.packets import collector as packet_collector
|
23
|
+
from aprsd.packets import core, seen_list
|
23
24
|
from aprsd.packets import log as packet_log
|
24
|
-
from aprsd.packets import
|
25
|
+
from aprsd.packets.filter import PacketFilter
|
26
|
+
from aprsd.packets.filters import dupe_filter, packet_type
|
25
27
|
from aprsd.stats import collector
|
26
28
|
from aprsd.threads import keepalive, rx
|
27
29
|
from aprsd.threads import stats as stats_thread
|
@@ -29,7 +31,7 @@ from aprsd.threads.aprsd import APRSDThread
|
|
29
31
|
|
30
32
|
# setup the global logger
|
31
33
|
# log.basicConfig(level=log.DEBUG) # level=10
|
32
|
-
LOG = logging.getLogger(
|
34
|
+
LOG = logging.getLogger('APRSD')
|
33
35
|
CONF = cfg.CONF
|
34
36
|
LOGU = logger
|
35
37
|
console = Console()
|
@@ -37,9 +39,9 @@ console = Console()
|
|
37
39
|
|
38
40
|
def signal_handler(sig, frame):
|
39
41
|
threads.APRSDThreadList().stop_all()
|
40
|
-
if
|
42
|
+
if 'subprocess' not in str(frame):
|
41
43
|
LOG.info(
|
42
|
-
|
44
|
+
'Ctrl+C, Sending all threads exit! Can take up to 10 seconds {}'.format(
|
43
45
|
datetime.datetime.now(),
|
44
46
|
),
|
45
47
|
)
|
@@ -48,90 +50,66 @@ def signal_handler(sig, frame):
|
|
48
50
|
collector.Collector().collect()
|
49
51
|
|
50
52
|
|
51
|
-
class
|
53
|
+
class APRSDListenProcessThread(rx.APRSDFilterThread):
|
52
54
|
def __init__(
|
53
55
|
self,
|
54
56
|
packet_queue,
|
55
57
|
packet_filter=None,
|
56
58
|
plugin_manager=None,
|
57
|
-
enabled_plugins=
|
59
|
+
enabled_plugins=None,
|
58
60
|
log_packets=False,
|
59
61
|
):
|
60
|
-
super().__init__(packet_queue)
|
62
|
+
super().__init__('ListenProcThread', packet_queue)
|
61
63
|
self.packet_filter = packet_filter
|
62
64
|
self.plugin_manager = plugin_manager
|
63
65
|
if self.plugin_manager:
|
64
|
-
LOG.info(f
|
66
|
+
LOG.info(f'Plugins {self.plugin_manager.get_message_plugins()}')
|
65
67
|
self.log_packets = log_packets
|
66
68
|
|
67
|
-
def
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
packets.ObjectPacket.__name__: packets.ObjectPacket,
|
77
|
-
packets.StatusPacket.__name__: packets.StatusPacket,
|
78
|
-
packets.ThirdPartyPacket.__name__: packets.ThirdPartyPacket,
|
79
|
-
packets.WeatherPacket.__name__: packets.WeatherPacket,
|
80
|
-
packets.UnknownPacket.__name__: packets.UnknownPacket,
|
81
|
-
}
|
82
|
-
|
83
|
-
if self.packet_filter:
|
84
|
-
filter_class = filters[self.packet_filter]
|
85
|
-
if isinstance(packet, filter_class):
|
86
|
-
if self.log_packets:
|
87
|
-
packet_log.log(packet)
|
88
|
-
if self.plugin_manager:
|
89
|
-
# Don't do anything with the reply
|
90
|
-
# This is the listen only command.
|
91
|
-
self.plugin_manager.run(packet)
|
92
|
-
else:
|
93
|
-
if self.log_packets:
|
94
|
-
packet_log.log(packet)
|
95
|
-
if self.plugin_manager:
|
96
|
-
# Don't do anything with the reply.
|
97
|
-
# This is the listen only command.
|
98
|
-
self.plugin_manager.run(packet)
|
99
|
-
|
100
|
-
packet_collector.PacketCollector().rx(packet)
|
69
|
+
def print_packet(self, packet):
|
70
|
+
if self.log_packets:
|
71
|
+
packet_log.log(packet)
|
72
|
+
|
73
|
+
def process_packet(self, packet: type[core.Packet]):
|
74
|
+
if self.plugin_manager:
|
75
|
+
# Don't do anything with the reply.
|
76
|
+
# This is the listen only command.
|
77
|
+
self.plugin_manager.run(packet)
|
101
78
|
|
102
79
|
|
103
80
|
class ListenStatsThread(APRSDThread):
|
104
81
|
"""Log the stats from the PacketList."""
|
105
82
|
|
106
83
|
def __init__(self):
|
107
|
-
super().__init__(
|
84
|
+
super().__init__('PacketStatsLog')
|
108
85
|
self._last_total_rx = 0
|
86
|
+
self.period = 31
|
109
87
|
|
110
88
|
def loop(self):
|
111
|
-
if self.loop_count %
|
89
|
+
if self.loop_count % self.period == 0:
|
112
90
|
# log the stats every 10 seconds
|
113
91
|
stats_json = collector.Collector().collect()
|
114
|
-
stats = stats_json[
|
115
|
-
total_rx = stats[
|
116
|
-
packet_count = len(stats[
|
92
|
+
stats = stats_json['PacketList']
|
93
|
+
total_rx = stats['rx']
|
94
|
+
packet_count = len(stats['packets'])
|
117
95
|
rx_delta = total_rx - self._last_total_rx
|
118
|
-
rate = rx_delta /
|
96
|
+
rate = rx_delta / self.period
|
119
97
|
|
120
98
|
# Log summary stats
|
121
99
|
LOGU.opt(colors=True).info(
|
122
|
-
f
|
123
|
-
f
|
124
|
-
f
|
125
|
-
f
|
100
|
+
f'<green>RX Rate: {rate:.2f} pps</green> '
|
101
|
+
f'<yellow>Total RX: {total_rx}</yellow> '
|
102
|
+
f'<red>RX Last {self.period} secs: {rx_delta}</red> '
|
103
|
+
f'<white>Packets in PacketListStats: {packet_count}</white>',
|
126
104
|
)
|
127
105
|
self._last_total_rx = total_rx
|
128
106
|
|
129
107
|
# Log individual type stats
|
130
|
-
for k, v in stats[
|
131
|
-
thread_hex = f
|
108
|
+
for k, v in stats['types'].items():
|
109
|
+
thread_hex = f'fg {utils.hex_from_name(k)}'
|
132
110
|
LOGU.opt(colors=True).info(
|
133
|
-
f
|
134
|
-
f
|
111
|
+
f'<{thread_hex}>{k:<15}</{thread_hex}> '
|
112
|
+
f'<blue>RX: {v["rx"]}</blue> <red>TX: {v["tx"]}</red>',
|
135
113
|
)
|
136
114
|
|
137
115
|
time.sleep(1)
|
@@ -141,19 +119,19 @@ class ListenStatsThread(APRSDThread):
|
|
141
119
|
@cli.command()
|
142
120
|
@cli_helper.add_options(cli_helper.common_options)
|
143
121
|
@click.option(
|
144
|
-
|
145
|
-
envvar=
|
122
|
+
'--aprs-login',
|
123
|
+
envvar='APRS_LOGIN',
|
146
124
|
show_envvar=True,
|
147
|
-
help=
|
125
|
+
help='What callsign to send the message from.',
|
148
126
|
)
|
149
127
|
@click.option(
|
150
|
-
|
151
|
-
envvar=
|
128
|
+
'--aprs-password',
|
129
|
+
envvar='APRS_PASSWORD',
|
152
130
|
show_envvar=True,
|
153
|
-
help=
|
131
|
+
help='the APRS-IS password for APRS_LOGIN',
|
154
132
|
)
|
155
133
|
@click.option(
|
156
|
-
|
134
|
+
'--packet-filter',
|
157
135
|
type=click.Choice(
|
158
136
|
[
|
159
137
|
packets.AckPacket.__name__,
|
@@ -170,35 +148,37 @@ class ListenStatsThread(APRSDThread):
|
|
170
148
|
],
|
171
149
|
case_sensitive=False,
|
172
150
|
),
|
173
|
-
|
151
|
+
multiple=True,
|
152
|
+
default=[],
|
153
|
+
help='Filter by packet type',
|
174
154
|
)
|
175
155
|
@click.option(
|
176
|
-
|
156
|
+
'--enable-plugin',
|
177
157
|
multiple=True,
|
178
|
-
help=
|
158
|
+
help='Enable a plugin. This is the name of the file in the plugins directory.',
|
179
159
|
)
|
180
160
|
@click.option(
|
181
|
-
|
161
|
+
'--load-plugins',
|
182
162
|
default=False,
|
183
163
|
is_flag=True,
|
184
|
-
help=
|
164
|
+
help='Load plugins as enabled in aprsd.conf ?',
|
185
165
|
)
|
186
166
|
@click.argument(
|
187
|
-
|
167
|
+
'filter',
|
188
168
|
nargs=-1,
|
189
169
|
required=True,
|
190
170
|
)
|
191
171
|
@click.option(
|
192
|
-
|
172
|
+
'--log-packets',
|
193
173
|
default=False,
|
194
174
|
is_flag=True,
|
195
|
-
help=
|
175
|
+
help='Log incoming packets.',
|
196
176
|
)
|
197
177
|
@click.option(
|
198
|
-
|
178
|
+
'--enable-packet-stats',
|
199
179
|
default=False,
|
200
180
|
is_flag=True,
|
201
|
-
help=
|
181
|
+
help='Enable packet stats periodic logging.',
|
202
182
|
)
|
203
183
|
@click.pass_context
|
204
184
|
@cli_helper.process_standard_options
|
@@ -228,46 +208,46 @@ def listen(
|
|
228
208
|
|
229
209
|
if not aprs_login:
|
230
210
|
click.echo(ctx.get_help())
|
231
|
-
click.echo(
|
232
|
-
ctx.fail(
|
211
|
+
click.echo('')
|
212
|
+
ctx.fail('Must set --aprs-login or APRS_LOGIN')
|
233
213
|
ctx.exit()
|
234
214
|
|
235
215
|
if not aprs_password:
|
236
216
|
click.echo(ctx.get_help())
|
237
|
-
click.echo(
|
238
|
-
ctx.fail(
|
217
|
+
click.echo('')
|
218
|
+
ctx.fail('Must set --aprs-password or APRS_PASSWORD')
|
239
219
|
ctx.exit()
|
240
220
|
|
241
221
|
# CONF.aprs_network.login = aprs_login
|
242
222
|
# config["aprs"]["password"] = aprs_password
|
243
223
|
|
244
|
-
LOG.info(f
|
224
|
+
LOG.info(f'APRSD Listen Started version: {aprsd.__version__}')
|
245
225
|
|
246
226
|
CONF.log_opt_values(LOG, logging.DEBUG)
|
247
227
|
collector.Collector()
|
248
228
|
|
249
229
|
# Try and load saved MsgTrack list
|
250
|
-
LOG.debug(
|
230
|
+
LOG.debug('Loading saved MsgTrack object.')
|
251
231
|
|
252
232
|
# Initialize the client factory and create
|
253
233
|
# The correct client object ready for use
|
254
234
|
# Make sure we have 1 client transport enabled
|
255
235
|
if not client_factory.is_client_enabled():
|
256
|
-
LOG.error(
|
236
|
+
LOG.error('No Clients are enabled in config.')
|
257
237
|
sys.exit(-1)
|
258
238
|
|
259
239
|
# Creates the client object
|
260
|
-
LOG.info(
|
240
|
+
LOG.info('Creating client connection')
|
261
241
|
aprs_client = client_factory.create()
|
262
242
|
LOG.info(aprs_client)
|
263
243
|
if not aprs_client.login_success:
|
264
244
|
# We failed to login, will just quit!
|
265
|
-
msg = f
|
245
|
+
msg = f'Login Failure: {aprs_client.login_failure}'
|
266
246
|
LOG.error(msg)
|
267
247
|
print(msg)
|
268
248
|
sys.exit(-1)
|
269
249
|
|
270
|
-
LOG.debug(f"Filter by '{filter}'")
|
250
|
+
LOG.debug(f"Filter messages on aprsis server by '{filter}'")
|
271
251
|
aprs_client.set_filter(filter)
|
272
252
|
|
273
253
|
keepalive_thread = keepalive.KeepAliveThread()
|
@@ -276,10 +256,19 @@ def listen(
|
|
276
256
|
# just deregister the class from the packet collector
|
277
257
|
packet_collector.PacketCollector().unregister(seen_list.SeenList)
|
278
258
|
|
259
|
+
# we don't want the dupe filter to run here.
|
260
|
+
PacketFilter().unregister(dupe_filter.DupePacketFilter)
|
261
|
+
if packet_filter:
|
262
|
+
LOG.info('Enabling packet filtering for {packet_filter}')
|
263
|
+
packet_type.PacketTypeFilter().set_allow_list(packet_filter)
|
264
|
+
PacketFilter().register(packet_type.PacketTypeFilter)
|
265
|
+
else:
|
266
|
+
LOG.info('No packet filtering enabled.')
|
267
|
+
|
279
268
|
pm = None
|
280
269
|
if load_plugins:
|
281
270
|
pm = plugin.PluginManager()
|
282
|
-
LOG.info(
|
271
|
+
LOG.info('Loading plugins')
|
283
272
|
pm.setup_plugins(load_help_plugin=False)
|
284
273
|
elif enable_plugin:
|
285
274
|
pm = plugin.PluginManager()
|
@@ -290,33 +279,37 @@ def listen(
|
|
290
279
|
else:
|
291
280
|
LOG.warning(
|
292
281
|
"Not Loading any plugins use --load-plugins to load what's "
|
293
|
-
|
282
|
+
'defined in the config file.',
|
294
283
|
)
|
295
284
|
|
296
285
|
if pm:
|
297
286
|
for p in pm.get_plugins():
|
298
|
-
LOG.info(
|
287
|
+
LOG.info('Loaded plugin %s', p.__class__.__name__)
|
299
288
|
|
300
289
|
stats = stats_thread.APRSDStatsStoreThread()
|
301
290
|
stats.start()
|
302
291
|
|
303
|
-
LOG.debug(
|
304
|
-
|
292
|
+
LOG.debug('Start APRSDRxThread')
|
293
|
+
rx_thread = rx.APRSDRXThread(packet_queue=threads.packet_queue)
|
294
|
+
rx_thread.start()
|
295
|
+
|
296
|
+
LOG.debug('Create APRSDListenProcessThread')
|
297
|
+
listen_thread = APRSDListenProcessThread(
|
305
298
|
packet_queue=threads.packet_queue,
|
306
299
|
packet_filter=packet_filter,
|
307
300
|
plugin_manager=pm,
|
308
301
|
enabled_plugins=enable_plugin,
|
309
302
|
log_packets=log_packets,
|
310
303
|
)
|
311
|
-
LOG.debug(
|
304
|
+
LOG.debug('Start APRSDListenProcessThread')
|
312
305
|
listen_thread.start()
|
313
306
|
if enable_packet_stats:
|
314
307
|
listen_stats = ListenStatsThread()
|
315
308
|
listen_stats.start()
|
316
309
|
|
317
310
|
keepalive_thread.start()
|
318
|
-
LOG.debug(
|
311
|
+
LOG.debug('keepalive Join')
|
319
312
|
keepalive_thread.join()
|
320
|
-
|
313
|
+
rx_thread.join()
|
321
314
|
listen_thread.join()
|
322
315
|
stats.join()
|
aprsd/cmds/server.py
CHANGED
@@ -147,7 +147,7 @@ def server(ctx, flush):
|
|
147
147
|
server_threads.register(keepalive.KeepAliveThread())
|
148
148
|
server_threads.register(stats_thread.APRSDStatsStoreThread())
|
149
149
|
server_threads.register(
|
150
|
-
rx.
|
150
|
+
rx.APRSDRXThread(
|
151
151
|
packet_queue=threads.packet_queue,
|
152
152
|
),
|
153
153
|
)
|