use super::utils::w;
use crate::p2p::types::{PeerAddr, PeerInfoDisplay, ReasonForBan};
use crate::p2p::{self, PeerData};
use crate::rest::*;
use crate::router::{Handler, ResponseFuture};
use crate::web::*;
use hyper::{Body, Request, StatusCode};
use mwc_p2p::types::Direction;
use mwc_p2p::types::PeerInfoDisplayLegacy;
use mwc_p2p::Capabilities;
use std::net::SocketAddr;
use std::sync::Weak;
pub struct PeersAllHandler {
pub peers: Weak<p2p::Peers>,
}
impl Handler for PeersAllHandler {
fn get(&self, _req: Request<Body>) -> ResponseFuture {
let peers = &w_fut!(&self.peers).all_peer_data(Capabilities::UNKNOWN);
json_response_pretty(&peers)
}
}
pub struct PeersConnectedHandler {
pub peers: Weak<p2p::Peers>,
}
impl PeersConnectedHandler {
pub fn get_connected_peers(&self) -> Result<Vec<PeerInfoDisplayLegacy>, Error> {
let peers = w(&self.peers)?
.iter()
.connected()
.into_iter()
.map(|p| p.info.clone().into())
.collect::<Vec<PeerInfoDisplay>>();
let mut peers_ret: Vec<PeerInfoDisplayLegacy> = Vec::new();
for peer in peers {
let peer_addr_str = match peer.addr {
PeerAddr::Onion(_) => format!("127.0.0.1:{}", 3414),
PeerAddr::Ip(ip) => format!("{}:{}", ip.ip(), ip.port()),
};
let peer_direction = if peer.direction == Direction::OutboundTor {
Direction::Outbound
} else if peer.direction == Direction::InboundTor {
Direction::Inbound
} else {
peer.direction
};
let peer_display = PeerInfoDisplayLegacy {
capabilities: peer.capabilities,
user_agent: peer.user_agent,
version: peer.version,
addr: peer_addr_str,
direction: peer_direction,
total_difficulty: peer.total_difficulty,
height: peer.height,
};
peers_ret.push(peer_display);
}
Ok(peers_ret)
}
}
impl Handler for PeersConnectedHandler {
fn get(&self, _req: Request<Body>) -> ResponseFuture {
let peers: Vec<PeerInfoDisplay> = w_fut!(&self.peers)
.iter()
.connected()
.into_iter()
.map(|p| p.info.clone().into())
.collect();
let mut peers_ret: Vec<PeerInfoDisplayLegacy> = Vec::new();
for peer in peers.clone() {
let peer_addr_str = match peer.addr {
PeerAddr::Onion(_) => format!("127.0.0.1:{}", 3414),
PeerAddr::Ip(ip) => format!("{}:{}", ip.ip(), ip.port()),
};
let peer_direction = if peer.direction == Direction::OutboundTor {
Direction::Outbound
} else if peer.direction == Direction::InboundTor {
Direction::Inbound
} else {
peer.direction
};
let peer_display = PeerInfoDisplayLegacy {
capabilities: peer.capabilities,
user_agent: peer.user_agent,
version: peer.version,
addr: peer_addr_str,
direction: peer_direction,
total_difficulty: peer.total_difficulty,
height: peer.height,
};
peers_ret.push(peer_display);
}
json_response(&peers_ret)
}
}
pub struct PeerHandler {
pub peers: Weak<p2p::Peers>,
}
impl PeerHandler {
pub fn get_peers(&self, addr: Option<SocketAddr>) -> Result<Vec<PeerData>, Error> {
if let Some(addr) = addr {
let peer_addr = PeerAddr::Ip(addr);
let peer_data: PeerData = w(&self.peers)?.get_peer(&peer_addr).map_err(|e| {
Error::Internal(format!(
"Unable to get peer for address {}, {}",
peer_addr, e
))
})?;
return Ok(vec![peer_data]);
}
let peers = w(&self.peers)?.all_peer_data(Capabilities::UNKNOWN);
Ok(peers)
}
pub fn ban_peer(&self, addr: SocketAddr) -> Result<(), Error> {
let peer_addr = PeerAddr::Ip(addr);
w(&self.peers)?
.ban_peer(&peer_addr, ReasonForBan::ManualBan, "banned from api")
.map_err(|e| {
Error::Internal(format!(
"Unable to ban peer for address {}, {}",
peer_addr, e
))
})
}
pub fn unban_peer(&self, addr: SocketAddr) -> Result<(), Error> {
let peer_addr = PeerAddr::Ip(addr);
w(&self.peers)?.unban_peer(&peer_addr).map_err(|e| {
Error::Internal(format!(
"Unable to unban peer for address {}, {}",
peer_addr, e
))
})
}
}
impl Handler for PeerHandler {
fn get(&self, req: Request<Body>) -> ResponseFuture {
#![allow(irrefutable_let_patterns)]
let command = right_path_element!(req);
let peer_addr;
if let Ok(ip_addr) = command.parse() {
peer_addr = PeerAddr::from_ip(ip_addr);
} else if let Ok(addr) = command.parse() {
peer_addr = PeerAddr::Ip(addr);
} else if let Ok(onion) = command.parse() {
peer_addr = PeerAddr::Onion(onion);
} else {
return response(
StatusCode::BAD_REQUEST,
format!("peer address unrecognized: {}", req.uri().path()),
);
}
match w_fut!(&self.peers).get_peer(&peer_addr) {
Ok(peer) => json_response(&peer),
Err(_) => response(
StatusCode::NOT_FOUND,
format!("peer {} not found", peer_addr),
),
}
}
fn post(&self, req: Request<Body>) -> ResponseFuture {
#![allow(irrefutable_let_patterns)]
let mut path_elems = req.uri().path().trim_end_matches('/').rsplit('/');
let command = match path_elems.next() {
None => return response(StatusCode::BAD_REQUEST, "invalid url"),
Some(c) => c,
};
let addr = match path_elems.next() {
None => return response(StatusCode::BAD_REQUEST, "invalid url"),
Some(a) => {
if let Ok(ip_addr) = a.parse() {
PeerAddr::from_ip(ip_addr)
} else if let Ok(addr) = a.parse() {
PeerAddr::Ip(addr)
} else if let Ok(addr) = a.parse() {
PeerAddr::Onion(addr)
} else {
return response(
StatusCode::BAD_REQUEST,
format!("invalid peer address: {}", req.uri().path()),
);
}
}
};
match command {
"ban" => match w_fut!(&self.peers).ban_peer(
&addr,
ReasonForBan::ManualBan,
"banned from CLI",
) {
Ok(_) => response(StatusCode::OK, "{}"),
Err(e) => response(
StatusCode::INTERNAL_SERVER_ERROR,
format!("ban for peer {} failed, {:?}", addr, e),
),
},
"unban" => match w_fut!(&self.peers).unban_peer(&addr) {
Ok(_) => response(StatusCode::OK, "{}"),
Err(e) => response(
StatusCode::INTERNAL_SERVER_ERROR,
format!("unban for peer {} failed, {:?}", addr, e),
),
},
_ => response(
StatusCode::BAD_REQUEST,
format!("invalid command {}", command),
),
}
}
}