aprsd 4.2.0__tar.gz → 4.2.1__tar.gz
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-4.2.0 → aprsd-4.2.1}/ChangeLog.md +15 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/PKG-INFO +1 -1
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/client/client.py +32 -17
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/client/drivers/aprsis.py +3 -3
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/client/drivers/tcpkiss.py +20 -5
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/cmds/dev.py +6 -1
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/cmds/fetch_stats.py +2 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/cmds/list_plugins.py +6 -133
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/cmds/listen.py +2 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/cmds/send_message.py +4 -1
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/cmds/server.py +3 -1
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/conf/common.py +7 -1
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/exception.py +7 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/threads/rx.py +1 -1
- aprsd-4.2.1/aprsd/utils/package.py +176 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd.egg-info/PKG-INFO +1 -1
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd.egg-info/SOURCES.txt +1 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/tests/client/drivers/test_aprsis_driver.py +2 -2
- {aprsd-4.2.0 → aprsd-4.2.1}/.coveragerc +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/.github/workflows/authors.yml +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/.github/workflows/codeql.yml +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/.github/workflows/manual_build.yml +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/.github/workflows/master-build.yml +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/.github/workflows/python.yml +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/.github/workflows/release_build.yml +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/.mailmap +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/.pre-commit-config.yaml +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/.readthedocs.yaml +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/AUTHORS +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/CONTRIBUTING.md +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/INSTALL.txt +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/LICENSE +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/MANIFEST.in +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/Makefile +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/README.md +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/__init__.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/cli_helper.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/client/__init__.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/client/drivers/__init__.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/client/drivers/fake.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/client/drivers/lib/__init__.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/client/drivers/lib/aprslib.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/client/drivers/registry.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/client/stats.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/cmds/__init__.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/cmds/completion.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/cmds/healthcheck.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/conf/__init__.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/conf/client.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/conf/log.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/conf/opts.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/conf/plugin_common.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/log/__init__.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/log/log.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/main.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/packets/__init__.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/packets/collector.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/packets/core.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/packets/filter.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/packets/filters/__init__.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/packets/filters/dupe_filter.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/packets/filters/packet_type.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/packets/log.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/packets/packet_list.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/packets/seen_list.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/packets/tracker.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/packets/watch_list.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/plugin.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/plugin_utils.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/plugins/__init__.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/plugins/fortune.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/plugins/notify.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/plugins/ping.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/plugins/time.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/plugins/version.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/plugins/weather.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/stats/__init__.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/stats/app.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/stats/collector.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/threads/__init__.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/threads/aprsd.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/threads/keepalive.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/threads/registry.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/threads/service.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/threads/stats.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/threads/tx.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/utils/__init__.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/utils/counter.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/utils/fuzzyclock.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/utils/json.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/utils/keepalive_collector.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/utils/objectstore.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/utils/ring_buffer.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd/utils/trace.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd-lnav.json +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd.egg-info/dependency_links.txt +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd.egg-info/entry_points.txt +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd.egg-info/requires.txt +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd.egg-info/top_level.txt +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/aprsd_logo.png +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docker/Dockerfile +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docker/bin/admin.sh +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docker/bin/healthcheck.sh +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docker/bin/listen.sh +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docker/bin/run.sh +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docker/bin/setup.sh +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docker/build.sh +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docker/docker-compose.yml +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/_static/.keep +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/_static/aprsd_overview.png +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/_static/aprsd_overview.svg +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/_templates/.keep +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/apidoc/aprsd.client.drivers.rst +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/apidoc/aprsd.client.rst +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/apidoc/aprsd.cmds.rst +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/apidoc/aprsd.conf.rst +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/apidoc/aprsd.log.rst +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/apidoc/aprsd.packets.rst +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/apidoc/aprsd.plugins.rst +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/apidoc/aprsd.rst +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/apidoc/aprsd.stats.rst +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/apidoc/aprsd.threads.rst +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/apidoc/aprsd.utils.rst +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/apidoc/modules.rst +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/aprsd.drawio +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/changelog.rst +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/clean_docs.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/conf.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/configure.rst +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/index.rst +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/install.rst +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/links.rst +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/plugin.rst +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/readme.rst +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/docs/server.rst +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/examples/plugins/__init__.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/examples/plugins/example_plugin.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/gray.conf +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/pyproject.toml +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/requirements-dev.in +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/requirements-dev.txt +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/requirements.in +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/requirements.txt +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/setup.cfg +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/setup.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/tests/__init__.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/tests/client/__init__.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/tests/client/drivers/__init__.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/tests/client/drivers/test_fake_driver.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/tests/client/drivers/test_tcpkiss_driver.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/tests/client/test_registry.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/tests/cmds/__init__.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/tests/cmds/test_send_message.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/tests/fake.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/tests/mock_client_driver.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/tests/plugins/__init__.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/tests/plugins/test_fortune.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/tests/plugins/test_notify.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/tests/plugins/test_ping.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/tests/plugins/test_time.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/tests/plugins/test_version.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/tests/plugins/test_weather.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/tests/test_packets.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/tests/test_plugin.py +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/tools/fast8.sh +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/tox.ini +0 -0
- {aprsd-4.2.0 → aprsd-4.2.1}/uv.lock +0 -0
@@ -4,6 +4,20 @@ All notable changes to this project will be documented in this file. Dates are d
|
|
4
4
|
|
5
5
|
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
6
6
|
|
7
|
+
#### [4.2.1](https://github.com/craigerl/aprsd/compare/4.2.0...4.2.1)
|
8
|
+
|
9
|
+
> 7 October 2025
|
10
|
+
|
11
|
+
- Sanity check around decoding packet [`58cb046`](https://github.com/craigerl/aprsd/commit/58cb046b3131f4300255c527dee4c7291a4aeed2)
|
12
|
+
- Added CONF.is_digipi [`f3039eb`](https://github.com/craigerl/aprsd/commit/f3039ebfa153d0fbad4a390089fce360e6148854)
|
13
|
+
- Fixed stats issue with tcpkiss client. [`556554b`](https://github.com/craigerl/aprsd/commit/556554b1a76743989fa88877e7f694b918f770cf)
|
14
|
+
- Fixed missing f string [`8cd61a7`](https://github.com/craigerl/aprsd/commit/8cd61a72c8f16e8651533baf2d677d3345bd3712)
|
15
|
+
- Added ThirdPartyPacket decoding in tcpkiss driver [`3961e1d`](https://github.com/craigerl/aprsd/commit/3961e1d1adf428ff0fa66ed5fe0d6192adf164bf)
|
16
|
+
- refactored list-plugins [`c7c9a92`](https://github.com/craigerl/aprsd/commit/c7c9a92b153ccc673275dca628d485d1df88db12)
|
17
|
+
- Added package [`e15322e`](https://github.com/craigerl/aprsd/commit/e15322ede384d6e463c42e9496502e2c6ea0886c)
|
18
|
+
- Some client and driver cleanup. [`328c027`](https://github.com/craigerl/aprsd/commit/328c027ad3db594f3d5622a2cab7cafb21d1cfd6)
|
19
|
+
- Fixed some unit tests [`af0feaf`](https://github.com/craigerl/aprsd/commit/af0feaf9c81b8b9f443e58fbe7d23f1ff7ba63d2)
|
20
|
+
|
7
21
|
#### [4.2.0](https://github.com/craigerl/aprsd/compare/4.1.2...4.2.0)
|
8
22
|
|
9
23
|
> 12 August 2025
|
@@ -25,6 +39,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
25
39
|
- Fix tox failures [`74887af`](https://github.com/craigerl/aprsd/commit/74887af507755cd7ee27f13129b177f4d58ca8e0)
|
26
40
|
- log the exception when tx fails. [`fa5d0c6`](https://github.com/craigerl/aprsd/commit/fa5d0c643ae85fc9ad3f615f9d0afc590f422283)
|
27
41
|
- Updated requirements for 4.2.0 [`2c476d8`](https://github.com/craigerl/aprsd/commit/2c476d8a04df8cebbaa50780688e58d8b9df2bc9)
|
42
|
+
- Updated Changelog for 4.2.0 [`b9fea98`](https://github.com/craigerl/aprsd/commit/b9fea982f977e9cf60c4695ca1892adaeee64298)
|
28
43
|
|
29
44
|
#### [4.1.2](https://github.com/craigerl/aprsd/compare/4.1.1...4.1.2)
|
30
45
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: aprsd
|
3
|
-
Version: 4.2.
|
3
|
+
Version: 4.2.1
|
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>
|
@@ -38,15 +38,16 @@ class APRSDClient:
|
|
38
38
|
keepalive_collector.KeepAliveCollector().register(cls)
|
39
39
|
return cls._instance
|
40
40
|
|
41
|
-
def __init__(self):
|
41
|
+
def __init__(self, auto_connect: bool = True):
|
42
|
+
self.auto_connect = auto_connect
|
42
43
|
self.connected = False
|
43
44
|
self.login_status = {
|
44
45
|
'success': False,
|
45
46
|
'message': None,
|
46
47
|
}
|
47
|
-
|
48
|
-
|
49
|
-
self.
|
48
|
+
self.driver = DriverRegistry().get_driver()
|
49
|
+
if self.auto_connect:
|
50
|
+
self.connect()
|
50
51
|
|
51
52
|
def stats(self, serializable=False) -> dict:
|
52
53
|
stats = {}
|
@@ -54,17 +55,20 @@ class APRSDClient:
|
|
54
55
|
stats = self.driver.stats(serializable=serializable)
|
55
56
|
return stats
|
56
57
|
|
57
|
-
@
|
58
|
-
def is_enabled(
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
58
|
+
@staticmethod
|
59
|
+
def is_enabled():
|
60
|
+
for driver in DriverRegistry().drivers:
|
61
|
+
if driver.is_enabled():
|
62
|
+
return True
|
63
|
+
return False
|
64
|
+
|
65
|
+
@staticmethod
|
66
|
+
def is_configured():
|
67
|
+
"""Check if ANY driver is configured."""
|
68
|
+
for driver in DriverRegistry().drivers:
|
69
|
+
if driver.is_configured():
|
70
|
+
return True
|
71
|
+
return False
|
68
72
|
|
69
73
|
# @property
|
70
74
|
# def is_connected(self):
|
@@ -98,6 +102,11 @@ class APRSDClient:
|
|
98
102
|
def is_alive(self):
|
99
103
|
return self.driver.is_alive()
|
100
104
|
|
105
|
+
def connect(self):
|
106
|
+
if not self.driver:
|
107
|
+
self.driver = DriverRegistry().get_driver()
|
108
|
+
self.driver.setup_connection()
|
109
|
+
|
101
110
|
def close(self):
|
102
111
|
if not self.driver:
|
103
112
|
return
|
@@ -109,7 +118,8 @@ class APRSDClient:
|
|
109
118
|
LOG.info('Resetting client connection.')
|
110
119
|
if self.driver:
|
111
120
|
self.driver.close()
|
112
|
-
self.
|
121
|
+
if not self.delay_connect:
|
122
|
+
self.driver.setup_connection()
|
113
123
|
if self.filter:
|
114
124
|
self.driver.set_filter(self.filter)
|
115
125
|
else:
|
@@ -138,4 +148,9 @@ class APRSDClient:
|
|
138
148
|
return self.driver.consumer(callback=callback, raw=raw)
|
139
149
|
|
140
150
|
def decode_packet(self, *args, **kwargs) -> core.Packet:
|
141
|
-
|
151
|
+
try:
|
152
|
+
packet = self.driver.decode_packet(*args, **kwargs)
|
153
|
+
except Exception as e:
|
154
|
+
LOG.error(f'Error decoding packet: {e}')
|
155
|
+
return None
|
156
|
+
return packet
|
@@ -26,6 +26,7 @@ class APRSISDriver:
|
|
26
26
|
|
27
27
|
_client = None
|
28
28
|
_checks = False
|
29
|
+
connected = False
|
29
30
|
|
30
31
|
def __init__(self):
|
31
32
|
max_timeout = {'hours': 0.0, 'minutes': 2, 'seconds': 0}
|
@@ -164,7 +165,7 @@ class APRSISDriver:
|
|
164
165
|
return core.factory(args[0])
|
165
166
|
|
166
167
|
def consumer(self, callback: Callable, raw: bool = False):
|
167
|
-
if self._client:
|
168
|
+
if self._client and self.connected:
|
168
169
|
try:
|
169
170
|
self._client.consumer(
|
170
171
|
callback,
|
@@ -177,10 +178,9 @@ class APRSISDriver:
|
|
177
178
|
LOG.info(e.__cause__)
|
178
179
|
raise e
|
179
180
|
else:
|
180
|
-
LOG.warning('client is None, might be resetting.')
|
181
181
|
self.connected = False
|
182
182
|
|
183
|
-
def stats(self, serializable=False) -> dict:
|
183
|
+
def stats(self, serializable: bool = False) -> dict:
|
184
184
|
stats = {}
|
185
185
|
if self.is_configured():
|
186
186
|
if self._client:
|
@@ -79,8 +79,8 @@ class TCPKISSDriver:
|
|
79
79
|
def transport(self) -> str:
|
80
80
|
return client.TRANSPORT_TCPKISS
|
81
81
|
|
82
|
-
@
|
83
|
-
def is_enabled(
|
82
|
+
@staticmethod
|
83
|
+
def is_enabled() -> bool:
|
84
84
|
"""Check if KISS is enabled in configuration.
|
85
85
|
|
86
86
|
Returns:
|
@@ -248,7 +248,11 @@ class TCPKISSDriver:
|
|
248
248
|
LOG.warning(f'FRAME: {str(frame)}')
|
249
249
|
try:
|
250
250
|
aprslib_frame = aprslib.parse(str(frame))
|
251
|
-
|
251
|
+
packet = core.factory(aprslib_frame)
|
252
|
+
if isinstance(packet, core.ThirdPartyPacket):
|
253
|
+
return packet.subpacket
|
254
|
+
else:
|
255
|
+
return packet
|
252
256
|
except Exception as e:
|
253
257
|
LOG.error(f'Error decoding packet: {e}')
|
254
258
|
return None
|
@@ -271,8 +275,19 @@ class TCPKISSDriver:
|
|
271
275
|
"""
|
272
276
|
if serializable:
|
273
277
|
keepalive = self.keepalive.isoformat()
|
278
|
+
if self.last_packet_sent:
|
279
|
+
last_packet_sent = self.last_packet_sent.isoformat()
|
280
|
+
else:
|
281
|
+
last_packet_sent = 'None'
|
282
|
+
if self.last_packet_received:
|
283
|
+
last_packet_received = self.last_packet_received.isoformat()
|
284
|
+
else:
|
285
|
+
last_packet_received = 'None'
|
274
286
|
else:
|
275
287
|
keepalive = self.keepalive
|
288
|
+
last_packet_sent = self.last_packet_sent
|
289
|
+
last_packet_received = self.last_packet_received
|
290
|
+
|
276
291
|
stats = {
|
277
292
|
'client': self.__class__.__name__,
|
278
293
|
'transport': self.transport,
|
@@ -280,8 +295,8 @@ class TCPKISSDriver:
|
|
280
295
|
'path': self.path,
|
281
296
|
'packets_sent': self.packets_sent,
|
282
297
|
'packets_received': self.packets_received,
|
283
|
-
'last_packet_sent':
|
284
|
-
'last_packet_received':
|
298
|
+
'last_packet_sent': last_packet_sent,
|
299
|
+
'last_packet_received': last_packet_received,
|
285
300
|
'connection_keepalive': keepalive,
|
286
301
|
'host': CONF.kiss_tcp.host,
|
287
302
|
'port': CONF.kiss_tcp.port,
|
@@ -4,11 +4,13 @@
|
|
4
4
|
#
|
5
5
|
# python included libs
|
6
6
|
import logging
|
7
|
+
import sys
|
7
8
|
|
8
9
|
import click
|
9
10
|
from oslo_config import cfg
|
10
11
|
|
11
|
-
|
12
|
+
import aprsd
|
13
|
+
from aprsd import cli_helper, conf, packets, plugin, utils
|
12
14
|
|
13
15
|
# local imports here
|
14
16
|
from aprsd.main import cli
|
@@ -71,6 +73,9 @@ def test_plugin(
|
|
71
73
|
):
|
72
74
|
"""Test an individual APRSD plugin given a python path."""
|
73
75
|
|
76
|
+
LOG.info(f'Python version: {sys.version}')
|
77
|
+
LOG.info(f'APRSD DEV Started version: {aprsd.__version__}')
|
78
|
+
utils.package.log_installed_extensions_and_plugins()
|
74
79
|
CONF.log_opt_values(LOG, logging.DEBUG)
|
75
80
|
|
76
81
|
if not aprs_login:
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# Fetch active stats from a remote running instance of aprsd admin web interface.
|
2
2
|
import logging
|
3
|
+
import sys
|
3
4
|
|
4
5
|
import click
|
5
6
|
import requests
|
@@ -38,6 +39,7 @@ CONF = cfg.CONF
|
|
38
39
|
def fetch_stats(ctx, host, port):
|
39
40
|
"""Fetch stats from a APRSD admin web interface."""
|
40
41
|
console = Console()
|
42
|
+
console.print(f'Python version: {sys.version}')
|
41
43
|
console.print(f'APRSD Fetch-Stats started version: {aprsd.__version__}')
|
42
44
|
|
43
45
|
CONF.log_opt_values(LOG, logging.DEBUG)
|
@@ -1,119 +1,18 @@
|
|
1
|
-
import fnmatch
|
2
|
-
import importlib
|
3
1
|
import inspect
|
4
2
|
import logging
|
5
|
-
import os
|
6
|
-
import pkgutil
|
7
|
-
import sys
|
8
|
-
from traceback import print_tb
|
9
3
|
|
10
4
|
import click
|
11
|
-
import requests
|
12
5
|
from rich.console import Console
|
13
6
|
from rich.table import Table
|
14
7
|
from rich.text import Text
|
15
|
-
from thesmuggler import smuggle
|
16
8
|
|
17
9
|
from aprsd import cli_helper
|
18
10
|
from aprsd import plugin as aprsd_plugin
|
19
11
|
from aprsd.main import cli
|
20
12
|
from aprsd.plugins import fortune, notify, ping, time, version, weather
|
13
|
+
from aprsd.utils import package as aprsd_package
|
21
14
|
|
22
15
|
LOG = logging.getLogger('APRSD')
|
23
|
-
PYPI_URL = 'https://pypi.org/search/'
|
24
|
-
|
25
|
-
|
26
|
-
def onerror(name):
|
27
|
-
print(f'Error importing module {name}')
|
28
|
-
type, value, traceback = sys.exc_info()
|
29
|
-
print_tb(traceback)
|
30
|
-
|
31
|
-
|
32
|
-
def is_plugin(obj):
|
33
|
-
for c in inspect.getmro(obj):
|
34
|
-
if issubclass(c, aprsd_plugin.APRSDPluginBase):
|
35
|
-
return True
|
36
|
-
|
37
|
-
return False
|
38
|
-
|
39
|
-
|
40
|
-
def plugin_type(obj):
|
41
|
-
for c in inspect.getmro(obj):
|
42
|
-
if issubclass(c, aprsd_plugin.APRSDRegexCommandPluginBase):
|
43
|
-
return 'RegexCommand'
|
44
|
-
if issubclass(c, aprsd_plugin.APRSDWatchListPluginBase):
|
45
|
-
return 'WatchList'
|
46
|
-
if issubclass(c, aprsd_plugin.APRSDPluginBase):
|
47
|
-
return 'APRSDPluginBase'
|
48
|
-
|
49
|
-
return 'Unknown'
|
50
|
-
|
51
|
-
|
52
|
-
def walk_package(package):
|
53
|
-
return pkgutil.walk_packages(
|
54
|
-
package.__path__,
|
55
|
-
package.__name__ + '.',
|
56
|
-
onerror=onerror,
|
57
|
-
)
|
58
|
-
|
59
|
-
|
60
|
-
def get_module_info(package_name, module_name, module_path):
|
61
|
-
if not os.path.exists(module_path):
|
62
|
-
return None
|
63
|
-
|
64
|
-
dir_path = os.path.realpath(module_path)
|
65
|
-
pattern = '*.py'
|
66
|
-
|
67
|
-
obj_list = []
|
68
|
-
|
69
|
-
for path, _subdirs, files in os.walk(dir_path):
|
70
|
-
for name in files:
|
71
|
-
if fnmatch.fnmatch(name, pattern):
|
72
|
-
module = smuggle(f'{path}/{name}')
|
73
|
-
for mem_name, obj in inspect.getmembers(module):
|
74
|
-
if inspect.isclass(obj) and is_plugin(obj):
|
75
|
-
obj_list.append(
|
76
|
-
{
|
77
|
-
'package': package_name,
|
78
|
-
'name': mem_name,
|
79
|
-
'obj': obj,
|
80
|
-
'version': obj.version,
|
81
|
-
'path': f'{".".join([module_name, obj.__name__])}',
|
82
|
-
},
|
83
|
-
)
|
84
|
-
|
85
|
-
return obj_list
|
86
|
-
|
87
|
-
|
88
|
-
def _get_installed_aprsd_items():
|
89
|
-
# installed plugins
|
90
|
-
plugins = {}
|
91
|
-
extensions = {}
|
92
|
-
for _finder, name, ispkg in pkgutil.iter_modules():
|
93
|
-
if ispkg and name.startswith('aprsd_'):
|
94
|
-
module = importlib.import_module(name)
|
95
|
-
pkgs = walk_package(module)
|
96
|
-
for pkg in pkgs:
|
97
|
-
pkg_info = get_module_info(
|
98
|
-
module.__name__, pkg.name, module.__path__[0]
|
99
|
-
)
|
100
|
-
if 'plugin' in name:
|
101
|
-
plugins[name] = pkg_info
|
102
|
-
elif 'extension' in name:
|
103
|
-
extensions[name] = pkg_info
|
104
|
-
return plugins, extensions
|
105
|
-
|
106
|
-
|
107
|
-
def get_installed_plugins():
|
108
|
-
# installed plugins
|
109
|
-
plugins, extensions = _get_installed_aprsd_items()
|
110
|
-
return plugins
|
111
|
-
|
112
|
-
|
113
|
-
def get_installed_extensions():
|
114
|
-
# installed plugins
|
115
|
-
plugins, extensions = _get_installed_aprsd_items()
|
116
|
-
return extensions
|
117
16
|
|
118
17
|
|
119
18
|
def show_built_in_plugins(console):
|
@@ -157,34 +56,8 @@ def show_built_in_plugins(console):
|
|
157
56
|
console.print(table)
|
158
57
|
|
159
58
|
|
160
|
-
def _get_pypi_packages():
|
161
|
-
if simple_r := requests.get(
|
162
|
-
'https://pypi.org/simple',
|
163
|
-
headers={'Accept': 'application/vnd.pypi.simple.v1+json'},
|
164
|
-
):
|
165
|
-
simple_response = simple_r.json()
|
166
|
-
else:
|
167
|
-
simple_response = {}
|
168
|
-
|
169
|
-
key = 'aprsd'
|
170
|
-
matches = [
|
171
|
-
p['name'] for p in simple_response['projects'] if p['name'].startswith(key)
|
172
|
-
]
|
173
|
-
|
174
|
-
packages = []
|
175
|
-
for pkg in matches:
|
176
|
-
# Get info for first match
|
177
|
-
if r := requests.get(
|
178
|
-
f'https://pypi.org/pypi/{pkg}/json',
|
179
|
-
headers={'Accept': 'application/json'},
|
180
|
-
):
|
181
|
-
packages.append(r.json())
|
182
|
-
|
183
|
-
return packages
|
184
|
-
|
185
|
-
|
186
59
|
def show_pypi_plugins(installed_plugins, console):
|
187
|
-
packages =
|
60
|
+
packages = aprsd_package.get_pypi_packages()
|
188
61
|
|
189
62
|
title = Text.assemble(
|
190
63
|
('Pypi.org APRSD Installable Plugin Packages\n\n', 'bold magenta'),
|
@@ -225,7 +98,7 @@ def show_pypi_plugins(installed_plugins, console):
|
|
225
98
|
|
226
99
|
|
227
100
|
def show_pypi_extensions(installed_extensions, console):
|
228
|
-
packages =
|
101
|
+
packages = aprsd_package.get_pypi_packages()
|
229
102
|
|
230
103
|
title = Text.assemble(
|
231
104
|
('Pypi.org APRSD Installable Extension Packages\n\n', 'bold magenta'),
|
@@ -282,7 +155,7 @@ def show_installed_plugins(installed_plugins, console):
|
|
282
155
|
name.replace('_', '-'),
|
283
156
|
plugin['name'],
|
284
157
|
plugin['version'],
|
285
|
-
plugin_type(plugin['obj']),
|
158
|
+
aprsd_package.plugin_type(plugin['obj']),
|
286
159
|
plugin['path'],
|
287
160
|
)
|
288
161
|
|
@@ -302,7 +175,7 @@ def list_plugins(ctx):
|
|
302
175
|
show_built_in_plugins(console)
|
303
176
|
|
304
177
|
status.update('Fetching pypi.org plugins')
|
305
|
-
installed_plugins = get_installed_plugins()
|
178
|
+
installed_plugins = aprsd_package.get_installed_plugins()
|
306
179
|
show_pypi_plugins(installed_plugins, console)
|
307
180
|
|
308
181
|
status.update('Looking for installed APRSD plugins')
|
@@ -321,5 +194,5 @@ def list_extensions(ctx):
|
|
321
194
|
status.update('Fetching pypi.org APRSD Extensions')
|
322
195
|
|
323
196
|
status.update('Looking for installed APRSD Extensions')
|
324
|
-
installed_extensions = get_installed_extensions()
|
197
|
+
installed_extensions = aprsd_package.get_installed_extensions()
|
325
198
|
show_pypi_extensions(installed_extensions, console)
|
@@ -221,7 +221,9 @@ def listen(
|
|
221
221
|
# CONF.aprs_network.login = aprs_login
|
222
222
|
# config["aprs"]["password"] = aprs_password
|
223
223
|
|
224
|
+
LOG.info(f'Python version: {sys.version}')
|
224
225
|
LOG.info(f'APRSD Listen Started version: {aprsd.__version__}')
|
226
|
+
utils.package.log_installed_extensions_and_plugins()
|
225
227
|
|
226
228
|
CONF.log_opt_values(LOG, logging.DEBUG)
|
227
229
|
collector.Collector()
|
@@ -13,6 +13,7 @@ from aprsd import (
|
|
13
13
|
cli_helper,
|
14
14
|
conf, # noqa : F401
|
15
15
|
packets,
|
16
|
+
utils,
|
16
17
|
)
|
17
18
|
from aprsd.client.client import APRSDClient
|
18
19
|
from aprsd.main import cli
|
@@ -89,7 +90,9 @@ def send_message(
|
|
89
90
|
else:
|
90
91
|
aprs_password = CONF.aprs_network.password
|
91
92
|
|
92
|
-
LOG.info(f'
|
93
|
+
LOG.info(f'Python version: {sys.version}')
|
94
|
+
LOG.info(f'APRSD SEND_MESSAGE Started version: {aprsd.__version__}')
|
95
|
+
utils.package.log_installed_extensions_and_plugins()
|
93
96
|
if type(command) is tuple:
|
94
97
|
command = ' '.join(command)
|
95
98
|
if not quiet:
|
@@ -40,12 +40,14 @@ def server(ctx, flush):
|
|
40
40
|
|
41
41
|
service_threads = service.ServiceThreads()
|
42
42
|
|
43
|
+
LOG.info(f'Python version: {sys.version}')
|
44
|
+
LOG.info(f'APRSD Started version: {aprsd.__version__}')
|
43
45
|
level, msg = utils._check_version()
|
44
46
|
if level:
|
45
47
|
LOG.warning(msg)
|
46
48
|
else:
|
47
49
|
LOG.info(msg)
|
48
|
-
|
50
|
+
utils.package.log_installed_extensions_and_plugins()
|
49
51
|
|
50
52
|
# Make sure we have 1 client transport enabled
|
51
53
|
if not APRSDClient().is_enabled:
|
@@ -19,7 +19,7 @@ registry_group = cfg.OptGroup(
|
|
19
19
|
aprsd_opts = [
|
20
20
|
cfg.StrOpt(
|
21
21
|
'callsign',
|
22
|
-
|
22
|
+
default='NOCALL',
|
23
23
|
help='Callsign to use for messages sent by APRSD',
|
24
24
|
),
|
25
25
|
cfg.BoolOpt(
|
@@ -137,6 +137,12 @@ aprsd_opts = [
|
|
137
137
|
help='Set this to False, to disable sending of ack packets. This will entirely stop'
|
138
138
|
'APRSD from sending ack packets.',
|
139
139
|
),
|
140
|
+
cfg.BoolOpt(
|
141
|
+
'is_digipi',
|
142
|
+
default=False,
|
143
|
+
help='Set this to True, if APRSD is running on a Digipi.'
|
144
|
+
'This is useful for changing the behavior of APRSD to work with Digipi.',
|
145
|
+
),
|
140
146
|
]
|
141
147
|
|
142
148
|
watch_list_opts = [
|
@@ -13,3 +13,10 @@ class ConfigOptionBogusDefaultException(Exception):
|
|
13
13
|
f"Config file option '{config_option}' needs to be "
|
14
14
|
f"changed from provided default of '{default_fail}'"
|
15
15
|
)
|
16
|
+
|
17
|
+
|
18
|
+
class APRSClientNotConfiguredException(Exception):
|
19
|
+
"""APRS client is not configured."""
|
20
|
+
|
21
|
+
def __init__(self):
|
22
|
+
self.message = 'APRS client is not configured.'
|
@@ -275,7 +275,7 @@ class APRSDProcessPacketThread(APRSDFilterThread):
|
|
275
275
|
def process_other_packet(self, packet, for_us=False):
|
276
276
|
"""Process an APRS Packet that isn't a message or ack"""
|
277
277
|
if not for_us:
|
278
|
-
LOG.info("Got a packet meant for someone else '{packet.to_call}'")
|
278
|
+
LOG.info(f"Got a packet meant for someone else '{packet.to_call}'")
|
279
279
|
else:
|
280
280
|
LOG.info('Got a non AckPacket/MessagePacket')
|
281
281
|
|