Two halves, one binary
A Rust backend owns the sockets and all state; a static HTML/CSS/JS frontend renders it. They talk over Tauri's IPC — commands one way, events the other. Nothing else is running.
served from the binary
9 event types ←
rules, feeds, replay
clients on the wire
What happens to a line on the wire
Every byte a client sends walks the same path, whichever transport or framing it arrived on.
Outbound bytes are re-framed by the same codec and pushed to a client's own unbounded channel (TCP) or sent to its address (UDP), then logged to the stream with per-client counters updated.
Ten small Rust modules
Each does one thing; the pure ones (codec, payload, rules) carry the unit tests.
windowed entry point → lib::run().
Tauri builder, the 25-command registry, and config load on startup.
config types, metrics, client records, recorder/replay state — the one shared AppState.
TCP accept loop, UDP loop + idle sweeper, per-client tasks, delivery, feeds and replay.
the framing codec — newline / CRLF / length-prefix / raw — as a Tokio Decoder/Encoder.
text-escape and hex parsing in; byte→text/hex rendering out, with binary detection.
the auto-responder — compile, match, and the template renderer.
the timer-feed generator and the built-in geo world-map simulator.
load/save config.json in the app config directory.
the 25 IPC handlers the dashboard calls.
Concurrency & design choices
A task per client
Each connection runs on its own Tokio task with a select! over "bytes to send", "bytes received" and "kick". A per-client cancellation token makes a kick or a shutdown close the socket immediately — no polling, no polite timeout.
Lock-light shared state
DashMap for the client roster and channels, atomics for the counters, and parking_lot mutexes only for the small ring buffers. The metrics snapshot is a cheap read.
Live config, no bounce
Saving rules or feeds recompiles them and restarts the feed tasks in place via a swappable token — the listener never drops. Only bind, transport and framing need a restart.
No runtime, no sidecar
Everything is in one Rust binary behind the webview. No .NET, no Node, no Python, no external service — the whole reason the download is ~6 MB and starts instantly.
Small modules, one shared state, a task per socket. Boring on purpose — so the neon can be the interesting part.