From c11324bef3e93aac3748c6bb62c4a60872ea3f62 Mon Sep 17 00:00:00 2001 From: tv Date: Mon, 26 Oct 2026 22:57:47 +0100 Subject: peers in /peers is an attrset --- docs/openapi.yaml | 11 +++++------ src/api/peers.rs | 52 ++++++++++++++++++++++++++++------------------------ 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/docs/openapi.yaml b/docs/openapi.yaml index ae28c91..bfb297d 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -210,7 +210,7 @@ paths: summary: List known peers responses: '200': - description: Peers, sorted by public key. + description: Peers, by public key. content: application/json: schema: @@ -1080,16 +1080,15 @@ components: type: integer description: 'Heads of the local document (more than one: concurrent changes not yet merged).' peers: - type: array - items: + type: object + description: By public key. + additionalProperties: $ref: '#/components/schemas/Peer' Peer: type: object - required: [publicKey, status, handshakeComplete, hasPendingDelivery, neighbour, traffic, incidents] + required: [status, handshakeComplete, hasPendingDelivery, neighbour, traffic, incidents] properties: - publicKey: - type: string alias: type: [string, 'null'] description: The name the peer gave itself (`--alias`); not unique. diff --git a/src/api/peers.rs b/src/api/peers.rs index f0fd1d9..bc32ae1 100644 --- a/src/api/peers.rs +++ b/src/api/peers.rs @@ -1,5 +1,7 @@ //! /peers handlers. +use std::collections::BTreeMap; + use axum::{ Json, extract::{Path, Query, State}, @@ -44,7 +46,6 @@ impl From for EpochInfo { #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub(crate) struct PeerStatus { - public_key: String, /// The name the peer gave itself in the member list, if any (not unique). alias: Option, validated_swarm: Option, @@ -58,7 +59,7 @@ pub(crate) struct PeerStatus { /// Whether that epoch equals ours, i.e. whether we sync with this peer. same_epoch: Option, /// Number of heads in its last keepalive; absent before one, or when it had more - /// than 32 (then only their digest is sent). + /// than 32 (then only their digest and some of them are sent). heads: Option, /// We keep it alive and sync with it on our own; other peers we only answer. neighbour: bool, @@ -92,7 +93,8 @@ pub(crate) struct PeerListResponse { /// Number of heads of our document. Several heads are concurrent changes no later /// change has merged yet. local_heads: usize, - peers: Vec, + /// By public key. + peers: BTreeMap, } #[derive(Debug, Deserialize)] @@ -110,7 +112,7 @@ pub(crate) async fn list_peers( let now = Instant::now(); let local_epoch = state.local_epoch(); let mut aliases = crate::swarm::members::aliases(&state.doc.read().await.doc); - let mut peers = Vec::with_capacity(snapshot.len()); + let mut peers = BTreeMap::new(); for (public_key, peer_state_mutex) in snapshot { let neighbour = crate::swarm::topology::is_neighbour(&state, &public_key); @@ -138,29 +140,31 @@ pub(crate) async fn list_peers( ), }; - peers.push(PeerStatus { - alias: aliases.remove(&public_key), + let alias = aliases.remove(&public_key); + peers.insert( public_key, - validated_swarm: ps.standing.swarm_id().map(str::to_owned), - status, - handshake_complete: ps.hello_state == HelloState::Established, - last_seen_secs_ago: ps - .last_seen - .map(|t| now.saturating_duration_since(t).as_secs()), - dormant_for_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), - heads: ps.reported_heads, - neighbour, - rtt_ms, - traffic, - incidents: ps.incidents, - sync_throughput, - }); + PeerStatus { + alias, + validated_swarm: ps.standing.swarm_id().map(str::to_owned), + status, + handshake_complete: ps.hello_state == HelloState::Established, + last_seen_secs_ago: ps + .last_seen + .map(|t| now.saturating_duration_since(t).as_secs()), + dormant_for_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), + heads: ps.reported_heads, + neighbour, + rtt_ms, + traffic, + incidents: ps.incidents, + sync_throughput, + }, + ); } - peers.sort_by(|a, b| a.public_key.cmp(&b.public_key)); let local_heads = state.doc.read().await.heads().len(); Ok(Json(PeerListResponse { local_alias: state.alias.clone(), -- cgit v1.3.1