From 5099c25df7b06f0cb800d1e1c3a354334a955d19 Mon Sep 17 00:00:00 2001 From: Lorenz Leutgeb Date: Fri, 13 Feb 2026 16:14:36 +0100 Subject: [PATCH] node/debug: Use derived serializers The construction of the debug object is unwieldy, and error prone (for example, renamed struct members have to be manually renamed in the serialization code, see "refs" vs. "refsAt"). Use derived serializers where possible to make this easier to maintain. --- crates/radicle-node/src/runtime/handle.rs | 29 ++----------------- crates/radicle-protocol/src/fetcher/state.rs | 14 +++++---- .../radicle-protocol/src/service/limiter.rs | 3 +- 3 files changed, 12 insertions(+), 34 deletions(-) diff --git a/crates/radicle-node/src/runtime/handle.rs b/crates/radicle-node/src/runtime/handle.rs index 95166895..391d410b 100644 --- a/crates/radicle-node/src/runtime/handle.rs +++ b/crates/radicle-node/src/runtime/handle.rs @@ -350,35 +350,10 @@ impl radicle::node::Handle for Handle { fn debug(&self) -> Result { let (sender, receiver) = chan::bounded(1); let query: Arc = Arc::new(move |state| { - let fetcher_state = state.fetching(); let debug = serde_json::json!({ "outboxSize": state.outbox().len(), - "fetching": fetcher_state.active_fetches() - .iter() - .map(|(rid, active)| { - json!({ - "rid": rid, - "from": active.from(), - "refsAt": active.refs(), - }) - }).collect::>(), - "queue": fetcher_state.queued_fetches().iter().map(|(node, queue)| { - json!({ - "nid": node, - "queue": queue.iter().map(|fetch| { - json!({ - "rid": fetch.rid, - "refsAt": fetch.refs, - }) - }).collect::>() - }) - }).collect::>(), - "rateLimiter": state.limiter().buckets.iter().map(|(host, bucket)| { - json!({ - "host": host.to_string(), - "bucket": bucket - }) - }).collect::>(), + "fetching": state.fetching(), + "rateLimiter": state.limiter(), "events": json!({ "subscribers": state.emitter().subscriptions(), "pending": state.emitter().pending(), diff --git a/crates/radicle-protocol/src/fetcher/state.rs b/crates/radicle-protocol/src/fetcher/state.rs index cde707a6..62b87b77 100644 --- a/crates/radicle-protocol/src/fetcher/state.rs +++ b/crates/radicle-protocol/src/fetcher/state.rs @@ -10,6 +10,7 @@ pub mod event; pub use command::Command; pub use event::Event; +use serde::Serialize; use std::collections::{BTreeMap, VecDeque}; use std::num::NonZeroUsize; @@ -42,7 +43,7 @@ pub const MAX_CONCURRENCY: NonZeroUsize = NonZeroUsize::MIN; /// of fetches can happen with it concurrently. This does not guarantee that the /// node will actually allow this node to fetch from it – since it will maintain /// its own capacity for connections and load. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] pub struct FetcherState { /// The active fetches that are occurring, ensuring only one fetch per repository. active: BTreeMap, @@ -235,7 +236,7 @@ impl FetcherState { } /// Configuration for the [`FetcherState`]. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)] pub struct Config { /// Maximum number of concurrent fetches per peer connection. maximum_concurrency: NonZeroUsize, @@ -271,7 +272,7 @@ impl Default for Config { } /// An active fetch represents a repository being fetched by a particular node. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] pub struct ActiveFetch { pub from: NodeId, pub refs: RefsToFetch, @@ -290,7 +291,7 @@ impl ActiveFetch { } /// A fetch that is waiting to be processed, in the fetch queue. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)] pub struct QueuedFetch { /// The repository that will be fetched. pub rid: RepoId, @@ -304,14 +305,15 @@ pub struct QueuedFetch { /// /// It ensures that the queue contains unique items for fetching, and does not /// exceed the provided maximum capacity. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] pub struct Queue { queue: VecDeque, max_queue_size: MaxQueueSize, } /// The maximum number of fetches that can be queued for a single node. -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] +#[serde(transparent)] pub struct MaxQueueSize(usize); impl MaxQueueSize { diff --git a/crates/radicle-protocol/src/service/limiter.rs b/crates/radicle-protocol/src/service/limiter.rs index 1ef6e50b..704f0f81 100644 --- a/crates/radicle-protocol/src/service/limiter.rs +++ b/crates/radicle-protocol/src/service/limiter.rs @@ -2,6 +2,7 @@ use std::collections::{HashMap, HashSet}; use localtime::LocalTime; use radicle::node::{address, config, HostName, NodeId}; +use serde::Serialize; /// Peer rate limiter. /// @@ -9,7 +10,7 @@ use radicle::node::{address, config, HostName, NodeId}; /// and every request from that address consumes one token. Tokens refill at a predefined /// rate. This mechanism allows for consistent request rates with potential bursts up to the /// bucket's capacity. -#[derive(Debug, Default)] +#[derive(Debug, Default, Serialize)] pub struct RateLimiter { pub buckets: HashMap, pub bypass: HashSet,