aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-31 04:09:40 +0100
committertv <tv@krebsco.de>2026-10-31 04:09:40 +0100
commit4a2793864047134c6521dc44562828b6ab071c17 (patch)
tree9c5baa8f44d2ae1888a2d64c86d5bb4692d0f82c
parentac65b537339b9bbb5528fe94e4587fa01ae6f34c (diff)
add lastSyncSecsAgo and description to /peers
-rw-r--r--docs/openapi.yaml13
-rw-r--r--src/api/dashboard/dashboard.html2
-rw-r--r--src/api/dashboard/mod.rs1
-rw-r--r--src/api/peers.rs11
4 files changed, 23 insertions, 4 deletions
diff --git a/docs/openapi.yaml b/docs/openapi.yaml
index b04c98a..b7c632d 100644
--- a/docs/openapi.yaml
+++ b/docs/openapi.yaml
@@ -584,9 +584,10 @@ paths:
`{"all": true}` when too many changed or the node lost count. When the node
stops, an `offline` event ends the stream (a client reconnects once the node
is back). Nothing changed, nothing is sent but keep-alive comments.
- Ages (`…SecsAgo`, `secsAgo`, `uptimeSecs`, `dormantForSecs`, `observedSecs`,
- `lastFromNeighbourSecs`, `oldestQuarantineSecs`) are as of the event: they
- alone changing sends nothing, the client counts them on. Only with the
+ Ages (`…SecsAgo`, `secsAgo`, `uptimeSecs`, `dormantForSecs`,
+ `divergedForSecs`, `observedSecs`, `lastFromNeighbourSecs`,
+ `oldestQuarantineSecs`) are as of the event: they alone changing sends
+ nothing, the client counts them on. Only with the
`dashboard` cargo feature.
responses:
'200':
@@ -1337,6 +1338,12 @@ components:
type: [integer, 'null']
dormantForSecs:
type: [integer, 'null']
+ lastSyncSecsAgo:
+ type: [integer, 'null']
+ description: Since a sync message from it was applied (or the epoch changed).
+ divergedForSecs:
+ type: [integer, 'null']
+ description: How long its heads have differed from ours with no sync message from it in between; null while they match.
hasPendingDelivery:
type: boolean
epoch:
diff --git a/src/api/dashboard/dashboard.html b/src/api/dashboard/dashboard.html
index 0bbd9c5..091d7ee 100644
--- a/src/api/dashboard/dashboard.html
+++ b/src/api/dashboard/dashboard.html
@@ -163,7 +163,7 @@ let state = null;
let stateAt = 0;
// Fields that grow by themselves (`GROWING` and `is_age` in the node's dashboard).
-const GROWING = new Set(["uptimeSecs", "dormantForSecs", "observedSecs",
+const GROWING = new Set(["uptimeSecs", "dormantForSecs", "divergedForSecs", "observedSecs",
"lastFromNeighbourSecs", "oldestQuarantineSecs"]);
const isAge = key => key === "secsAgo" || key.endsWith("SecsAgo") || GROWING.has(key);
const elapsed = () => Math.floor((Date.now() - stateAt) / 1000);
diff --git a/src/api/dashboard/mod.rs b/src/api/dashboard/mod.rs
index 86f349a..ad907ed 100644
--- a/src/api/dashboard/mod.rs
+++ b/src/api/dashboard/mod.rs
@@ -324,6 +324,7 @@ fn links_json(links: &[Link]) -> JsonValue {
const GROWING: &[&str] = &[
"uptimeSecs",
"dormantForSecs",
+ "divergedForSecs",
"observedSecs",
"lastFromNeighbourSecs",
"oldestQuarantineSecs",
diff --git a/src/api/peers.rs b/src/api/peers.rs
index da714d0..2f93a43 100644
--- a/src/api/peers.rs
+++ b/src/api/peers.rs
@@ -61,6 +61,11 @@ pub(crate) struct PeerStatus {
handshake_complete: bool,
last_seen_secs_ago: Option<u64>,
dormant_for_secs: Option<u64>,
+ /// Since a sync message from it was applied (or the epoch changed).
+ last_sync_secs_ago: Option<u64>,
+ /// How long its heads have differed from ours with no sync message from it in
+ /// between; absent while they match.
+ diverged_for_secs: Option<u64>,
has_pending_delivery: bool,
/// Epoch the peer last advertised; absent until it has sent a message.
epoch: Option<EpochInfo>,
@@ -166,6 +171,12 @@ pub(crate) async fn peer_list(state: &AppState) -> PeerListResponse {
.last_seen
.map(|t| now.saturating_duration_since(t).as_secs()),
dormant_for_secs,
+ last_sync_secs_ago: ps
+ .last_sync_rx
+ .map(|t| now.saturating_duration_since(t).as_secs()),
+ diverged_for_secs: ps
+ .diverged_since
+ .map(|t| now.saturating_duration_since(t).as_secs()),
has_pending_delivery: ps.sync.sending.is_some() || ps.sync.retry_at.is_some(),
epoch: ps.epoch.map(EpochInfo::from),
same_epoch: ps.epoch.map(|epoch| epoch == local_epoch),