use std::net::SocketAddr;
use crate::error::{Error, ErrorKind};
use super::{Node, krpc, rpc::DhtRpc};
pub async fn find_node(
rpc: &DhtRpc, addr: SocketAddr, tid: krpc::TransactionId, node_id: &[u8; 20],
target: &[u8; 20], want: Option<&[&str]>,
) -> Result<Vec<Node>, Error> {
tracing::debug!("DHT find_node to {}", addr);
let data = krpc::build_find_node(tid, node_id, target, want);
let response = rpc.query(addr, tid, &data).await?;
match &response {
krpc::KrpcMessage::Response { result, .. } => {
let mut nodes = Vec::new();
if let Some(nodes_bytes) = krpc::dict_get_bytes(result, b"nodes") {
nodes.extend(krpc::parse_compact_nodes4(nodes_bytes));
}
if let Some(nodes6_bytes) = krpc::dict_get_bytes(result, b"nodes6") {
nodes.extend(krpc::parse_compact_nodes6(nodes6_bytes));
}
if nodes.is_empty() {
Err(Error::new(ErrorKind::Protocol))
} else {
Ok(nodes)
}
}
_ => Err(Error::new(ErrorKind::Protocol)),
}
}
pub async fn get_peers(
rpc: &DhtRpc, addr: SocketAddr, tid: krpc::TransactionId, node_id: &[u8; 20],
info_hash: &[u8; 20], want: Option<&[&str]>,
) -> Result<krpc::GetPeersResult, Error> {
tracing::debug!("DHT get_peers to {}", addr);
let data = krpc::build_get_peers(tid, node_id, info_hash, want);
let response = rpc.query(addr, tid, &data).await?;
krpc::parse_get_peers_response(&response)
}
pub async fn announce_peer(
rpc: &DhtRpc, addr: SocketAddr, tid: krpc::TransactionId, node_id: &[u8; 20],
info_hash: &[u8; 20], port: u16, token: &[u8],
) -> Result<(), Error> {
tracing::debug!("DHT announce_peer to {} (port {})", addr, port);
let data = krpc::build_announce_peer(tid, node_id, info_hash, port, token);
let response = rpc.query(addr, tid, &data).await?;
if matches!(&response, krpc::KrpcMessage::Error { .. }) {
return Err(Error::new(ErrorKind::Protocol));
}
Ok(())
}