1use std::collections::BTreeMap;
6
7use reqwest::Method;
8use serde::{Deserialize, Deserializer};
9
10use crate::client::request;
11use crate::swarm::Error;
12
13use super::DebugApi;
14
15#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
17pub struct Peer {
18 pub address: String,
20 #[serde(default, rename = "fullNode")]
22 pub full_node: bool,
23}
24
25#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
27#[serde(rename_all = "camelCase")]
28pub struct Addresses {
29 pub overlay: String,
31 pub underlay: Vec<String>,
33 pub ethereum: String,
35 pub public_key: String,
37 pub pss_public_key: String,
39}
40
41#[derive(Clone, Debug, PartialEq, Default, Deserialize)]
43#[serde(rename_all = "camelCase")]
44pub struct MetricSnapshotView {
45 #[serde(default)]
47 pub last_seen_timestamp: i64,
48 #[serde(default)]
50 pub session_connection_retry: u64,
51 #[serde(default)]
54 pub connection_total_duration: f64,
55 #[serde(default)]
57 pub session_connection_duration: f64,
58 #[serde(default)]
60 pub session_connection_direction: String,
61 #[serde(default, rename = "latencyEWMA")]
64 pub latency_ewma: i64,
65 #[serde(default)]
68 pub reachability: String,
69 #[serde(default)]
72 pub healthy: bool,
73}
74
75#[derive(Clone, Debug, PartialEq, Default, Deserialize)]
77pub struct PeerInfo {
78 pub address: String,
80 #[serde(default)]
83 pub metrics: Option<MetricSnapshotView>,
84}
85
86#[derive(Clone, Debug, PartialEq, Default, Deserialize)]
92#[serde(rename_all = "camelCase")]
93pub struct BinInfo {
94 #[serde(default, rename = "population")]
96 pub population: u64,
97 #[serde(default, rename = "connected")]
99 pub connected: u64,
100 #[serde(default, deserialize_with = "deserialize_null_or_seq")]
102 pub connected_peers: Vec<PeerInfo>,
103 #[serde(default, deserialize_with = "deserialize_null_or_seq")]
105 pub disconnected_peers: Vec<PeerInfo>,
106}
107
108fn deserialize_null_or_seq<'de, D, T>(d: D) -> Result<Vec<T>, D::Error>
111where
112 D: Deserializer<'de>,
113 T: Deserialize<'de>,
114{
115 Ok(Option::<Vec<T>>::deserialize(d)?.unwrap_or_default())
116}
117
118#[derive(Clone, Debug, PartialEq, Default, Deserialize)]
125#[serde(rename_all = "camelCase")]
126pub struct Topology {
127 pub base_addr: String,
129 pub population: i64,
131 pub connected: i64,
133 pub timestamp: String,
135 pub nn_low_watermark: i64,
137 pub depth: u8,
139 #[serde(default)]
143 pub reachability: String,
144 #[serde(default)]
147 pub network_availability: String,
148 #[serde(default = "default_bins", deserialize_with = "deserialize_bins")]
151 pub bins: Vec<BinInfo>,
152 #[serde(default)]
155 pub light_nodes: BinInfo,
156}
157
158fn default_bins() -> Vec<BinInfo> {
163 vec![BinInfo::default(); 32]
164}
165
166fn deserialize_bins<'de, D>(d: D) -> Result<Vec<BinInfo>, D::Error>
170where
171 D: Deserializer<'de>,
172{
173 let map: Option<BTreeMap<String, BinInfo>> = Option::deserialize(d)?;
175 let mut map = map.unwrap_or_default();
176 let mut out = Vec::with_capacity(32);
177 for i in 0..32u8 {
178 let key = format!("bin_{i}");
179 out.push(map.remove(&key).unwrap_or_default());
180 }
181 Ok(out)
182}
183
184#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
186#[serde(rename_all = "camelCase")]
187pub struct ReserveState {
188 pub radius: u8,
190 pub storage_radius: u8,
192 pub commitment: i64,
194}
195
196impl DebugApi {
197 pub async fn peers(&self) -> Result<Vec<Peer>, Error> {
199 let builder = request(&self.inner, Method::GET, "peers")?;
200 #[derive(Deserialize)]
201 struct Resp {
202 peers: Vec<Peer>,
203 }
204 let r: Resp = self.inner.send_json(builder).await?;
205 Ok(r.peers)
206 }
207
208 pub async fn blocklist(&self) -> Result<Vec<Peer>, Error> {
210 let builder = request(&self.inner, Method::GET, "blocklist")?;
211 #[derive(Deserialize)]
212 struct Resp {
213 peers: Vec<Peer>,
214 }
215 let r: Resp = self.inner.send_json(builder).await?;
216 Ok(r.peers)
217 }
218
219 pub async fn remove_peer(&self, address: &str) -> Result<(), Error> {
221 let path = format!("peers/{address}");
222 let builder = request(&self.inner, Method::DELETE, &path)?;
223 self.inner.send(builder).await?;
224 Ok(())
225 }
226
227 pub async fn ping_peer(&self, address: &str) -> Result<String, Error> {
230 let path = format!("pingpong/{address}");
231 let builder = request(&self.inner, Method::POST, &path)?;
232 #[derive(Deserialize)]
233 struct Resp {
234 rtt: String,
235 }
236 let r: Resp = self.inner.send_json(builder).await?;
237 Ok(r.rtt)
238 }
239
240 pub async fn connect_peer(&self, multiaddr: &str) -> Result<String, Error> {
245 let trimmed = multiaddr.trim_start_matches('/');
246 let path = format!("connect/{trimmed}");
247 let builder = request(&self.inner, Method::POST, &path)?;
248 #[derive(Deserialize)]
249 struct Resp {
250 address: String,
251 }
252 let r: Resp = self.inner.send_json(builder).await?;
253 Ok(r.address)
254 }
255
256 pub async fn addresses(&self) -> Result<Addresses, Error> {
258 let builder = request(&self.inner, Method::GET, "addresses")?;
259 self.inner.send_json(builder).await
260 }
261
262 pub async fn topology(&self) -> Result<Topology, Error> {
264 let builder = request(&self.inner, Method::GET, "topology")?;
265 self.inner.send_json(builder).await
266 }
267
268 pub async fn reserve_state(&self) -> Result<ReserveState, Error> {
270 let builder = request(&self.inner, Method::GET, "reservestate")?;
271 self.inner.send_json(builder).await
272 }
273
274 pub async fn welcome_message(&self) -> Result<String, Error> {
276 let builder = request(&self.inner, Method::GET, "welcome-message")?;
277 #[derive(Deserialize)]
278 struct Resp {
279 #[serde(rename = "welcomeMessage")]
280 welcome_message: String,
281 }
282 let r: Resp = self.inner.send_json(builder).await?;
283 Ok(r.welcome_message)
284 }
285
286 pub async fn set_welcome_message(&self, message: &str) -> Result<(), Error> {
288 #[derive(serde::Serialize)]
289 struct Body<'a> {
290 #[serde(rename = "welcomeMessage")]
291 welcome_message: &'a str,
292 }
293 let body = serde_json::to_vec(&Body {
294 welcome_message: message,
295 })?;
296 let builder = request(&self.inner, Method::POST, "welcome-message")?
297 .header("Content-Type", "application/json")
298 .body(bytes::Bytes::from(body));
299 self.inner.send(builder).await?;
300 Ok(())
301 }
302}