From 55f140445da82a4bbe56bab4ecb71aa7010a9ea5 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Fri, 19 Apr 2019 20:32:40 -0700 Subject: [PATCH] tendermint-rs: /net_info RPC endpoint --- tendermint-rs/src/rpc/endpoint.rs | 2 + tendermint-rs/src/rpc/endpoint/net_info.rs | 189 ++++++++++++++++ tendermint-rs/src/rpc/endpoint/status.rs | 2 +- tendermint-rs/src/rpc/response.rs | 7 +- tendermint-rs/tests/rpc.rs | 19 +- tendermint-rs/tests/support/net_info.json | 238 +++++++++++++++++++++ 6 files changed, 450 insertions(+), 7 deletions(-) create mode 100644 tendermint-rs/src/rpc/endpoint/net_info.rs create mode 100644 tendermint-rs/tests/support/net_info.json diff --git a/tendermint-rs/src/rpc/endpoint.rs b/tendermint-rs/src/rpc/endpoint.rs index 79b9a79..69faec7 100644 --- a/tendermint-rs/src/rpc/endpoint.rs +++ b/tendermint-rs/src/rpc/endpoint.rs @@ -1,5 +1,7 @@ //! Tendermint JSONRPC endpoints +mod net_info; mod status; +pub use net_info::{NetInfoRequest, NetInfoResponse}; pub use status::{StatusRequest, StatusResponse}; diff --git a/tendermint-rs/src/rpc/endpoint/net_info.rs b/tendermint-rs/src/rpc/endpoint/net_info.rs new file mode 100644 index 0000000..6ea75ad --- /dev/null +++ b/tendermint-rs/src/rpc/endpoint/net_info.rs @@ -0,0 +1,189 @@ +//! RPC wrapper for `/net_info` endpoint + +use crate::{channel::Channel, node, rpc, Timestamp}; +use serde::{Deserialize, Serialize}; +use std::{ + fmt::{self, Display}, + net::IpAddr, + time::Duration, +}; + +/// Request the status of the node +#[derive(Debug, Default)] +pub struct NetInfoRequest; + +impl rpc::Request for NetInfoRequest { + type Response = NetInfoResponse; + + fn path(&self) -> rpc::request::Path { + "/net_info".parse().unwrap() + } +} + +/// Status responses +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct NetInfoResponse { + /// Are we presently listening? + pub listening: bool, + + /// Active listeners + pub listeners: Vec, + + /// Number of connected peers + #[serde( + serialize_with = "rpc::response::serialize_u64", + deserialize_with = "rpc::response::parse_u64" + )] + pub n_peers: u64, + + /// Peer information + pub peers: Vec, +} + +impl rpc::Response for NetInfoResponse {} + +/// Listener information +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct Listener(String); + +impl Display for Listener { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +/// Peer information +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct PeerInfo { + /// Node information + pub node_info: node::Info, + + /// Is this an outbound connection? + pub is_outbound: bool, + + /// Connection status + pub connection_status: ConnectionStatus, + + /// Remote IP address + pub remote_ip: IpAddr, +} + +/// Connection status information +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct ConnectionStatus { + /// Duration of this connection + #[serde( + rename = "Duration", + serialize_with = "rpc::response::serialize_duration", + deserialize_with = "rpc::response::parse_duration" + )] + pub duration: Duration, + + /// Send monitor + #[serde(rename = "SendMonitor")] + pub send_monitor: Monitor, + + /// Receive monitor + #[serde(rename = "RecvMonitor")] + pub recv_monitor: Monitor, + + /// Channels + #[serde(rename = "Channels")] + pub channels: Vec, +} + +/// Monitor +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct Monitor { + /// Is this monitor active? + #[serde(rename = "Active")] + pub active: bool, + + /// When the monitor started + #[serde(rename = "Start")] + pub start: Timestamp, + + /// Duration of this monitor + #[serde( + rename = "Duration", + serialize_with = "rpc::response::serialize_duration", + deserialize_with = "rpc::response::parse_duration" + )] + pub duration: Duration, + + /// Idle duration for this monitor + #[serde( + rename = "Idle", + serialize_with = "rpc::response::serialize_duration", + deserialize_with = "rpc::response::parse_duration" + )] + pub idle: Duration, + + /// Bytes + #[serde( + rename = "Bytes", + serialize_with = "rpc::response::serialize_u64", + deserialize_with = "rpc::response::parse_u64" + )] + bytes: u64, + + /// Samples + #[serde( + rename = "Samples", + serialize_with = "rpc::response::serialize_u64", + deserialize_with = "rpc::response::parse_u64" + )] + samples: u64, + + /// Instant rate + #[serde( + rename = "InstRate", + serialize_with = "rpc::response::serialize_u64", + deserialize_with = "rpc::response::parse_u64" + )] + inst_rate: u64, + + /// Current rate + #[serde( + rename = "CurRate", + serialize_with = "rpc::response::serialize_u64", + deserialize_with = "rpc::response::parse_u64" + )] + cur_rate: u64, + + /// Average rate + #[serde( + rename = "AvgRate", + serialize_with = "rpc::response::serialize_u64", + deserialize_with = "rpc::response::parse_u64" + )] + avg_rate: u64, + + /// Peak rate + #[serde( + rename = "PeakRate", + serialize_with = "rpc::response::serialize_u64", + deserialize_with = "rpc::response::parse_u64" + )] + peak_rate: u64, + + /// Bytes remaining + #[serde( + rename = "BytesRem", + serialize_with = "rpc::response::serialize_u64", + deserialize_with = "rpc::response::parse_u64" + )] + bytes_rem: u64, + + /// Time remaining + #[serde( + rename = "TimeRem", + serialize_with = "rpc::response::serialize_u64", + deserialize_with = "rpc::response::parse_u64" + )] + time_rem: u64, + + /// Progress + #[serde(rename = "Progress")] + progress: u64, +} diff --git a/tendermint-rs/src/rpc/endpoint/status.rs b/tendermint-rs/src/rpc/endpoint/status.rs index ffefe34..b16d914 100644 --- a/tendermint-rs/src/rpc/endpoint/status.rs +++ b/tendermint-rs/src/rpc/endpoint/status.rs @@ -4,7 +4,7 @@ use crate::{account, block, node, rpc, Hash, PublicKey, Timestamp}; use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize, Serializer}; /// Node status request -#[derive(Default)] +#[derive(Debug, Default)] pub struct StatusRequest; impl rpc::Request for StatusRequest { diff --git a/tendermint-rs/src/rpc/response.rs b/tendermint-rs/src/rpc/response.rs index 1f40a98..21532c9 100644 --- a/tendermint-rs/src/rpc/response.rs +++ b/tendermint-rs/src/rpc/response.rs @@ -1,8 +1,5 @@ //! JSONRPC response types -// TODO(tarcieri): remove this when functions below are all used -#![allow(dead_code)] - use failure::{format_err, Error}; use serde::{ de::{DeserializeOwned, Error as DeError}, @@ -78,7 +75,7 @@ where } /// Parse `Duration` from a JSON string containing a nanosecond count -fn parse_duration<'de, D>(deserializer: D) -> Result +pub(crate) fn parse_duration<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { @@ -91,7 +88,7 @@ where } /// Serialize `Duration` as a JSON string containing a nanosecond count -fn serialize_duration(duration: &Duration, serializer: S) -> Result +pub(crate) fn serialize_duration(duration: &Duration, serializer: S) -> Result where S: Serializer, { diff --git a/tendermint-rs/tests/rpc.rs b/tendermint-rs/tests/rpc.rs index 91c6817..fe0e4f1 100644 --- a/tendermint-rs/tests/rpc.rs +++ b/tendermint-rs/tests/rpc.rs @@ -3,13 +3,30 @@ #[cfg(feature = "rpc")] mod endpoints { use std::{fs, path::PathBuf}; - use tendermint::rpc::{endpoint::StatusResponse, Response}; + use tendermint::rpc::{ + endpoint::{NetInfoResponse, StatusResponse}, + Response, + }; fn read_json_fixture(name: &str) -> String { fs::read_to_string(PathBuf::from("./tests/support/").join(name.to_owned() + ".json")) .unwrap() } + #[test] + fn net_info() { + let net_info_json = read_json_fixture("net_info"); + let net_info_response = NetInfoResponse::from_json(&net_info_json).unwrap(); + + println!("net_info_response: {:?}", net_info_response); + + assert_eq!(net_info_response.n_peers, 2); + assert_eq!( + net_info_response.peers[0].node_info.network.as_str(), + "cosmoshub-1" + ); + } + #[test] fn status() { let status_json = read_json_fixture("status"); diff --git a/tendermint-rs/tests/support/net_info.json b/tendermint-rs/tests/support/net_info.json new file mode 100644 index 0000000..6d36723 --- /dev/null +++ b/tendermint-rs/tests/support/net_info.json @@ -0,0 +1,238 @@ +{ + "jsonrpc": "2.0", + "id": "", + "result": { + "listening": true, + "listeners": [ + "Listener(@)" + ], + "n_peers": "2", + "peers": [ + { + "node_info": { + "protocol_version": { + "p2p": "7", + "block": "10", + "app": "0" + }, + "id": "9d55f7d40ba4925cca86e3880bc287f30451230e", + "listen_addr": "tcp://11.22.33.44:26656", + "network": "cosmoshub-1", + "version": "0.30.1", + "channels": "4020212223303800", + "moniker": "shredder", + "other": { + "tx_index": "on", + "rpc_address": "tcp://0.0.0.0:26657" + } + }, + "is_outbound": true, + "connection_status": { + "Duration": "3350648332604", + "SendMonitor": { + "Active": true, + "Start": "2019-04-19T12:57:18.04Z", + "Duration": "3350640000000", + "Idle": "3350640000000", + "Bytes": "19", + "Samples": "1", + "InstRate": "0", + "CurRate": "0", + "AvgRate": "0", + "PeakRate": "0", + "BytesRem": "0", + "TimeRem": "0", + "Progress": 0 + }, + "RecvMonitor": { + "Active": true, + "Start": "2019-04-19T12:57:18.04Z", + "Duration": "3350640000000", + "Idle": "3350640000000", + "Bytes": "0", + "Samples": "1", + "InstRate": "0", + "CurRate": "0", + "AvgRate": "0", + "PeakRate": "0", + "BytesRem": "0", + "TimeRem": "0", + "Progress": 0 + }, + "Channels": [ + { + "ID": 48, + "SendQueueCapacity": "1", + "SendQueueSize": "0", + "Priority": "5", + "RecentlySent": "0" + }, + { + "ID": 64, + "SendQueueCapacity": "1000", + "SendQueueSize": "0", + "Priority": "10", + "RecentlySent": "19" + }, + { + "ID": 32, + "SendQueueCapacity": "100", + "SendQueueSize": "0", + "Priority": "5", + "RecentlySent": "0" + }, + { + "ID": 33, + "SendQueueCapacity": "100", + "SendQueueSize": "0", + "Priority": "10", + "RecentlySent": "0" + }, + { + "ID": 34, + "SendQueueCapacity": "100", + "SendQueueSize": "0", + "Priority": "5", + "RecentlySent": "0" + }, + { + "ID": 35, + "SendQueueCapacity": "2", + "SendQueueSize": "0", + "Priority": "1", + "RecentlySent": "0" + }, + { + "ID": 56, + "SendQueueCapacity": "1", + "SendQueueSize": "0", + "Priority": "5", + "RecentlySent": "0" + }, + { + "ID": 0, + "SendQueueCapacity": "10", + "SendQueueSize": "0", + "Priority": "1", + "RecentlySent": "0" + } + ] + }, + "remote_ip": "11.22.33.44" + }, + { + "node_info": { + "protocol_version": { + "p2p": "7", + "block": "10", + "app": "0" + }, + "id": "a5ceaad3a1907665b2514db4e741939f0a5ab7dd", + "listen_addr": "tcp://0.0.0.0:26656", + "network": "cosmoshub-1", + "version": "0.30.1", + "channels": "4020212223303800", + "moniker": "kraang", + "other": { + "tx_index": "on", + "rpc_address": "tcp://0.0.0.0:26657" + } + }, + "is_outbound": true, + "connection_status": { + "Duration": "20412582851", + "SendMonitor": { + "Active": true, + "Start": "2019-04-19T13:52:48.28Z", + "Duration": "20400000000", + "Idle": "3100000000", + "Bytes": "209809", + "Samples": "56", + "InstRate": "0", + "CurRate": "1505", + "AvgRate": "10285", + "PeakRate": "210610", + "BytesRem": "0", + "TimeRem": "0", + "Progress": 0 + }, + "RecvMonitor": { + "Active": true, + "Start": "2019-04-19T13:52:48.28Z", + "Duration": "20400000000", + "Idle": "2920000000", + "Bytes": "222732", + "Samples": "53", + "InstRate": "0", + "CurRate": "1823", + "AvgRate": "10918", + "PeakRate": "106300", + "BytesRem": "0", + "TimeRem": "0", + "Progress": 0 + }, + "Channels": [ + { + "ID": 48, + "SendQueueCapacity": "1", + "SendQueueSize": "0", + "Priority": "5", + "RecentlySent": "0" + }, + { + "ID": 64, + "SendQueueCapacity": "1000", + "SendQueueSize": "0", + "Priority": "10", + "RecentlySent": "0" + }, + { + "ID": 32, + "SendQueueCapacity": "100", + "SendQueueSize": "0", + "Priority": "5", + "RecentlySent": "4804" + }, + { + "ID": 33, + "SendQueueCapacity": "100", + "SendQueueSize": "0", + "Priority": "10", + "RecentlySent": "17208" + }, + { + "ID": 34, + "SendQueueCapacity": "100", + "SendQueueSize": "0", + "Priority": "5", + "RecentlySent": "43624" + }, + { + "ID": 35, + "SendQueueCapacity": "2", + "SendQueueSize": "0", + "Priority": "1", + "RecentlySent": "36" + }, + { + "ID": 56, + "SendQueueCapacity": "1", + "SendQueueSize": "0", + "Priority": "5", + "RecentlySent": "0" + }, + { + "ID": 0, + "SendQueueCapacity": "10", + "SendQueueSize": "0", + "Priority": "1", + "RecentlySent": "0" + } + ] + }, + "remote_ip": "77.66.55.44" + } + ] + } +} +