# Heartbeat Daemon (hbd) โœ… A lightweight daemon that listens for UDP heartbeat messages and acts on them: keeps host state, optionally updates DNS records via `nsupdate`, forwards messages to WebSocket clients, and sends notifications (email, Pushover, Mattermost, Signal). It is a refactor of a previously monolithic script into a modular Python package (`hbd`). --- ## ๐Ÿ“Œ Features - Receive and parse heartbeat datagrams (text or zlib-compressed) โœ… - Maintain host state and detect up/down transitions โœ… - Queue DNS updates via `nsupdate` and run them in a background thread โœ… - WebSocket API for live updates (hosts & messages) โœ… - Notification pipeline (email, Pushover, Mattermost, Signal) โœ… - Modular codebase suitable for unit testing and CI โœ… --- ## โš™๏ธ Quickstart Prerequisites: - Python 3.10+ (project uses language features from recent Python) - `nsupdate` (for DNS updates) if using dynamic DNS Install dependencies (recommended into a venv): ```bash python3 -m venv .venv source .venv/bin/activate python -m pip install --upgrade pip python -m pip install -r requirements.txt # for development/testing tools python -m pip install -r requirements-dev.txt ``` Run the daemon (example): ```bash # run with default config lookup (~/.hb.yaml) PYTHONPATH=. hbd -c .hb.yaml -f -v ``` You can also run it directly via the package entrypoint after installation: ```bash python -m hbd.cli -c /path/to/config.yaml ``` ## ๐Ÿž Debugging in VS Code This repository includes a ready-to-use `.vscode/launch.json` with configurations to run or attach the VS Code debugger to `hbd`. - Ensure the **Python** extension is installed and select the project `.venv` as the interpreter (bottom-left of VS Code). - Use **F5** and pick one of these configurations from the Run view: - **Python: Run hbd (module)** โ€” runs `hbd.cli` as a module and sets `PYTHONPATH` to the workspace root (recommended). - **Python: Run hbd with debugpy (listen)** โ€” launches `debugpy` and `hbd` together; useful when you want the process to listen for a debugger. - **Python: Attach (localhost:5678)** โ€” attach the debugger to a running process started with `debugpy`. To start `hbd` manually and wait for the debugger to attach, run: ```bash PYTHONPATH=. python -m debugpy --listen 5678 --wait-for-client -m hbd.cli -c .hb.yaml -f -v ``` Set breakpoints in modules such as `hbd/udp.py`, `hbd/dns.py`, or `hbd/server.py`, and use the **Attach** configuration to connect. Use `justMyCode: false` if you need to step into third-party code. --- ## ๐Ÿ›  Configuration `hbd` reads YAML configuration (optional). If `PyYAML` is not installed, built-in defaults are used. Example configuration keys (see `hbd/config.py`): - `hb_port`: UDP port to listen for heartbeats (default: 50003) - `hbd_port`: internal control port (default: 50004) - `hbd_host`: bind address for HTTP/WSS - `pickfile`: path for persisted state - `logfile`: path to log file - `logfmt`: `text` or `msg` - `pushsrv`: push service (`pushover`|`mattermost`|`all`) - `interval` / `grace`: heartbeat timing configuration - `dyndomains`: list of dyndomains to update via `nsupdate` - `nsupdate_bin`: path to nsupdate binary Example `.hb.yaml` (minimal): ```yaml hbd_host: 0.0.0.0 hbd_port: 50004 dyndomains: - example.com nsupdate_bin: /usr/bin/nsupdate pushsrv: pushover ``` > Tip: `config.DEFAULTS` in `hbd/config.py` contains the canonical defaults and accepted configuration keys. --- ## ๐Ÿ”ง Architecture & Modules - `hbd.proto` โ€” serialization/deserialization of heartbeat messages (supports compressed payloads) - `hbd.udp` โ€” UDP parsing and `handle_datagram` implementation (main state machine) - `hbd.dns` โ€” `create_nsupdate_payload`, `nsupdate`, and a background DNS thread (`start_dns_thread`) - `hbd.notify` โ€” email and push notification helpers - `hbd.ws` โ€” WebSocket server and thread-safe broadcast helpers - `hbd.http` โ€” HTTP handler factory for the status UI/API - `hbd.utils` โ€” small utility helpers (`shortname`, `dur`, `initlog`) - `hbd.cli` โ€” CLI entrypoint and argument parsing - `hbd.server` โ€” async orchestration to run UDP/HTTP/WSS components This modular layout makes the code easier to test and maintain. --- ## ๐Ÿงช Testing & Dev Tests are implemented using `unittest` and additional tests rely on `pytest` if you prefer. To run tests locally without installing anything beyond the dev requirements: ```bash # with project root on PYTHONPATH PYTHONPATH=. python -m unittest discover -v # or with pytest if installed pytest -q ``` Developer tooling included: - `pyproject.toml` โ€” project metadata and dependencies - `requirements-dev.txt` โ€” dev/test dependencies - `tox.ini` โ€” convenience wrappers for running tests, lint, and mypy To run linters and type checks locally: ```bash # after installing dev deps tox -e lint tox -e mypy ``` --- ## ๐Ÿš€ Running in production - Use your system service manager (systemd, launchd, etc.) to run `hbd` in the background. - Ensure `nsupdate` and necessary credentials are available for dynamic DNS updates. - Configure TLS for WSS if you enable secure websockets. > Note: The project contains a small example for obtaining DNS-verified certs (certbot with RFC2136) โ€” see earlier commit history or ask me to re-add the example to this README if you want it documented here. --- ## ๐Ÿค Contributing Contributions welcome! Please: 1. Open an issue to discuss larger changes. 2. Create a topic branch and a clear PR. 3. Add tests for new features and run linters. 4. Keep changes focused and documented. --- ## ๐Ÿ“œ License This repository is licensed under the MIT license. See `LICENSE` for details. --- If you'd like, I can also: - add a **GitHub Actions** workflow that runs tests and lint on push/PR ๐Ÿ” - add a `CONTRIBUTING.md` template for PRs and code style ๐Ÿ’ฌ Which one should I do next? โœจ