diff --git a/api/Cargo.toml b/api/Cargo.toml index ec834e38c..6a576bd9a 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -10,6 +10,7 @@ grin_chain = { path = "../chain" } grin_pool = { path = "../pool" } grin_store = { path = "../store" } grin_util = { path = "../util" } +grin_p2p = { path = "../p2p" } hyper = "~0.10.6" slog = { version = "^2.0.12", features = ["max_level_trace", "release_max_level_trace"] } iron = "~0.5.1" diff --git a/api/src/handlers.rs b/api/src/handlers.rs index f077c38b2..3754894ae 100644 --- a/api/src/handlers.rs +++ b/api/src/handlers.rs @@ -27,6 +27,7 @@ use chain; use core::core::Transaction; use core::ser; use pool; +use p2p; use rest::*; use util::secp::pedersen::Commitment; use types::*; @@ -146,6 +147,32 @@ impl Handler for SumTreeHandler { } } +pub struct PeersAllHandler { + pub peer_store: Arc<p2p::PeerStore>, +} + +impl Handler for PeersAllHandler { + fn handle(&self, _req: &mut Request) -> IronResult<Response> { + let peers = &self.peer_store.all_peers(); + json_response(&peers) + } +} + +pub struct PeersConnectedHandler { + pub p2p_server: Arc<p2p::Server>, +} + +impl Handler for PeersConnectedHandler { + fn handle(&self, _req: &mut Request) -> IronResult<Response> { + let mut peers = vec![]; + for p in &self.p2p_server.all_peers() { + let peer_info = p.info.clone(); + peers.push(peer_info); + } + json_response(&peers) + } +} + // Chain handler. Get the head details. // GET /v1/chain pub struct ChainHandler { @@ -251,6 +278,8 @@ pub fn start_rest_apis<T>( addr: String, chain: Arc<chain::Chain>, tx_pool: Arc<RwLock<pool::TransactionPool<T>>>, + p2p_server: Arc<p2p::Server>, + peer_store: Arc<p2p::PeerStore>, ) where T: pool::BlockChain + Send + Sync + 'static, { @@ -271,13 +300,21 @@ pub fn start_rest_apis<T>( let pool_push_handler = PoolPushHandler { tx_pool: tx_pool.clone(), }; + let peers_all_handler = PeersAllHandler { + peer_store: peer_store.clone(), + }; + let peers_connected_handler = PeersConnectedHandler { + p2p_server: p2p_server.clone(), + }; let router = router!( chain_tip: get "/chain" => chain_tip_handler, chain_utxos: get "/chain/utxos" => utxo_handler, sumtree_roots: get "/sumtrees/*" => sumtree_handler, - pool_info: get "/pool" => pool_info_handler, - pool_push: post "/pool/push" => pool_push_handler, + pool_info: get "/pool" => pool_info_handler, + pool_push: post "/pool/push" => pool_push_handler, + peers_all: get "/peers/all" => peers_all_handler, + peers_connected: get "/peers/connected" => peers_connected_handler, ); let mut apis = ApiServer::new("/v1".to_string()); diff --git a/api/src/lib.rs b/api/src/lib.rs index 4afd613b9..fbf0c13f7 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -15,6 +15,7 @@ extern crate grin_chain as chain; extern crate grin_core as core; extern crate grin_pool as pool; +extern crate grin_p2p as p2p; extern crate grin_store as store; extern crate grin_util as util; diff --git a/grin/src/server.rs b/grin/src/server.rs index a32f842ae..d73b86102 100644 --- a/grin/src/server.rs +++ b/grin/src/server.rs @@ -150,6 +150,8 @@ impl Server { config.api_http_addr.clone(), shared_chain.clone(), tx_pool.clone(), + p2p_server.clone(), + peer_store.clone(), ); warn!(LOGGER, "Grin server started."); diff --git a/p2p/src/server.rs b/p2p/src/server.rs index 1667a50d1..2023c9b31 100644 --- a/p2p/src/server.rs +++ b/p2p/src/server.rs @@ -207,6 +207,10 @@ impl Server { addr.ip() == self.config.host && addr.port() == self.config.port } + pub fn all_peers(&self) -> Vec<Arc<Peer>> { + self.peers.read().unwrap().clone() + } + /// Get a peer we're connected to by address. pub fn get_peer(&self, addr: SocketAddr) -> Option<Arc<Peer>> { for p in self.peers.read().unwrap().deref() { diff --git a/p2p/src/store.rs b/p2p/src/store.rs index bc7f64722..91d77e08a 100644 --- a/p2p/src/store.rs +++ b/p2p/src/store.rs @@ -28,16 +28,16 @@ const PEER_PREFIX: u8 = 'p' as u8; /// Types of messages enum_from_primitive! { - #[derive(Debug, Clone, Copy, PartialEq)] - pub enum State { - Healthy, - Banned, - Defunct, - } + #[derive(Debug, Clone, Copy, PartialEq, Serialize)] + pub enum State { + Healthy, + Banned, + Defunct, + } } /// Data stored for any given peer we've encountered. -#[derive(Debug)] +#[derive(Debug, Serialize)] pub struct PeerData { /// Network address of the peer. pub addr: SocketAddr, @@ -129,6 +129,17 @@ impl PeerStore { peers } + /// List all known peers (for the /v1/peers api endpoint) + pub fn all_peers(&self) -> Vec<PeerData> { + let peers_iter = self.db + .iter::<PeerData>(&to_key(PEER_PREFIX, &mut "".to_string().into_bytes())); + let mut peers = vec![]; + for p in peers_iter { + peers.push(p); + } + peers + } + /// Convenience method to load a peer data, update its status and save it /// back. pub fn update_state(&self, peer_addr: SocketAddr, new_state: State) -> Result<(), Error> { diff --git a/p2p/src/types.rs b/p2p/src/types.rs index 7c7942088..8dc5276e8 100644 --- a/p2p/src/types.rs +++ b/p2p/src/types.rs @@ -100,7 +100,7 @@ bitflags! { } /// General information about a connected peer that's useful to other modules. -#[derive(Debug)] +#[derive(Clone, Debug, Serialize)] pub struct PeerInfo { pub capabilities: Capabilities, pub user_agent: String,