use crate::{libp2p::peer_id, util::protobuf};
use alloc::vec::Vec;
pub fn build_find_node_request(peer_id: &[u8]) -> Vec<u8> {
let mut out = Vec::with_capacity(64 + peer_id.len());
for slice in protobuf::enum_tag_encode(1, 4) {
out.extend_from_slice(slice.as_ref());
}
for slice in protobuf::bytes_tag_encode(2, peer_id) {
out.extend_from_slice(slice.as_ref());
}
out
}
pub fn decode_find_node_response(
response_bytes: &[u8],
) -> Result<Vec<(peer_id::PeerId, Vec<Vec<u8>>)>, DecodeFindNodeResponseError> {
let mut parser = nom::combinator::all_consuming::<_, nom::error::Error<&[u8]>, _>(
nom::combinator::complete(protobuf::message_decode! {
#[optional] response_ty = 1 => protobuf::enum_tag_decode,
#[repeated(max = 1024)] peers = 8 => protobuf::message_tag_decode(protobuf::message_decode!{
#[required] peer_id = 1 => protobuf::bytes_tag_decode,
#[repeated(max = 1024)] addrs = 2 => protobuf::bytes_tag_decode,
}),
}),
);
let closer_peers = match nom::Finish::finish(nom::Parser::parse(&mut parser, response_bytes)) {
Ok((_, out)) if out.response_ty.unwrap_or(0) == 4 => out.peers,
Ok((_, _)) => return Err(DecodeFindNodeResponseError::BadResponseTy),
Err(_) => {
return Err(DecodeFindNodeResponseError::ProtobufDecode(
ProtobufDecodeError,
));
}
};
let mut result = Vec::with_capacity(closer_peers.len());
for peer in closer_peers {
let peer_id = peer_id::PeerId::from_bytes(peer.peer_id.to_vec())
.map_err(|(err, _)| DecodeFindNodeResponseError::BadPeerId(err))?;
let mut multiaddrs = Vec::with_capacity(peer.addrs.len());
for addr in peer.addrs {
multiaddrs.push(addr.to_vec());
}
result.push((peer_id, multiaddrs));
}
Ok(result)
}
#[derive(Debug, derive_more::Display, derive_more::Error)]
pub enum DecodeFindNodeResponseError {
#[display("Error decoding the response: {_0}")]
ProtobufDecode(ProtobufDecodeError),
BadResponseTy,
#[display("Invalid PeerId: {_0}")]
BadPeerId(peer_id::FromBytesError),
}
#[derive(Debug, derive_more::Display, derive_more::Error)]
pub struct ProtobufDecodeError;