aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-02 22:32:31 +0100
committertv <tv@krebsco.de>2026-11-02 22:32:31 +0100
commit4ae3326ebca32252020b5899e4a3566d0a6b5ec7 (patch)
tree389c0db1bcec235f787a264cf1165d1ffc7ec099
parentdf314df4793765ea5334ac75b97d415286cc7fa3 (diff)
dashboard: show newly joined remote peers asap
-rw-r--r--docs/dashboard.md4
-rw-r--r--docs/openapi.yaml5
-rw-r--r--src/api/dashboard/mod.rs16
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,