1
0
mirror of https://github.com/craigerl/aprsd.git synced 2026-05-16 14:22:42 -04:00

1376 Commits

Author SHA1 Message Date
5cc918e5c2 fix: add socket lock to prevent TX/RX race causing stream corruption on retransmits
The RX reader thread sets setblocking(0) and the TX writer (via aprslib
sendall) sets setblocking(1) on the same socket without synchronization.
This race condition causes partial writes where other stations' APRS-IS
stream data gets concatenated onto retransmitted packets.

Add a shared _socket_lock between send() and _socket_readlines() so the
socket blocking mode is never changed by one thread while the other is
mid-operation.
5.0.0
2026-05-14 16:55:57 -04:00
9146ff76c9 fix: remove stale .client attribute access in send_message command
APRSDClient no longer has a .client property after the driver refactor
(commit 1c39546). Instantiating APRSDClient() is sufficient to trigger
connection via auto_connect=True.
2026-05-13 23:17:38 -04:00
0c515d45fe fix: filter stale BeaconPackets from PacketTrack on load from disk
Older versions persisted BeaconPackets to packettrack.json. On restart
these zombie beacons would be retransmitted by the scheduler. Now
PacketTrack.load() strips any BeaconPackets from the persisted data.

Workaround: delete ~/.config/aprsd/packettrack.json before restarting.
2026-05-13 12:14:21 -04:00
d3281cff0b test: add tests for beacon/ack flood prevention and scheduler timing guards
Tests cover:
- BeaconPacket skipped in PacketTrack.tx() (fire-and-forget)
- AckPacket send_count not reset when same ack already tracked
- Heavy traffic scenario with 5 digi paths for same message
- Scheduler timing guards prevent threadpool race conditions
- Scheduler cleanup of max-retry packets
- MessagePacket still allows re-send (existing behavior preserved)
2026-05-13 11:44:49 -04:00
d8134c4531 fix: prevent beacon and ack packet floods from PacketTrack retries
BeaconPackets are now skipped in PacketTrack — they are fire-and-forget
and never receive an ack, so tracking them caused the scheduler to
re-transmit them as unwanted duplicates.

AckPackets already being tracked are no longer reset when the same
message arrives via multiple digipeater paths, which was restarting
the retry counter and flooding RF with duplicate acks.

Added timing guards in both scheduler loops to prevent threadpool race
conditions where multiple workers could fire before send_count was
incremented.
2026-05-13 11:36:25 -04:00
3a47571b60
Merge pull request #224 from craigerl/dependabot/uv/uv-0.11.6
Bump uv from 0.9.26 to 0.11.6
2026-04-29 09:16:53 -04:00
dependabot[bot]
4ecdec0aa4
Bump uv from 0.9.26 to 0.11.6
Bumps [uv](https://github.com/astral-sh/uv) from 0.9.26 to 0.11.6.
- [Release notes](https://github.com/astral-sh/uv/releases)
- [Changelog](https://github.com/astral-sh/uv/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/uv/compare/0.9.26...0.11.6)

---
updated-dependencies:
- dependency-name: uv
  dependency-version: 0.11.6
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-10 19:49:05 +00:00
490ff41cdc feat: Add configurable stats_store_interval for stats file saves
Add stats_store_interval config option to control how frequently
the statsstore.json file is written to disk. Default remains 10
seconds for backward compatibility.

This allows reducing disk I/O in production deployments and
can help avoid potential file corruption issues when external
processes read the stats file.
2026-03-27 17:37:16 -04:00
27413ab8cf
Merge pull request #223 from craigerl/feature/configurable-stale-timeout
feat: Add configurable stale_timeout for APRS-IS connections
2026-03-27 10:27:09 -04:00
314f4da180 fix: Restore max_delta after custom stale_timeout test
The singleton's max_delta was being modified by test_init_custom_stale_timeout
and not restored, causing test_is_stale_connection_false to fail because
it expected 2 minutes but got 60 seconds.
2026-03-27 10:18:07 -04:00
f6eb383caf fix: Update test to work with singleton pattern
The APRSISDriver uses @singleton decorator which transforms the class
into a function. The test was incorrectly trying to use __new__ which
doesn't work with decorated singletons. Instead, re-initialize the
existing instance after changing the config.
2026-03-27 10:13:55 -04:00
930339d4cf feat: Add configurable stale_timeout for APRS-IS connections
Add a new 'stale_timeout' configuration option to the aprs_network config
group that allows users to customize how long to wait before considering
an APRS-IS connection stale.

Problem:
The stale connection threshold was hardcoded to 2 minutes. In environments
with frequent network hiccups or when using certain APRS-IS servers that
may drop connections silently, 2 minutes can be too long to wait before
reconnecting, resulting in significant data loss.

Solution:
- Add 'stale_timeout' option to aprsd/conf/client.py with default of 120s
- Update APRSISDriver.__init__ to use the config value
- Maintain backward compatibility by defaulting to 120s if not configured
- Update tests to handle the new configuration option

Usage:
  [aprs_network]
  stale_timeout = 60  # Reconnect after 60 seconds without data

The default remains 120 seconds (2 minutes) for backward compatibility.
2026-03-27 10:05:44 -04:00
a2e07a2279
Merge pull request #221 from craigerl/fix-urllib3-security
security: bump urllib3 from 2.6.2 to 2.6.3
2026-03-24 13:49:17 -04:00
3a12ccb842 security: bump urllib3 from 2.6.2 to 2.6.3
Fixes CVE-2026-21441 (8.9 High severity) - decompression-bomb safeguards
of the streaming API were bypassed when HTTP redirects were followed.

Closes #210
2026-03-24 13:43:44 -04:00
github-actions[bot]
5463b8d5b5
chore: update AUTHORS [skip ci] 2026-03-24 17:32:35 +00:00
f2526efe1d
Merge pull request #219 from craigerl/feature-daemon-threads-event-refactor
Refactor threads to use daemon threads and Event-based timing
2026-03-24 13:32:26 -04:00
96b017d59e chore: update uv.lock for uv 0.11.0 compatibility 2026-03-24 13:26:33 -04:00
8d8648e9dd style(threads): add return type to loop() and use modern type hints
- Add -> bool return type annotation to abstract loop() method
- Replace 'from typing import List' with built-in list[] (Python 3.9+)
2026-03-24 13:22:37 -04:00
bf258e4bcf chore(tests): fix unused variable linter warning in test_stats.py 2026-03-24 13:22:37 -04:00
4ab59c6cf3 refactor(main): update signal handler for Event-based thread shutdown
- Replace time.sleep(1.5) with thread_list.join_non_daemon(timeout=5.0)
- Remove unused import time since time.sleep is no longer used
- Remove outdated commented-out code
- Improve log message (removed '10 seconds' reference)
2026-03-24 13:22:37 -04:00
505c0fa8a8 refactor(threads): migrate APRSRegistryThread to Event-based timing
- Set self.period=CONF.aprs_registry.frequency_seconds in __init__
- Remove counter-based conditional (loop every N seconds pattern)
- Replace time.sleep(1) with self.wait()
- Remove _loop_cnt tracking (use inherited loop_count from base)
- Remove unused time import
2026-03-24 13:22:37 -04:00
85ebf8a274 refactor(threads): migrate TX threads to Event-based timing
- PacketSendSchedulerThread: Add daemon=False, replace time.sleep with self.wait
- AckSendSchedulerThread: Add daemon=False, replace time.sleep with self.wait
- SendPacketThread: Replace time.sleep with self.wait, remove manual loop_count
- SendAckThread: Replace time.sleep with self.wait, remove manual loop_count
- BeaconSendThread: Set self.period=CONF.beacon_interval, remove counter-based
  conditional, replace time.sleep with self.wait, remove _loop_cnt tracking
- Update tests to use new Event-based API
2026-03-24 13:22:37 -04:00
bc9ce61e59 refactor(threads): migrate RX threads to Event-based timing
- APRSDRXThread: Replace time.sleep with self.wait for interruptible waits
- APRSDRXThread.stop(): Use _shutdown_event.set() instead of thread_stop
- APRSDRXThread: Error recovery waits check for shutdown signal
- APRSDFilterThread: Use queue timeout with self.period for interruptible wait
- Remove unused time import
- Update tests to use new Event-based API
2026-03-24 13:22:37 -04:00
343ec3e81c refactor(threads): migrate stats threads to Event-based timing 2026-03-24 13:22:37 -04:00
44b8bc572d refactor(threads): migrate KeepAliveThread to Event-based timing 2026-03-24 13:22:36 -04:00
43ba69e352 feat(threads): add join_non_daemon() to APRSDThreadList
Allows graceful shutdown by waiting for non-daemon threads to complete
while allowing daemon threads to be terminated immediately.
2026-03-24 13:22:36 -04:00
b7a37322e1 refactor(threads): add daemon, period, Event-based shutdown to APRSDThread
- Add daemon=True class attribute (subclasses override to False)
- Add period=1 class attribute for wait interval
- Replace thread_stop boolean with _shutdown_event (threading.Event)
- Add wait() method for interruptible sleeps
- Update tests for new Event-based API

BREAKING: thread_stop boolean replaced with _shutdown_event.
Code checking thread.thread_stop directly must use thread._shutdown_event.is_set()
2026-03-24 13:22:36 -04:00
bc9b15d47a Add implementation plan for daemon threads and Event-based timing refactor 2026-03-24 13:22:36 -04:00
d8747317df Add design spec for daemon threads and Event-based timing refactor 2026-03-24 13:22:36 -04:00
github-actions[bot]
4cc90a53ed
chore: update AUTHORS [skip ci] 2026-03-24 17:12:56 +00:00
dependabot[bot]
425ad469b0
Bump marshmallow from 3.26.1 to 3.26.2 (#207)
Bumps [marshmallow](https://github.com/marshmallow-code/marshmallow) from 3.26.1 to 3.26.2.
- [Changelog](https://github.com/marshmallow-code/marshmallow/blob/3.26.2/CHANGELOG.rst)
- [Commits](https://github.com/marshmallow-code/marshmallow/compare/3.26.1...3.26.2)

---
updated-dependencies:
- dependency-name: marshmallow
  dependency-version: 3.26.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-24 13:12:45 -04:00
bbc2ccd302
Merge pull request #214 from craigerl/fix/cli-command-issues
Fix CLI command inconsistencies
2026-02-28 09:33:31 -05:00
698d218572 Fix JSON serialization of UnknownPacket in stats
The SimpleJSONEncoder didn't handle dataclasses like UnknownPacket,
causing a TypeError when saving stats to disk. Added support for
dataclasses using dataclasses.asdict().
2026-02-27 23:40:14 -05:00
fcfb349d29 Fix CLI command inconsistencies
- Refactor duplicate plugin discovery code into aprsd/utils/package.py
- Fix inconsistent --profile option in listen.py (now uses common_options)
- Add common_options decorator to completion command for consistency
- Improve healthcheck error message for missing APRSClientStats
- Consolidate signal handler in listen.py to use shared one from main.py
2026-02-27 23:35:38 -05:00
7172d6352f address failure for healthcheck 2026-02-19 13:33:55 -05:00
bc8a24bea4 Fix master-build.yml: remove zero-width spaces from GitHub Actions template syntax 2026-02-19 08:33:18 -05:00
ac35c44bc2 another attempt at master build for github 2026-02-18 21:58:54 -05:00
8483d93965 try and fix master build 2026-02-18 14:30:59 -05:00
0248f40604 fixed some type declaration inconsistencies. 2026-02-18 14:20:52 -05:00
6ea9889369 make consumer call signature consistent. 2026-02-18 14:11:25 -05:00
2b7e42802b update the keepalive for kiss 2026-02-18 14:00:52 -05:00
c99a9c919d fixed inconsistent driver send() declaration.
The KISS drivers aren't adhering to the protocol for
defining the send() method.  both now specify that they
return a bool.
2026-02-18 13:49:40 -05:00
202c689658 Replace insecure pickle serialization with JSON
SECURITY FIX: Replace pickle.load() with json.load() to eliminate
remote code execution vulnerability from malicious pickle files.

Changes:
- Update ObjectStoreMixin to use JSON instead of pickle
- Add PacketJSONDecoder to reconstruct Packet objects from JSON
- Change file extension from .p to .json
- Add warning when old pickle files detected
- Add OrderedDict restoration for PacketList
- Update all tests to work with JSON format

Users with existing pickle files must run:
  aprsd dev migrate-pickle

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-17 16:07:55 -05:00
0701db2629 docs on listen 2026-02-10 19:09:07 -05:00
c5ca4f11af Added new APRSDPushStatsThread
This allows an aprsd server instance to push it's to a remote
location.
2026-02-10 18:49:23 -05:00
008fe3c83e Fixed an issue with dev command 2026-02-07 17:17:15 -05:00
3128f24ef7 reverse the threaded plugin processing.
Considering how little processing each plugin has, it's
a bit overkill for now to have a threaded processing of plugins.

Also had issues where the help plugin was responding when it shouldn't.
2026-02-06 17:31:05 -05:00
6968f16cec update multiarch build on tag 2026-02-05 17:23:35 -05:00
03da33c905 change python tests 2026-02-05 17:17:14 -05:00
8b500ac5f1 added ruff to tox 2026-02-05 17:11:40 -05:00