From 4ae3326ebca32252020b5899e4a3566d0a6b5ec7 Mon Sep 17 00:00:00 2001 From: tv Date: Mon, 2 Nov 2026 22:32:31 +0100 Subject: dashboard: show newly joined remote peers asap --- docs/dashboard.md | 4 +++- docs/openapi.yaml | 5 +++-- src/api/dashboard/mod.rs | 16 ++++++++++++++-- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/docs/dashboard.md b/docs/dashboard.md index d39022d..a93e4d4 100644 --- a/docs/dashboard.md +++ b/docs/dashboard.md @@ -285,7 +285,9 @@ are done. The map isn't redrawn under the pointer: what you point at stays put. built with `dashboard` (404), or the user isn't in `--htpasswd` (401). * **A hollow node**: no links report from it. If it is also dormant here, it is probably down or unreachable; if not, it may not take this node for a member yet - (it hasn't registered it), or its answers don't arrive. + (it hasn't registered it), or its answers don't arrive. A node that just joined + through others shows as soon as one of them reports a link to it, hollow until its + registration reaches this node and it is asked for its links (within 30 s). * **Only dashed grey between two nodes**: the member list wants them as neighbours, but neither reports a link to the other: they haven't reached each other (yet). * **A dotted link**: one end has stopped reporting; the link is as it was last diff --git a/docs/openapi.yaml b/docs/openapi.yaml index 8ffc8d7..387a7ac 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -748,8 +748,9 @@ paths: description: | The dashboard's latest snapshot: `node` (`id`, `alias`), `page` (the page's version, a hash: a page showing another reloads), `stats` (as - `/admin/stats`), `peers` (as `/peers`) and `graph`: `members` (by node ID: - `alias`, `self`, `dashboard`: its `--dashboard-url`), `intended` (by node ID: the neighbours the member list gives + `/admin/stats`), `peers` (as `/peers`) and `graph`: `members` (by node ID, + those of the member list, and any a link reported goes to: `alias`, `self`, + `dashboard`: its `--dashboard-url`), `intended` (by node ID: the neighbours the member list gives it, as this node computes them), `measured` (by node ID: `secsAgo` and `links`, each with `peer`, `transport`, `relayed`, `down`, `rttMs`, `dormant` and `others` (the peer's other transports: `transport`, `rttMs`, `relayed`), as the member diff --git a/src/api/dashboard/mod.rs b/src/api/dashboard/mod.rs index 91b81d4..14321a8 100644 --- a/src/api/dashboard/mod.rs +++ b/src/api/dashboard/mod.rs @@ -361,9 +361,21 @@ async fn build(state: &AppState, graph: &Graph, live: bool) -> JsonValue { ), u64::try_from(state.clock_skew_warn.as_millis()).unwrap_or(u64::MAX), ); - // Everyone on the map: in the member list's graph, or measured. + // Everyone on the map: in the member list's graph, measured, or at the other end of + // a link measured. A node that joined through others is linked to them before its + // registration reaches this node, and before the graph is computed again + // (`LINKS_EVERY`); it shows then, hollow (no links of its own reported). + let linked: BTreeSet<&String> = own + .iter() + .chain( + replies + .iter() + .flat_map(|(_, _, member_links)| member_links.iter()), + ) + .map(|link| &link.peer) + .collect(); let mut members_json = Map::new(); - for member in graph.intended.keys().chain(measured.keys()) { + for member in graph.intended.keys().chain(measured.keys()).chain(linked) { members_json.insert( member.clone(), json!({ "alias": aliases.get(member), "self": member == local, -- cgit v1.3.1