use crate::{
libp2p::peer_id::{FromProtobufEncodingError, PublicKey},
util::protobuf,
};
use alloc::vec::{self, Vec};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IdentifyResponse<'a, TLaIter, TProtoIter> {
pub protocol_version: &'a str,
pub agent_version: &'a str,
pub ed25519_public_key: [u8; 32],
pub listen_addrs: TLaIter,
pub observed_addr: &'a [u8],
pub protocols: TProtoIter,
}
pub fn build_identify_response<'a>(
config: IdentifyResponse<
'a,
impl Iterator<Item = &'a [u8]> + 'a,
impl Iterator<Item = &'a str> + 'a,
>,
) -> impl Iterator<Item = impl AsRef<[u8]>> {
protobuf::string_tag_encode(5, config.protocol_version)
.map(either::Left)
.map(either::Left)
.map(either::Left)
.chain(
protobuf::string_tag_encode(6, config.agent_version)
.map(either::Right)
.map(either::Left)
.map(either::Left),
)
.chain(
protobuf::bytes_tag_encode(
1,
PublicKey::Ed25519(config.ed25519_public_key).to_protobuf_encoding(),
)
.map(either::Left)
.map(either::Right)
.map(either::Left),
)
.chain(
config
.listen_addrs
.flat_map(|addr| protobuf::bytes_tag_encode(2, addr))
.map(either::Right)
.map(either::Right)
.map(either::Left),
)
.chain(
protobuf::bytes_tag_encode(4, config.observed_addr)
.map(either::Left)
.map(either::Right),
)
.chain(
config
.protocols
.flat_map(|p| protobuf::string_tag_encode(3, p))
.map(either::Right)
.map(either::Right),
)
}
pub fn decode_identify_response(
response_bytes: &[u8],
) -> Result<
IdentifyResponse<'_, vec::IntoIter<&[u8]>, vec::IntoIter<&str>>,
DecodeIdentifyResponseError,
> {
let mut parser = nom::combinator::all_consuming::<_, nom::error::Error<&[u8]>, _>(
nom::combinator::complete(protobuf::message_decode! {
#[optional] protocol_version = 5 => protobuf::string_tag_decode,
#[optional] agent_version = 6 => protobuf::string_tag_decode,
#[optional] ed25519_public_key = 1 => protobuf::bytes_tag_decode,
#[repeated(max = 1024)] listen_addrs = 2 => protobuf::bytes_tag_decode,
#[optional] observed_addr = 4 => protobuf::bytes_tag_decode,
#[repeated(max = 1024)] protocols = 3 => protobuf::string_tag_decode,
}),
);
let decoded = match nom::Finish::finish(nom::Parser::parse(&mut parser, response_bytes)) {
Ok((_, out)) => out,
Err(_) => return Err(DecodeIdentifyResponseError::ProtobufDecode),
};
Ok(IdentifyResponse {
agent_version: decoded.agent_version.unwrap_or_default(),
protocol_version: decoded.protocol_version.unwrap_or_default(),
ed25519_public_key: match PublicKey::from_protobuf_encoding(
decoded.ed25519_public_key.unwrap_or_default(),
)
.map_err(DecodeIdentifyResponseError::InvalidPublicKey)?
{
PublicKey::Ed25519(key) => key,
},
listen_addrs: decoded.listen_addrs.into_iter(),
observed_addr: decoded.observed_addr.unwrap_or_default(),
protocols: decoded.protocols.into_iter(),
})
}
#[derive(Debug, derive_more::Display, derive_more::Error)]
pub enum DecodeIdentifyResponseError {
ProtobufDecode,
#[display("Failed to decode remote public key: {_0}")]
InvalidPublicKey(FromProtobufEncodingError),
}