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.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: aprsd
3
- Version: 4.1.2
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.1.0
205
+ Requires-Dist: attrs==25.3.0
206
206
  Requires-Dist: ax253==0.1.5.post1
207
- Requires-Dist: bitarray==3.1.0
208
- Requires-Dist: certifi==2025.1.31
209
- Requires-Dist: charset-normalizer==3.4.1
210
- Requires-Dist: click==8.1.8
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.6.1
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==3.0.0
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.0.0
220
+ Requires-Dist: mypy-extensions==1.1.0
222
221
  Requires-Dist: netaddr==1.3.0
223
- Requires-Dist: oslo-config==9.7.1
222
+ Requires-Dist: oslo-config==10.0.0
224
223
  Requires-Dist: oslo-i18n==6.5.1
225
- Requires-Dist: packaging==24.2
224
+ Requires-Dist: packaging==25.0
226
225
  Requires-Dist: pbr==6.1.1
227
- Requires-Dist: pluggy==1.5.0
228
- Requires-Dist: pygments==2.19.1
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.1
230
+ Requires-Dist: pytz==2025.2
232
231
  Requires-Dist: pyyaml==6.0.2
233
- Requires-Dist: requests==2.32.3
232
+ Requires-Dist: requests==2.32.4
234
233
  Requires-Dist: rfc3986==2.0.0
235
- Requires-Dist: rich==13.9.4
234
+ Requires-Dist: rich==14.1.0
236
235
  Requires-Dist: rush==2021.4.0
237
- Requires-Dist: setuptools==75.8.2
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.12.2
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.3.0
246
- Requires-Dist: wrapt==1.17.2
247
- Requires-Dist: zipp==3.21.0
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.2.2.post1; extra == "dev"
252
- Requires-Dist: cachetools==5.5.2; extra == "dev"
253
- Requires-Dist: certifi==2025.1.31; extra == "dev"
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.1; extra == "dev"
257
- Requires-Dist: click==8.1.8; extra == "dev"
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.3.9; extra == "dev"
258
+ Requires-Dist: distlib==0.4.0; extra == "dev"
260
259
  Requires-Dist: docutils==0.21.2; extra == "dev"
261
- Requires-Dist: filelock==3.17.0; extra == "dev"
262
- Requires-Dist: identify==2.6.8; extra == "dev"
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.5; extra == "dev"
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==24.2; extra == "dev"
271
- Requires-Dist: pip==25.0.1; extra == "dev"
272
- Requires-Dist: pip-tools==7.4.1; extra == "dev"
273
- Requires-Dist: platformdirs==4.3.6; extra == "dev"
274
- Requires-Dist: pluggy==1.5.0; extra == "dev"
275
- Requires-Dist: pre-commit==4.1.0; extra == "dev"
276
- Requires-Dist: pygments==2.19.1; extra == "dev"
277
- Requires-Dist: pyproject-api==1.9.0; extra == "dev"
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.3; extra == "dev"
281
- Requires-Dist: setuptools==75.8.2; extra == "dev"
282
- Requires-Dist: snowballstemmer==2.2.0; extra == "dev"
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.24.1; extra == "dev"
292
- Requires-Dist: typing-extensions==4.12.2; extra == "dev"
293
- Requires-Dist: urllib3==2.3.0; extra == "dev"
294
- Requires-Dist: virtualenv==20.29.2; extra == "dev"
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=Mkovb7a5NaOKO-a0brnT-lWsz-nSucidEIE1x-XfU4s,4855
5
- aprsd/plugin.py,sha256=ZeGuXUlmBKkixQ_kZEjXzUCekJkIiWTCcPma63OkT1Y,17836
6
- aprsd/plugin_utils.py,sha256=2NUfNYA3XXOUoqI1QtM7YfPZtGnTVUfwY9l5iNhe5nE,2544
7
- aprsd/client/__init__.py,sha256=aajKndFPk259RLTUuobVDleJmOENHvdRVodfhY5BmX8,348
8
- aprsd/client/aprsis.py,sha256=ncGzA5q_3x2BsjEXP8WaZliGL0lhqwz9OrWhwDFvB7E,6181
9
- aprsd/client/base.py,sha256=PiNHJw8UE0sc3a8Y993FVmiPHO8yfxhR-ArGqr2e8sM,3842
10
- aprsd/client/factory.py,sha256=uuQmUreEKo8dVqqYQTZWtha7E5gVATAQGwB6W56a4Zk,2305
11
- aprsd/client/fake.py,sha256=RVWqvNVFoSGGiqPC_Z4OHdgX6uSnZ9Y8hxlDFABhPo8,1119
12
- aprsd/client/kiss.py,sha256=dVpQ2UM2LPmAMm6ue-AsHh97pyk9YR6OZKtaO6F4spw,4588
13
- aprsd/client/stats.py,sha256=VRexKAS3yD-kXyR3Xwe-lArAKx5BmrKYafrLdSeXr_s,351
14
- aprsd/client/drivers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
- aprsd/client/drivers/aprsis.py,sha256=GBuZWRUkRyCB6nY-YI1HRbsYqrtV5m8HCUEDmRFnNp0,9103
16
- aprsd/client/drivers/fake.py,sha256=doDPjkdAIjT05zpXwiefrcMQgwNB5ZUu9MelDmm24Oo,2126
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=MTy6O85ZdptfPmyw4COWhU0vVGM7SV_12NfSe6uEWOg,4150
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=dii-DNo950kWgWDmY4pSlokJKBRVQnXkbN18yoiRTDI,9431
25
- aprsd/cmds/send_message.py,sha256=hOFLoZTDuGbMhAkSxcCgNJ8mTG5V4_WyVwfe-aeqU8Y,4742
26
- aprsd/cmds/server.py,sha256=sWbK2GJmnd-K2LxEn6z_CNTCfsXIGXbCvhr6bcLTlbk,4277
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=W_vRKJ3P4VQaxxCjNdWCl7UmrRB8l7m_pCUi4XiOk6w,3085
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=uv2BfM6deHUbyC2aj20hxeZTsNZbjes6_MDQzxmDvys,27741
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=JGYRhwrTE_Gr49IXiOmXQffxYrqSEhp0PUhJwvE-Aek,5382
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=yGeyUV7R6EfOM87T8xDe-P2SUZqPTBA6pO_lZCGZaFY,13408
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=UIyOM4ZUdPud4UhXQLMhB_vK9P7aDeKqyvXfy2BStuw,1478
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=DyxAvRcBaqge3hYifxfeKWQ4L7p3oMLAADPtsRJlaKA,14875
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=5kIOKj5O3EJeGVbb88Y3Wl9J0NwnHOLDs2cj-87h5BI,9240
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=oAjxXbem00w1GImyWBqSasrdrruSzUyIUU-qDTxRA2g,1759
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.1.2.dist-info/AUTHORS,sha256=fGZhgXFMCfDPbp0hHllwmPyfiKPobLNA3sJA3BMIJVE,22
74
- aprsd-4.1.2.dist-info/LICENSE,sha256=CeipvOyAZxBGUsFoaFqwkx54aPnIKEtm9a5u2uXxEws,10142
75
- aprsd-4.1.2.dist-info/METADATA,sha256=VKJ51Jnmilt8MsnTlt2YFAV8VQfJRyX85jHPHqPe3Jk,45603
76
- aprsd-4.1.2.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
77
- aprsd-4.1.2.dist-info/entry_points.txt,sha256=4fReoJUB-bFqOUK6eeXYYCvTdVLprL7KVH0hWQRP9eM,171
78
- aprsd-4.1.2.dist-info/top_level.txt,sha256=v1O96niUcJOTMh9aQnFRknbScJ6mMOwqurdbxeaeSjs,6
79
- aprsd-4.1.2.dist-info/RECORD,,
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.2)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
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