P3: routes (selected, fallback, queried)

Backend
- api/routes.rs models the Babel-style route shape; metric uses an
  untagged enum to round-trip both numeric hop counts and the
  literal "infinite" string the daemon emits for poisoned routes
- routes_snapshot() runs the three GETs concurrently with try_join
  so the snapshot is internally consistent
- poller spawns a second 5s loop emitting routes://updated; both
  loops are owned by the Poller and aborted together on stop_daemon

Frontend
- routes store mirrors the snapshot shape; tabbed view (radix-vue)
  with selected, fallback and queried lists
- RouteTable component shared by selected/fallback; metric column
  is colour-coded (0 green, low neutral, high yellow, infinite red)
- Queried subnets show a live `expires in 12s` countdown driven by
  a 1Hz tick ref instead of mutating the store
This commit is contained in:
syoul
2026-04-25 23:02:32 +02:00
parent c1a81a9065
commit 95e7cb4bd3
9 changed files with 382 additions and 34 deletions

View File

@@ -1,5 +1,6 @@
use crate::api::admin::NodeInfo;
use crate::api::peers::{AggregatedStats, PeerInfo};
use crate::api::routes::RoutesSnapshot;
use crate::api::MyceliumClient;
use crate::error::{AppError, AppResult};
use crate::sidecar::SidecarConfig;
@@ -91,3 +92,10 @@ pub async fn peers_stats(state: State<'_, AppState>) -> AppResult<AggregatedStat
let peers = require_client(&state)?.list_peers().await?;
Ok(crate::api::peers::aggregate(&peers))
}
// ─── Routes ──────────────────────────────────────────────────────────────────
#[tauri::command]
pub async fn routes_snapshot(state: State<'_, AppState>) -> AppResult<RoutesSnapshot> {
require_client(&state)?.routes_snapshot().await
}