Files
mux-py/CHANGELOG.md
swaits e81cb9dc20
CI / lint (push) Canceled after 0s
CI / test (3.10) (push) Canceled after 0s
CI / test (3.11) (push) Canceled after 0s
CI / test (3.12) (push) Canceled after 0s
CI / test (3.13) (push) Canceled after 0s
CI / publish (push) Canceled after 0s
chore: release 1.0.0
2026-04-22 09:56:05 -06:00

3.8 KiB
Raw Permalink Blame History

Changelog

1.0.0 — 2026-04-22

Breaking

  • Upgraded to the DongLoRa Protocol v2 wire format. The 0.x line spoke the legacy v0.1 protocol with hardcoded tag constants (TAG_OK=4, TAG_ERROR=5, CMD_TAG_SET_CONFIG=2, …) that don't exist in v1.0. This release is wire-incompatible with 0.x clients and firmware.
  • Pins donglora>=1.0.0 and uses its donglora.frame / donglora.events / donglora.commands modules as the wire-level backbone. No more in-package reimplementation of the wire protocol.
  • Structural rewrite mirroring the Rust sibling donglora-mux one-to-one: donglora_mux/{daemon,intercept,session,tagmap}.py replace the single 601-line __init__.py.

Added

  • TagMapper — per-command device-tag allocator. Enables concurrent out-of-order command/response correlation for multi-client setups (the v0.1-era single-oneshot-response slot is gone).
  • Full §13.2 multi-client SET_CONFIG semantics — tracks the (client_id, modulation) lock owner. Cross-client calls synthesize:
    • OK(APPLIED / MINE, params) when the caller owns the lock (forwarded to dongle).
    • OK(ALREADY_MATCHED / OTHER, current) when another client holds the lock and the requested params byte-match.
    • OK(LOCKED_MISMATCH / OTHER, current) when they differ; current echoes the lock owner's actual modulation.
    • Lock auto-releases when the owning client disconnects.
  • TX loopback fan-out (§13.4) — on TX_DONE(TRANSMITTED) the mux synthesizes an RX frame with origin = LOCAL_LOOPBACK and sends it to every connected client except the transmitter.
  • Async ERR(EFRAME) fan-out — if the dongle emits async framing errors (tag 0), they're broadcast to all clients rather than swallowed.
  • Per-client TX cache on ClientSession so the loopback fan-out doesn't need the sender to re-buffer the payload.
  • Socket and serial file locking (fcntl.flock) to prevent multiple mux instances from fighting over the same dongle or socket path.
  • 500 ms keepalive matching PROTOCOL.md §3.4 (2× margin on the 1 s inactivity timer). Replaces the 5 s cadence from 0.x.
  • Clean ^C / SIGTERM shutdown — per-client handler tasks are tracked and cancelled on shutdown, so blocked reader.read() calls no longer pin the event loop open.

Removed

  • Every v0.1 wire constant and the inline cobs + raw serial.Serial frame codec.
  • The single pending_response: asyncio.Future slot (fundamentally incompatible with v1.0's per-tag concurrency).

Test coverage

  • 28 tests (up from 11):
    • test_tagmap.py (6) — tag allocator behaviour.
    • test_intercept.py (13) — every branch of the decide() matrix, including the ALREADY_MATCHED / LOCKED_MISMATCH synthesis paths.
    • test_multiclient.py (9) — asyncio-driven daemon dispatch tests: concurrent tag routing, SET_CONFIG lock installation, TX loopback to peer clients, lock release on disconnect, unsolicited-frame drop.

0.2.0 — 2026-04-08

Features

  • PyPI-ready metadata — full classifiers, URLs, keywords, readme. Publishable as donglora-mux.
  • Interception test suite — 11 tests ported from the Rust mux covering SetConfig locking, StartRx/StopRx reference counting, and passthrough behaviour.
  • GitHub Actions CI — ruff lint + format, pytest on Python 3.10–3.13, PyPI publish on tag.
  • Strict ruff linting — E, W, F, I, UP, B, C4, ARG, SIM, RUF rules.

Fixes

  • Fixed broken dependency path (../../clients/python → ../client-py).
  • Fixed dependency name (donglora-python → donglora).
  • Applied contextlib.suppress where ruff/SIM105 flagged try-except-pass.
  • Collapsed nested if per ruff/SIM102.

0.1.0 — 2026-04-06

Initial release.