feat: overhaul radio reconnection, TUI layout, DHT strategy, and signal handling
Radio reconnection: - Add connect_mux_auto() to donglora-client — mux-only connect that never silently falls back to USB serial (matches Python client's sticky mux) - Fix codec.rs read_frame() to handle WouldBlock alongside TimedOut - Add liveness ping (2s) to detect dead mux connections - Treat transmit errors as fatal (trigger reconnect) - Faster backoff: 250ms initial, 5s max, resets after stable connection TUI improvements: - Redesign packet log: RF+Net columns show full packet path (RX→TX), hash column with dedup ellipsis, fixed-width columns throughout - Move activity charts to right column (fills remaining width) - 1-second sparkline buckets instead of 10-second - Radio panel shows "(disconnected)" with red border when mux is down - Header: status pills left, clock with TZ right-justified, Ctrl-C quits - Local time via jiff crate with proper timezone abbreviation DHT strategy: - Alone: read every 3s, merge-publish every 30s (preserves existing peers) - Connected: publish authoritative [self + neighbors], purging stale peers - Publish immediately on first neighbor join Signal handling: - SIGINT and SIGTERM both trigger graceful shutdown via cancellation token - All paths go through swarm.shutdown() to update DHT before exit
This commit is contained in:
7 files changed
+373
-175
No files matched your search
+17
-10
@@ -142,6 +142,7 @@ async fn main() -> Result<()> {
|
||||
requested: radio_config,
|
||||
source: radio::ConfigSource::Ours,
|
||||
device: String::new(),
|
||||
connected: false,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -175,18 +176,25 @@ async fn main() -> Result<()> {
|
||||
router_cancel.cancel();
|
||||
});
|
||||
|
||||
// Spawn a task that cancels on ctrl-c or SIGTERM.
|
||||
{
|
||||
let cancel = cancel.clone();
|
||||
tokio::spawn(async move {
|
||||
let mut sigterm = tokio::signal::unix::signal(
|
||||
tokio::signal::unix::SignalKind::terminate(),
|
||||
).expect("failed to register SIGTERM handler");
|
||||
tokio::select! {
|
||||
_ = tokio::signal::ctrl_c() => info!("received SIGINT"),
|
||||
_ = sigterm.recv() => info!("received SIGTERM"),
|
||||
}
|
||||
cancel.cancel();
|
||||
});
|
||||
}
|
||||
|
||||
// Run TUI or headless.
|
||||
if cli.log_only {
|
||||
info!("running in headless mode");
|
||||
tokio::select! {
|
||||
() = cancel.cancelled() => {},
|
||||
result = tokio::signal::ctrl_c() => {
|
||||
if let Err(e) = result {
|
||||
tracing::error!("signal handler error: {e}");
|
||||
}
|
||||
info!("received ctrl-c, shutting down");
|
||||
}
|
||||
}
|
||||
cancel.cancelled().await;
|
||||
} else {
|
||||
let terminal = tui::run(
|
||||
config_watch_rx,
|
||||
@@ -210,7 +218,6 @@ async fn main() -> Result<()> {
|
||||
}
|
||||
|
||||
// Shutdown (headless path).
|
||||
cancel.cancel();
|
||||
swarm.shutdown().await;
|
||||
info!("donglora-bridge stopped");
|
||||
|
||||
|
||||
Reference in new issue
Block a user