$ show craigerl/aprsd
aprsd is a Python daemon for the APRS (Automatic Packet Reporting System) amateur radio protocol, connecting to APRS-IS (Internet Service) and optionally KISS serial/TCP interfaces. It receives and processes APRS packets through a pipeline of duplicate detection, type filtering, and a plugin-based message handler. The system also supports sending messages, beacons, and weather reports, with persistent storage of watch lists and tracked packets. The architecture is modular: client drivers abstract the network connection, a packet factory deserializes raw APRS frames into typed dataclasses, and a threading model handles RX processing, TX scheduling, and keepalive monitoring. Configuration is managed via oslo_config with a sample config generation command. The project is production-grade for its niche, with Docker support, CI/CD, and a documented plugin API for third-party extensions.
The LLM identified 5 files worth highlighting for reuse:
Implements a thread-safe ring buffer using collections.deque with a maximum length. Provides standard methods like append, extend, __len__, __getitem__, and read. The implementation is simple, self-contained, and can be reused in any Python project needing a bounded FIFO buffer.
ObjectStoreMixin provides a reusable pattern for persisting Python dictionaries to JSON files with atomic writes (tempfile + os.replace). Implements get_all, init_store, and data snapshot semantics. Used internally by multiple packet collections (WatchList, SeenList, PacketList) but can be extracted for any application requiring simple file-backed state.
Defines a @singleton decorator that ensures only one instance of a class exists and provides a .reset() method for test isolation. The decorator wraps the class __new__ and __init__ to enforce singleton behavior. This is a clean, reusable implementation suitable for any Python project needing controlled singletons (e.g., configuration managers, connection pools).
Implements a singleton PacketFilter that maintains an ordered list of filter callbacks. Packets are passed through each registered filter; if any filter returns None, the packet is dropped. Filters can be registered/unregistered dynamically. This pattern is a clean implementation of the Chain of Responsibility pattern and can be reused in any packet processing pipeline.
Provides abstract base classes (APRSDPluginBase, APRSDRegexCommandPluginBase, APRSDWatchListPluginBase) and a singleton PluginManager that loads plugins from entry points and configuration. Uses pluggy for hook registration. The pattern of defining abstract hooks and loading modules dynamically is reusable for any extensible Python application, though the specific hook names and processing logic are domain-specific.