aprsd 4.1.2__py3-none-any.whl → 4.2.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/__init__.py +5 -13
- aprsd/client/client.py +141 -0
- aprsd/client/drivers/__init__.py +10 -0
- aprsd/client/drivers/aprsis.py +174 -255
- aprsd/client/drivers/fake.py +59 -11
- aprsd/client/drivers/lib/__init__.py +0 -0
- aprsd/client/drivers/lib/aprslib.py +296 -0
- aprsd/client/drivers/registry.py +86 -0
- aprsd/client/drivers/tcpkiss.py +408 -0
- aprsd/client/stats.py +2 -2
- aprsd/cmds/dev.py +0 -3
- aprsd/cmds/listen.py +3 -3
- aprsd/cmds/send_message.py +4 -4
- aprsd/cmds/server.py +4 -10
- aprsd/log/log.py +1 -1
- aprsd/main.py +0 -7
- aprsd/packets/core.py +168 -169
- aprsd/packets/log.py +69 -59
- aprsd/plugin.py +3 -2
- aprsd/plugin_utils.py +2 -2
- aprsd/plugins/weather.py +2 -2
- aprsd/stats/collector.py +5 -4
- aprsd/threads/rx.py +12 -10
- aprsd/threads/tx.py +32 -31
- aprsd/utils/keepalive_collector.py +7 -5
- {aprsd-4.1.2.dist-info → aprsd-4.2.0.dist-info}/METADATA +48 -48
- {aprsd-4.1.2.dist-info → aprsd-4.2.0.dist-info}/RECORD +32 -33
- {aprsd-4.1.2.dist-info → aprsd-4.2.0.dist-info}/WHEEL +1 -1
- aprsd/client/aprsis.py +0 -183
- aprsd/client/base.py +0 -156
- aprsd/client/drivers/kiss.py +0 -144
- aprsd/client/factory.py +0 -91
- aprsd/client/fake.py +0 -49
- aprsd/client/kiss.py +0 -143
- {aprsd-4.1.2.dist-info → aprsd-4.2.0.dist-info}/entry_points.txt +0 -0
- {aprsd-4.1.2.dist-info → aprsd-4.2.0.dist-info/licenses}/AUTHORS +0 -0
- {aprsd-4.1.2.dist-info → aprsd-4.2.0.dist-info/licenses}/LICENSE +0 -0
- {aprsd-4.1.2.dist-info → aprsd-4.2.0.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: aprsd
|
3
|
-
Version: 4.
|
3
|
+
Version: 4.2.0
|
4
4
|
Summary: APRSd is a APRS-IS server that can be used to connect to APRS-IS and send and receive APRS packets.
|
5
5
|
Author-email: Craig Lamparter <craig@craiger.org>, "Walter A. Boring IV" <waboring@hemna.com>, Emre Saglam <emresaglam@gmail.com>, Jason Martin <jhmartin@toger.us>, John <johng42@users.noreply.github.com>, Martiros Shakhzadyan <vrzh@vrzh.net>, Zoe Moore <zoenb@mailbox.org>, ranguli <hello@joshmurphy.ca>
|
6
6
|
Maintainer-email: Craig Lamparter <craig@craiger.org>, "Walter A. Boring IV" <waboring@hemna.com>
|
@@ -202,84 +202,83 @@ Description-Content-Type: text/markdown
|
|
202
202
|
License-File: LICENSE
|
203
203
|
License-File: AUTHORS
|
204
204
|
Requires-Dist: aprslib==0.7.2
|
205
|
-
Requires-Dist: attrs==25.
|
205
|
+
Requires-Dist: attrs==25.3.0
|
206
206
|
Requires-Dist: ax253==0.1.5.post1
|
207
|
-
Requires-Dist: bitarray==3.1
|
208
|
-
Requires-Dist: certifi==2025.
|
209
|
-
Requires-Dist: charset-normalizer==3.4.
|
210
|
-
Requires-Dist: click==8.1
|
207
|
+
Requires-Dist: bitarray==3.6.1
|
208
|
+
Requires-Dist: certifi==2025.8.3
|
209
|
+
Requires-Dist: charset-normalizer==3.4.3
|
210
|
+
Requires-Dist: click==8.2.1
|
211
211
|
Requires-Dist: dataclasses-json==0.6.7
|
212
|
-
Requires-Dist: debtcollector==3.0.0
|
213
212
|
Requires-Dist: haversine==2.9.0
|
214
213
|
Requires-Dist: idna==3.10
|
215
|
-
Requires-Dist: importlib-metadata==8.
|
214
|
+
Requires-Dist: importlib-metadata==8.7.0
|
216
215
|
Requires-Dist: kiss3==8.0.0
|
217
216
|
Requires-Dist: loguru==0.7.3
|
218
|
-
Requires-Dist: markdown-it-py==
|
217
|
+
Requires-Dist: markdown-it-py==4.0.0
|
219
218
|
Requires-Dist: marshmallow==3.26.1
|
220
219
|
Requires-Dist: mdurl==0.1.2
|
221
|
-
Requires-Dist: mypy-extensions==1.
|
220
|
+
Requires-Dist: mypy-extensions==1.1.0
|
222
221
|
Requires-Dist: netaddr==1.3.0
|
223
|
-
Requires-Dist: oslo-config==
|
222
|
+
Requires-Dist: oslo-config==10.0.0
|
224
223
|
Requires-Dist: oslo-i18n==6.5.1
|
225
|
-
Requires-Dist: packaging==
|
224
|
+
Requires-Dist: packaging==25.0
|
226
225
|
Requires-Dist: pbr==6.1.1
|
227
|
-
Requires-Dist: pluggy==1.
|
228
|
-
Requires-Dist: pygments==2.19.
|
226
|
+
Requires-Dist: pluggy==1.6.0
|
227
|
+
Requires-Dist: pygments==2.19.2
|
229
228
|
Requires-Dist: pyserial==3.5
|
230
229
|
Requires-Dist: pyserial-asyncio==0.6
|
231
|
-
Requires-Dist: pytz==2025.
|
230
|
+
Requires-Dist: pytz==2025.2
|
232
231
|
Requires-Dist: pyyaml==6.0.2
|
233
|
-
Requires-Dist: requests==2.32.
|
232
|
+
Requires-Dist: requests==2.32.4
|
234
233
|
Requires-Dist: rfc3986==2.0.0
|
235
|
-
Requires-Dist: rich==
|
234
|
+
Requires-Dist: rich==14.1.0
|
236
235
|
Requires-Dist: rush==2021.4.0
|
237
|
-
Requires-Dist: setuptools==
|
236
|
+
Requires-Dist: setuptools==80.9.0
|
238
237
|
Requires-Dist: stevedore==5.4.1
|
239
238
|
Requires-Dist: thesmuggler==1.0.1
|
240
239
|
Requires-Dist: timeago==1.0.16
|
241
|
-
Requires-Dist: typing-extensions==4.
|
240
|
+
Requires-Dist: typing-extensions==4.14.1
|
242
241
|
Requires-Dist: typing-inspect==0.9.0
|
243
|
-
Requires-Dist: tzlocal==5.3
|
242
|
+
Requires-Dist: tzlocal==5.3.1
|
244
243
|
Requires-Dist: update-checker==0.18.0
|
245
|
-
Requires-Dist: urllib3==2.
|
246
|
-
Requires-Dist: wrapt==1.17.
|
247
|
-
Requires-Dist: zipp==3.
|
244
|
+
Requires-Dist: urllib3==2.5.0
|
245
|
+
Requires-Dist: wrapt==1.17.3
|
246
|
+
Requires-Dist: zipp==3.23.0
|
248
247
|
Provides-Extra: dev
|
249
248
|
Requires-Dist: alabaster==1.0.0; extra == "dev"
|
250
249
|
Requires-Dist: babel==2.17.0; extra == "dev"
|
251
|
-
Requires-Dist: build==1.
|
252
|
-
Requires-Dist: cachetools==
|
253
|
-
Requires-Dist: certifi==2025.
|
250
|
+
Requires-Dist: build==1.3.0; extra == "dev"
|
251
|
+
Requires-Dist: cachetools==6.1.0; extra == "dev"
|
252
|
+
Requires-Dist: certifi==2025.8.3; extra == "dev"
|
254
253
|
Requires-Dist: cfgv==3.4.0; extra == "dev"
|
255
254
|
Requires-Dist: chardet==5.2.0; extra == "dev"
|
256
|
-
Requires-Dist: charset-normalizer==3.4.
|
257
|
-
Requires-Dist: click==8.1
|
255
|
+
Requires-Dist: charset-normalizer==3.4.3; extra == "dev"
|
256
|
+
Requires-Dist: click==8.2.1; extra == "dev"
|
258
257
|
Requires-Dist: colorama==0.4.6; extra == "dev"
|
259
|
-
Requires-Dist: distlib==0.
|
258
|
+
Requires-Dist: distlib==0.4.0; extra == "dev"
|
260
259
|
Requires-Dist: docutils==0.21.2; extra == "dev"
|
261
|
-
Requires-Dist: filelock==3.
|
262
|
-
Requires-Dist: identify==2.6.
|
260
|
+
Requires-Dist: filelock==3.18.0; extra == "dev"
|
261
|
+
Requires-Dist: identify==2.6.13; extra == "dev"
|
263
262
|
Requires-Dist: idna==3.10; extra == "dev"
|
264
263
|
Requires-Dist: imagesize==1.4.1; extra == "dev"
|
265
|
-
Requires-Dist: jinja2==3.1.
|
264
|
+
Requires-Dist: jinja2==3.1.6; extra == "dev"
|
266
265
|
Requires-Dist: m2r==0.3.1; extra == "dev"
|
267
266
|
Requires-Dist: markupsafe==3.0.2; extra == "dev"
|
268
267
|
Requires-Dist: mistune==0.8.4; extra == "dev"
|
269
268
|
Requires-Dist: nodeenv==1.9.1; extra == "dev"
|
270
|
-
Requires-Dist: packaging==
|
271
|
-
Requires-Dist: pip==25.
|
272
|
-
Requires-Dist: pip-tools==7.
|
273
|
-
Requires-Dist: platformdirs==4.3.
|
274
|
-
Requires-Dist: pluggy==1.
|
275
|
-
Requires-Dist: pre-commit==4.
|
276
|
-
Requires-Dist: pygments==2.19.
|
277
|
-
Requires-Dist: pyproject-api==1.9.
|
269
|
+
Requires-Dist: packaging==25.0; extra == "dev"
|
270
|
+
Requires-Dist: pip==25.2; extra == "dev"
|
271
|
+
Requires-Dist: pip-tools==7.5.0; extra == "dev"
|
272
|
+
Requires-Dist: platformdirs==4.3.8; extra == "dev"
|
273
|
+
Requires-Dist: pluggy==1.6.0; extra == "dev"
|
274
|
+
Requires-Dist: pre-commit==4.3.0; extra == "dev"
|
275
|
+
Requires-Dist: pygments==2.19.2; extra == "dev"
|
276
|
+
Requires-Dist: pyproject-api==1.9.1; extra == "dev"
|
278
277
|
Requires-Dist: pyproject-hooks==1.2.0; extra == "dev"
|
279
278
|
Requires-Dist: pyyaml==6.0.2; extra == "dev"
|
280
|
-
Requires-Dist: requests==2.32.
|
281
|
-
Requires-Dist: setuptools==
|
282
|
-
Requires-Dist: snowballstemmer==
|
279
|
+
Requires-Dist: requests==2.32.4; extra == "dev"
|
280
|
+
Requires-Dist: setuptools==80.9.0; extra == "dev"
|
281
|
+
Requires-Dist: snowballstemmer==3.0.1; extra == "dev"
|
283
282
|
Requires-Dist: sphinx==8.1.3; extra == "dev"
|
284
283
|
Requires-Dist: sphinxcontrib-applehelp==2.0.0; extra == "dev"
|
285
284
|
Requires-Dist: sphinxcontrib-devhelp==2.0.0; extra == "dev"
|
@@ -288,11 +287,12 @@ Requires-Dist: sphinxcontrib-jsmath==1.0.1; extra == "dev"
|
|
288
287
|
Requires-Dist: sphinxcontrib-qthelp==2.0.0; extra == "dev"
|
289
288
|
Requires-Dist: sphinxcontrib-serializinghtml==2.0.0; extra == "dev"
|
290
289
|
Requires-Dist: tomli==2.2.1; extra == "dev"
|
291
|
-
Requires-Dist: tox==4.
|
292
|
-
Requires-Dist: typing-extensions==4.
|
293
|
-
Requires-Dist: urllib3==2.
|
294
|
-
Requires-Dist: virtualenv==20.
|
290
|
+
Requires-Dist: tox==4.28.4; extra == "dev"
|
291
|
+
Requires-Dist: typing-extensions==4.14.1; extra == "dev"
|
292
|
+
Requires-Dist: urllib3==2.5.0; extra == "dev"
|
293
|
+
Requires-Dist: virtualenv==20.33.1; extra == "dev"
|
295
294
|
Requires-Dist: wheel==0.45.1; extra == "dev"
|
295
|
+
Dynamic: license-file
|
296
296
|
|
297
297
|
# APRSD - Ham radio APRS-IS Message platform software
|
298
298
|
|
@@ -1,29 +1,28 @@
|
|
1
1
|
aprsd/__init__.py,sha256=ci_49KK2a4GXyxcM2lFZfNAOsBfXzh0yayIGQazw56I,687
|
2
2
|
aprsd/cli_helper.py,sha256=mKHww_cStwFBThjntFylrSnF6n9jOPHlR8r9SsrCxdY,4605
|
3
3
|
aprsd/exception.py,sha256=Oi6w0ISPemX0UpLB40BYnZBT1YOU-Pnpj8yf-A0E4-E,504
|
4
|
-
aprsd/main.py,sha256=
|
5
|
-
aprsd/plugin.py,sha256=
|
6
|
-
aprsd/plugin_utils.py,sha256=
|
7
|
-
aprsd/client/__init__.py,sha256=
|
8
|
-
aprsd/client/
|
9
|
-
aprsd/client/
|
10
|
-
aprsd/client/
|
11
|
-
aprsd/client/
|
12
|
-
aprsd/client/
|
13
|
-
aprsd/client/
|
14
|
-
aprsd/client/drivers/
|
15
|
-
aprsd/client/drivers/
|
16
|
-
aprsd/client/drivers/
|
17
|
-
aprsd/client/drivers/kiss.py,sha256=vS6bnp_6cf5gi6vKKgeKloUMseEbLiB5KOvWsnDHNF4,4193
|
4
|
+
aprsd/main.py,sha256=sOzG4tKtm7FGxwvYWIwiPujzo5TV3F0cSkR7IWHlb8M,4719
|
5
|
+
aprsd/plugin.py,sha256=pdyvKhSugFo4vRy7VflnaZ-BKozGa3GTTAHErskW3WU,17848
|
6
|
+
aprsd/plugin_utils.py,sha256=beXQ1n_YI38rqDwswtE8NjFwFzjpaeve9W_JotX1n1A,2544
|
7
|
+
aprsd/client/__init__.py,sha256=lh7mKBoSo2Tt82QoqlAARGm4LY6ffsn7d8x6M4B7n9g,154
|
8
|
+
aprsd/client/client.py,sha256=i4KBGT_-6btH9e3X2moyGYz7OGHLHgbS8qqYMmlsH_o,3912
|
9
|
+
aprsd/client/stats.py,sha256=dUqRZao04B2TTj9TGMSygdLHa3if3pEy86eK-fK4sj4,353
|
10
|
+
aprsd/client/drivers/__init__.py,sha256=IWSSrAEMrJQzulCIAx-N7Du0HK9sQOXIh98aJRCtfdg,421
|
11
|
+
aprsd/client/drivers/aprsis.py,sha256=upUqCYDVVvOfbX43h5ncXq7CdlMrJsnO2ghbA88RKAk,6665
|
12
|
+
aprsd/client/drivers/fake.py,sha256=b3q9-4O9Gtd7XnEzgZ2NzR5Zv6szxKBe07nsXJXmSHw,3249
|
13
|
+
aprsd/client/drivers/registry.py,sha256=AWDWqxjOYHDz8ow4fNSSJ7JR6Tgy1axG6r0I9Yk2nJ8,2213
|
14
|
+
aprsd/client/drivers/tcpkiss.py,sha256=PIiBaj0j4KDcXKRi3gUYDp10tC6qLmUlGfTbkQKPN1M,12926
|
15
|
+
aprsd/client/drivers/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
16
|
+
aprsd/client/drivers/lib/aprslib.py,sha256=9KTEKlivGT1f1js-u-w1WNLhOs1kQxkr3COa1CI95oE,9439
|
18
17
|
aprsd/cmds/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
18
|
aprsd/cmds/completion.py,sha256=BMM8dSYUihYmj2fSsefo6LzgJZKbxHnNfRIhwVZW_U8,816
|
20
|
-
aprsd/cmds/dev.py,sha256=
|
19
|
+
aprsd/cmds/dev.py,sha256=iXjO0WBrEPE8wnuQU-7BpKOHsPLqyNZZ-67FvWiWOko,4097
|
21
20
|
aprsd/cmds/fetch_stats.py,sha256=rE99ir67udprRLxOhWkZ1btgF5Vs8UX74S4ssjYi4lM,9621
|
22
21
|
aprsd/cmds/healthcheck.py,sha256=swXb4LE1qdr3Z-417fv4LhWvscE4WUrqF9So1sWXiCU,2635
|
23
22
|
aprsd/cmds/list_plugins.py,sha256=ongeK7gy_IxzLw_EfhclKMVHptyzIubV4PYxCxDMIqs,10415
|
24
|
-
aprsd/cmds/listen.py,sha256=
|
25
|
-
aprsd/cmds/send_message.py,sha256=
|
26
|
-
aprsd/cmds/server.py,sha256=
|
23
|
+
aprsd/cmds/listen.py,sha256=t_EOfy-qNRox6YwaeXHtynk_F5mShyDSjv2GZA9ca3I,9415
|
24
|
+
aprsd/cmds/send_message.py,sha256=iJEteEWTPj3gQhSyBj8BvQr4WQzjrVbHWxaHgvIcpQM,4709
|
25
|
+
aprsd/cmds/server.py,sha256=uZQawLzL5IKUPUHRleligJqlIokRwujcovhcivixY1g,4034
|
27
26
|
aprsd/conf/__init__.py,sha256=2ikrZahcS2EULQEJ5xErnzMVR2vcsDdMvixEPuNE-xE,1678
|
28
27
|
aprsd/conf/client.py,sha256=9oheIUnotnbHmpKtxlw-00quW0o-3pZYtFmaim9bsjs,3013
|
29
28
|
aprsd/conf/common.py,sha256=6bYna2bn0js6cq3c0h3KzbzgOWcpqeui5JEijx5rDj8,7386
|
@@ -31,12 +30,12 @@ aprsd/conf/log.py,sha256=qBoF8ptGHK7G6NPHNZCE2PBH7S-L587wFkT-9ikUtfE,1656
|
|
31
30
|
aprsd/conf/opts.py,sha256=kbZELePpBDoQrKbowbWHgmLksbREARU8T8UhX9FIhq8,2725
|
32
31
|
aprsd/conf/plugin_common.py,sha256=H7LxiJL0Sl1D_dpAmJHEHSbPxaOK938M1WCOcTpOYN8,1990
|
33
32
|
aprsd/log/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
34
|
-
aprsd/log/log.py,sha256=
|
33
|
+
aprsd/log/log.py,sha256=zldqJCHj5J-JRTnVsXkLepmhFkPYr9wQWi3RWKMmFMI,3099
|
35
34
|
aprsd/packets/__init__.py,sha256=IW61OJOAJ8_Deio72OEOngDuHHm7KzHjj5Bergr7e5g,1110
|
36
35
|
aprsd/packets/collector.py,sha256=VhuHj2CRxVtaC6QDKiYMnxRzNVj-fc7wkMyPpTl83Og,2322
|
37
|
-
aprsd/packets/core.py,sha256=
|
36
|
+
aprsd/packets/core.py,sha256=B_eTvBkUe5EMqGAaLru5F_qbb4tO_qJ4MV4Z0WiT9NQ,27807
|
38
37
|
aprsd/packets/filter.py,sha256=RmYSNepi_kxK2PeQwrRODQcml5yfUdJpBasuQw4W7Q4,2135
|
39
|
-
aprsd/packets/log.py,sha256=
|
38
|
+
aprsd/packets/log.py,sha256=R0hSg-SHBBHvwbnJklKBm1HHVXvBzaswfMyq7QUzdE4,5568
|
40
39
|
aprsd/packets/packet_list.py,sha256=BnaFokRiPOP9jUW0sXTQPXUquhiQ0qw8gt2Dh0JWAIM,3506
|
41
40
|
aprsd/packets/seen_list.py,sha256=fV87eyXeFxaZKqWfY1GOCQ6zfnjI1Or6i3KS_qJLuoA,1375
|
42
41
|
aprsd/packets/tracker.py,sha256=Fr7B9Ex2kikmAkUz0HNUEsx9p60ap9L7A96bkv9WaO0,2950
|
@@ -50,30 +49,30 @@ aprsd/plugins/notify.py,sha256=MHR9y_iCokOSNShI7DjW93tsP0tFj8_1hHf9elMjASo,1922
|
|
50
49
|
aprsd/plugins/ping.py,sha256=A3yLMPUDU-PA1Q98xStd0WM04MZvGn3FzVpGKjyoXDc,763
|
51
50
|
aprsd/plugins/time.py,sha256=59-tMl7ogccLobWl9hMDm8mUVXdqW6kB5javrtp0rok,3535
|
52
51
|
aprsd/plugins/version.py,sha256=NAPFKQ0lQqgjoDyTVy8tZcRGmdcJE_ZogRElDz27V2U,839
|
53
|
-
aprsd/plugins/weather.py,sha256=
|
52
|
+
aprsd/plugins/weather.py,sha256=XOspEoAumUb35TW2RYqjRV0lp6hrR_kOMIT41iEUGQQ,13399
|
54
53
|
aprsd/stats/__init__.py,sha256=ltAtUiEvpokBEtOpq0sxpDGOLQT2evgeZSVBzDzjkSo,808
|
55
54
|
aprsd/stats/app.py,sha256=axqMA137zKqU03yO8XI5f1QE8ajmr9YK0J9O9m4iSzo,1378
|
56
|
-
aprsd/stats/collector.py,sha256=
|
55
|
+
aprsd/stats/collector.py,sha256=7nx_KSP_PUeuX5q8xJhsB9G_JfgQFCAvrPNzO7uK4FM,1502
|
57
56
|
aprsd/threads/__init__.py,sha256=KPqAOhS4q995NCEWDnPCHiuu3guyuMZlyDUGx_h50z8,259
|
58
57
|
aprsd/threads/aprsd.py,sha256=13AS7jAhcQBmTervBiADaC1Ins9C-6TrMDYjW1fQJkg,4794
|
59
58
|
aprsd/threads/keepalive.py,sha256=E48_erNnqik5AAllMGx5gexAwPIaznCp0HCG45NltFw,3939
|
60
59
|
aprsd/threads/registry.py,sha256=zWG4-SMBSx46NY93__Bt_F8vFrljxQvMHbi80WP5kY8,1690
|
61
|
-
aprsd/threads/rx.py,sha256=
|
60
|
+
aprsd/threads/rx.py,sha256=u7SZ-YqINrnetusV7qFRWKVVoDMfj8-Z1bnSby3w3bI,14936
|
62
61
|
aprsd/threads/service.py,sha256=fGjyr34i2-CJdBynxachNaBrBsULwmAnewLHdTujfmk,1375
|
63
62
|
aprsd/threads/stats.py,sha256=drKqHV2WxgXhyWXGrmRHQx7oKlrJ9bwEMtCInCzulPY,884
|
64
|
-
aprsd/threads/tx.py,sha256=
|
63
|
+
aprsd/threads/tx.py,sha256=spuWk4E5HvTWYNyhKB1kxqVbVvxNapzYvi9tNScTAHs,9264
|
65
64
|
aprsd/utils/__init__.py,sha256=TsuSiHFK5VQW6w4Q1epTOyfnr58n4ZVKNe4obbxl-5Y,7333
|
66
65
|
aprsd/utils/counter.py,sha256=GQH2E1FEBshR5PROhCNS13I6CaYZLW7VJumaYd7yQcY,1378
|
67
66
|
aprsd/utils/fuzzyclock.py,sha256=qKV8SYZhQGOHG9biF8TeueLb6RMppspx1Zg4IOy1Z10,3265
|
68
67
|
aprsd/utils/json.py,sha256=eHoBfXGcchO4Q1MXj6uKK9YU-H8HKPJ2cThLZ1dM_vo,2578
|
69
|
-
aprsd/utils/keepalive_collector.py,sha256=
|
68
|
+
aprsd/utils/keepalive_collector.py,sha256=r0oKCpKPGsivOKTQkTfwcJRESqMfbNawCyqrcHoJo8M,1807
|
70
69
|
aprsd/utils/objectstore.py,sha256=0OivUeagncWGH7eWjTwZhauf-etweTabp8Oykt0hoF4,3541
|
71
70
|
aprsd/utils/ring_buffer.py,sha256=lWWuw7lEbc2URhqAJfRLjpXBDLiK6UUWzk3j2VFnERQ,1111
|
72
71
|
aprsd/utils/trace.py,sha256=lIuDZHOjvWbL2IMJ2tN_XW4Ch8oe4uQ7uLGylUByli0,5687
|
73
|
-
aprsd-4.
|
74
|
-
aprsd-4.
|
75
|
-
aprsd-4.
|
76
|
-
aprsd-4.
|
77
|
-
aprsd-4.
|
78
|
-
aprsd-4.
|
79
|
-
aprsd-4.
|
72
|
+
aprsd-4.2.0.dist-info/licenses/AUTHORS,sha256=fGZhgXFMCfDPbp0hHllwmPyfiKPobLNA3sJA3BMIJVE,22
|
73
|
+
aprsd-4.2.0.dist-info/licenses/LICENSE,sha256=CeipvOyAZxBGUsFoaFqwkx54aPnIKEtm9a5u2uXxEws,10142
|
74
|
+
aprsd-4.2.0.dist-info/METADATA,sha256=eky_cPS4yV2IcaRxoiHCOc95g4UzL8pmMbnfzI5cxpU,45583
|
75
|
+
aprsd-4.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
76
|
+
aprsd-4.2.0.dist-info/entry_points.txt,sha256=4fReoJUB-bFqOUK6eeXYYCvTdVLprL7KVH0hWQRP9eM,171
|
77
|
+
aprsd-4.2.0.dist-info/top_level.txt,sha256=v1O96niUcJOTMh9aQnFRknbScJ6mMOwqurdbxeaeSjs,6
|
78
|
+
aprsd-4.2.0.dist-info/RECORD,,
|
aprsd/client/aprsis.py
DELETED
@@ -1,183 +0,0 @@
|
|
1
|
-
import datetime
|
2
|
-
import logging
|
3
|
-
import time
|
4
|
-
|
5
|
-
import timeago
|
6
|
-
from aprslib.exceptions import LoginError
|
7
|
-
from loguru import logger
|
8
|
-
from oslo_config import cfg
|
9
|
-
|
10
|
-
from aprsd import client, exception
|
11
|
-
from aprsd.client import base
|
12
|
-
from aprsd.client.drivers import aprsis
|
13
|
-
from aprsd.packets import core
|
14
|
-
|
15
|
-
CONF = cfg.CONF
|
16
|
-
LOG = logging.getLogger("APRSD")
|
17
|
-
LOGU = logger
|
18
|
-
|
19
|
-
|
20
|
-
class APRSISClient(base.APRSClient):
|
21
|
-
_client = None
|
22
|
-
_checks = False
|
23
|
-
|
24
|
-
def __init__(self):
|
25
|
-
max_timeout = {"hours": 0.0, "minutes": 2, "seconds": 0}
|
26
|
-
self.max_delta = datetime.timedelta(**max_timeout)
|
27
|
-
|
28
|
-
def stats(self, serializable=False) -> dict:
|
29
|
-
stats = {}
|
30
|
-
if self.is_configured():
|
31
|
-
if self._client:
|
32
|
-
keepalive = self._client.aprsd_keepalive
|
33
|
-
server_string = self._client.server_string
|
34
|
-
if serializable:
|
35
|
-
keepalive = keepalive.isoformat()
|
36
|
-
else:
|
37
|
-
keepalive = "None"
|
38
|
-
server_string = "None"
|
39
|
-
stats = {
|
40
|
-
"connected": self.is_connected,
|
41
|
-
"filter": self.filter,
|
42
|
-
"login_status": self.login_status,
|
43
|
-
"connection_keepalive": keepalive,
|
44
|
-
"server_string": server_string,
|
45
|
-
"transport": self.transport(),
|
46
|
-
}
|
47
|
-
|
48
|
-
return stats
|
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
|
-
|
64
|
-
@staticmethod
|
65
|
-
def is_enabled():
|
66
|
-
# Defaults to True if the enabled flag is non existent
|
67
|
-
try:
|
68
|
-
return CONF.aprs_network.enabled
|
69
|
-
except KeyError:
|
70
|
-
return False
|
71
|
-
|
72
|
-
@staticmethod
|
73
|
-
def is_configured():
|
74
|
-
if APRSISClient.is_enabled():
|
75
|
-
# Ensure that the config vars are correctly set
|
76
|
-
if not CONF.aprs_network.login:
|
77
|
-
LOG.error("Config aprs_network.login not set.")
|
78
|
-
raise exception.MissingConfigOptionException(
|
79
|
-
"aprs_network.login is not set.",
|
80
|
-
)
|
81
|
-
if not CONF.aprs_network.password:
|
82
|
-
LOG.error("Config aprs_network.password not set.")
|
83
|
-
raise exception.MissingConfigOptionException(
|
84
|
-
"aprs_network.password is not set.",
|
85
|
-
)
|
86
|
-
if not CONF.aprs_network.host:
|
87
|
-
LOG.error("Config aprs_network.host not set.")
|
88
|
-
raise exception.MissingConfigOptionException(
|
89
|
-
"aprs_network.host is not set.",
|
90
|
-
)
|
91
|
-
|
92
|
-
return True
|
93
|
-
return True
|
94
|
-
|
95
|
-
def _is_stale_connection(self):
|
96
|
-
delta = datetime.datetime.now() - self._client.aprsd_keepalive
|
97
|
-
if delta > self.max_delta:
|
98
|
-
LOG.error(f"Connection is stale, last heard {delta} ago.")
|
99
|
-
return True
|
100
|
-
return False
|
101
|
-
|
102
|
-
def is_alive(self):
|
103
|
-
if not self._client:
|
104
|
-
LOG.warning(f"APRS_CLIENT {self._client} alive? NO!!!")
|
105
|
-
return False
|
106
|
-
return self._client.is_alive() and not self._is_stale_connection()
|
107
|
-
|
108
|
-
def close(self):
|
109
|
-
if self._client:
|
110
|
-
self._client.stop()
|
111
|
-
self._client.close()
|
112
|
-
|
113
|
-
@staticmethod
|
114
|
-
def transport():
|
115
|
-
return client.TRANSPORT_APRSIS
|
116
|
-
|
117
|
-
def decode_packet(self, *args, **kwargs):
|
118
|
-
"""APRS lib already decodes this."""
|
119
|
-
return core.factory(args[0])
|
120
|
-
|
121
|
-
def setup_connection(self):
|
122
|
-
user = CONF.aprs_network.login
|
123
|
-
password = CONF.aprs_network.password
|
124
|
-
host = CONF.aprs_network.host
|
125
|
-
port = CONF.aprs_network.port
|
126
|
-
self.connected = False
|
127
|
-
backoff = 1
|
128
|
-
aprs_client = None
|
129
|
-
retries = 3
|
130
|
-
retry_count = 0
|
131
|
-
while not self.connected:
|
132
|
-
retry_count += 1
|
133
|
-
if retry_count >= retries:
|
134
|
-
break
|
135
|
-
try:
|
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
|
-
)
|
142
|
-
# Force the log to be the same
|
143
|
-
aprs_client.logger = LOG
|
144
|
-
aprs_client.connect()
|
145
|
-
self.connected = self.login_status["success"] = True
|
146
|
-
self.login_status["message"] = aprs_client.server_string
|
147
|
-
backoff = 1
|
148
|
-
except LoginError as e:
|
149
|
-
LOG.error(f"Failed to login to APRS-IS Server '{e}'")
|
150
|
-
self.connected = self.login_status["success"] = False
|
151
|
-
self.login_status["message"] = e.message
|
152
|
-
LOG.error(e.message)
|
153
|
-
time.sleep(backoff)
|
154
|
-
except Exception as e:
|
155
|
-
LOG.error(f"Unable to connect to APRS-IS server. '{e}' ")
|
156
|
-
self.connected = self.login_status["success"] = False
|
157
|
-
self.login_status["message"] = e.message
|
158
|
-
time.sleep(backoff)
|
159
|
-
# Don't allow the backoff to go to inifinity.
|
160
|
-
if backoff > 5:
|
161
|
-
backoff = 5
|
162
|
-
else:
|
163
|
-
backoff += 1
|
164
|
-
continue
|
165
|
-
self._client = aprs_client
|
166
|
-
return aprs_client
|
167
|
-
|
168
|
-
def consumer(self, callback, blocking=False, immortal=False, raw=False):
|
169
|
-
if self._client:
|
170
|
-
try:
|
171
|
-
self._client.consumer(
|
172
|
-
callback,
|
173
|
-
blocking=blocking,
|
174
|
-
immortal=immortal,
|
175
|
-
raw=raw,
|
176
|
-
)
|
177
|
-
except Exception as e:
|
178
|
-
LOG.error(e)
|
179
|
-
LOG.info(e.__cause__)
|
180
|
-
raise e
|
181
|
-
else:
|
182
|
-
LOG.warning("client is None, might be resetting.")
|
183
|
-
self.connected = False
|
aprsd/client/base.py
DELETED
@@ -1,156 +0,0 @@
|
|
1
|
-
import abc
|
2
|
-
import logging
|
3
|
-
import threading
|
4
|
-
|
5
|
-
import wrapt
|
6
|
-
from oslo_config import cfg
|
7
|
-
|
8
|
-
from aprsd.packets import core
|
9
|
-
from aprsd.utils import keepalive_collector
|
10
|
-
|
11
|
-
CONF = cfg.CONF
|
12
|
-
LOG = logging.getLogger('APRSD')
|
13
|
-
|
14
|
-
|
15
|
-
class APRSClient:
|
16
|
-
"""Singleton client class that constructs the aprslib connection."""
|
17
|
-
|
18
|
-
_instance = None
|
19
|
-
_client = None
|
20
|
-
|
21
|
-
connected = False
|
22
|
-
login_status = {
|
23
|
-
'success': False,
|
24
|
-
'message': None,
|
25
|
-
}
|
26
|
-
filter = None
|
27
|
-
lock = threading.Lock()
|
28
|
-
|
29
|
-
def __new__(cls, *args, **kwargs):
|
30
|
-
"""This magic turns this into a singleton."""
|
31
|
-
if cls._instance is None:
|
32
|
-
cls._instance = super().__new__(cls)
|
33
|
-
keepalive_collector.KeepAliveCollector().register(cls)
|
34
|
-
# Put any initialization here.
|
35
|
-
cls._instance._create_client()
|
36
|
-
return cls._instance
|
37
|
-
|
38
|
-
@abc.abstractmethod
|
39
|
-
def stats(self) -> dict:
|
40
|
-
"""Return statistics about the client connection.
|
41
|
-
|
42
|
-
Returns:
|
43
|
-
dict: Statistics about the connection and packet handling
|
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
|
-
|
56
|
-
@property
|
57
|
-
def is_connected(self):
|
58
|
-
return self.connected
|
59
|
-
|
60
|
-
@property
|
61
|
-
def login_success(self):
|
62
|
-
return self.login_status.get('success', False)
|
63
|
-
|
64
|
-
@property
|
65
|
-
def login_failure(self):
|
66
|
-
return self.login_status['message']
|
67
|
-
|
68
|
-
def set_filter(self, filter):
|
69
|
-
self.filter = filter
|
70
|
-
if self._client:
|
71
|
-
self._client.set_filter(filter)
|
72
|
-
|
73
|
-
def get_filter(self):
|
74
|
-
return self.filter
|
75
|
-
|
76
|
-
@property
|
77
|
-
def client(self):
|
78
|
-
if not self._client:
|
79
|
-
self._create_client()
|
80
|
-
return self._client
|
81
|
-
|
82
|
-
def _create_client(self):
|
83
|
-
try:
|
84
|
-
self._client = self.setup_connection()
|
85
|
-
if self.filter:
|
86
|
-
LOG.info('Creating APRS client filter')
|
87
|
-
self._client.set_filter(self.filter)
|
88
|
-
except Exception as e:
|
89
|
-
LOG.error(f'Failed to create APRS client: {e}')
|
90
|
-
self._client = None
|
91
|
-
raise
|
92
|
-
|
93
|
-
def stop(self):
|
94
|
-
if self._client:
|
95
|
-
LOG.info('Stopping client connection.')
|
96
|
-
self._client.stop()
|
97
|
-
|
98
|
-
def send(self, packet: core.Packet) -> None:
|
99
|
-
"""Send a packet to the network.
|
100
|
-
|
101
|
-
Args:
|
102
|
-
packet: The APRS packet to send
|
103
|
-
"""
|
104
|
-
self.client.send(packet)
|
105
|
-
|
106
|
-
@wrapt.synchronized(lock)
|
107
|
-
def reset(self) -> None:
|
108
|
-
"""Call this to force a rebuild/reconnect."""
|
109
|
-
LOG.info('Resetting client connection.')
|
110
|
-
if self._client:
|
111
|
-
self._client.close()
|
112
|
-
del self._client
|
113
|
-
self._create_client()
|
114
|
-
else:
|
115
|
-
LOG.warning('Client not initialized, nothing to reset.')
|
116
|
-
|
117
|
-
# Recreate the client
|
118
|
-
LOG.info(f'Creating new client {self.client}')
|
119
|
-
|
120
|
-
@abc.abstractmethod
|
121
|
-
def setup_connection(self):
|
122
|
-
"""Initialize and return the underlying APRS connection.
|
123
|
-
|
124
|
-
Returns:
|
125
|
-
object: The initialized connection object
|
126
|
-
"""
|
127
|
-
|
128
|
-
@staticmethod
|
129
|
-
@abc.abstractmethod
|
130
|
-
def is_enabled():
|
131
|
-
pass
|
132
|
-
|
133
|
-
@staticmethod
|
134
|
-
@abc.abstractmethod
|
135
|
-
def transport():
|
136
|
-
pass
|
137
|
-
|
138
|
-
@abc.abstractmethod
|
139
|
-
def decode_packet(self, *args, **kwargs):
|
140
|
-
"""Decode raw APRS packet data into a Packet object.
|
141
|
-
|
142
|
-
Returns:
|
143
|
-
Packet: Decoded APRS packet
|
144
|
-
"""
|
145
|
-
|
146
|
-
@abc.abstractmethod
|
147
|
-
def consumer(self, callback, blocking=False, immortal=False, raw=False):
|
148
|
-
pass
|
149
|
-
|
150
|
-
@abc.abstractmethod
|
151
|
-
def is_alive(self):
|
152
|
-
pass
|
153
|
-
|
154
|
-
@abc.abstractmethod
|
155
|
-
def close(self):
|
156
|
-
pass
|