From 920efe0b597866759ba3d7b3e70e9f9d8e69bd2b Mon Sep 17 00:00:00 2001 From: Bo QIU <35757521+boqiu@users.noreply.github.com> Date: Tue, 16 Jul 2024 14:57:36 +0800 Subject: [PATCH] enhance admin rpc to return peers instead of dump (#128) --- node/rpc/src/admin/api.rs | 6 +-- node/rpc/src/admin/impl.rs | 26 ++++------- node/rpc/src/types.rs | 95 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 19 deletions(-) diff --git a/node/rpc/src/admin/api.rs b/node/rpc/src/admin/api.rs index a83f47d..adc23b9 100644 --- a/node/rpc/src/admin/api.rs +++ b/node/rpc/src/admin/api.rs @@ -1,4 +1,4 @@ -use crate::types::NetworkInfo; +use crate::types::{NetworkInfo, PeerInfo}; use jsonrpsee::core::RpcResult; use jsonrpsee::proc_macros::rpc; use std::collections::HashMap; @@ -33,6 +33,6 @@ pub trait Rpc { #[method(name = "getNetworkInfo")] async fn get_network_info(&self) -> RpcResult; - #[method(name = "dumpPeers")] - async fn dump_peers(&self, file: Option) -> RpcResult; + #[method(name = "getPeers")] + async fn get_peers(&self) -> RpcResult>; } diff --git a/node/rpc/src/admin/impl.rs b/node/rpc/src/admin/impl.rs index b092255..4ce73f5 100644 --- a/node/rpc/src/admin/impl.rs +++ b/node/rpc/src/admin/impl.rs @@ -1,12 +1,10 @@ use super::api::RpcServer; -use crate::types::NetworkInfo; +use crate::types::{NetworkInfo, PeerInfo}; use crate::{error, Context}; use futures::prelude::*; use jsonrpsee::core::async_trait; use jsonrpsee::core::RpcResult; -use network::PeerInfo; use std::collections::HashMap; -use std::fs::File; use sync::{FileSyncInfo, SyncRequest, SyncResponse}; use task_executor::ShutdownReason; @@ -150,20 +148,16 @@ impl RpcServer for RpcServerImpl { }) } - #[tracing::instrument(skip(self), err)] - async fn dump_peers(&self, file: Option) -> RpcResult { - info!("admin_dumpPeers()"); + async fn get_peers(&self) -> RpcResult> { + info!("admin_getPeers()"); - let db = self.ctx.network_globals.peers.read(); - - let peers: HashMap = db + Ok(self + .ctx + .network_globals + .peers + .read() .peers() - .map(|(peer_id, info)| (peer_id.to_base58(), info.clone())) - .collect(); - - let file = File::create(file.unwrap_or("peers.json".into()))?; - serde_json::to_writer_pretty(&file, &peers)?; - - Ok(peers.len()) + .map(|(peer_id, info)| (peer_id.to_base58(), info.into())) + .collect()) } } diff --git a/node/rpc/src/types.rs b/node/rpc/src/types.rs index 1cc9e1e..038765d 100644 --- a/node/rpc/src/types.rs +++ b/node/rpc/src/types.rs @@ -9,7 +9,10 @@ use serde::{Deserialize, Serialize}; use shared_types::{ compute_padded_chunk_size, compute_segment_size, DataRoot, FileProof, Transaction, CHUNK_SIZE, }; +use std::collections::HashSet; use std::hash::Hasher; +use std::net::IpAddr; +use std::time::Instant; use storage::log_store::log_manager::bytes_to_entries; use storage::H256; @@ -255,6 +258,98 @@ impl SegmentWithProof { } } +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PeerInfo { + pub client: Client, + pub connection_status: PeerConnectionStatus, + pub listening_addresses: Vec, + pub seen_ips: HashSet, + pub is_trusted: bool, + pub connection_direction: Option, // Incoming/Outgoing + pub enr: Option, +} + +impl From<&network::PeerInfo> for PeerInfo { + fn from(value: &network::PeerInfo) -> Self { + Self { + client: value.client().clone().into(), + connection_status: value.connection_status().clone().into(), + listening_addresses: value.listening_addresses().clone(), + seen_ips: value.seen_ip_addresses().collect(), + is_trusted: value.is_trusted(), + connection_direction: value.connection_direction().map(|x| match x { + network::ConnectionDirection::Incoming => "Incoming".into(), + network::ConnectionDirection::Outgoing => "Outgoing".into(), + }), + enr: value.enr().map(|x| x.to_base64()), + } + } +} + +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Client { + pub version: String, + pub os: String, + pub protocol: String, + pub agent: Option, +} + +impl From for Client { + fn from(value: network::Client) -> Self { + Self { + version: value.version, + os: value.os_version, + protocol: value.protocol_version, + agent: value.agent_string, + } + } +} + +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PeerConnectionStatus { + pub status: String, + pub connections_in: u8, + pub connections_out: u8, + pub last_seen_secs: u64, +} + +impl PeerConnectionStatus { + fn new(status: &str, n_in: u8, n_out: u8, last_seen: Option) -> Self { + Self { + status: status.into(), + connections_in: n_in, + connections_out: n_out, + last_seen_secs: last_seen.map_or(0, |x| x.elapsed().as_secs()), + } + } +} + +impl From for PeerConnectionStatus { + fn from(value: network::PeerConnectionStatus) -> Self { + match value { + network::PeerConnectionStatus::Connected { n_in, n_out } => { + Self::new("connected", n_in, n_out, None) + } + network::PeerConnectionStatus::Disconnecting { .. } => { + Self::new("disconnecting", 0, 0, None) + } + network::PeerConnectionStatus::Disconnected { since } => { + Self::new("disconnected", 0, 0, Some(since)) + } + network::PeerConnectionStatus::Banned { since } => { + Self::new("banned", 0, 0, Some(since)) + } + network::PeerConnectionStatus::Dialing { since } => { + Self::new("dialing", 0, 0, Some(since)) + } + network::PeerConnectionStatus::Unknown => Self::new("unknown", 0, 0, None), + } + } +} + mod base64 { use serde::{Deserialize, Deserializer, Serialize, Serializer};