use anyhow::Result;
use cyphernet::addr::{HostName, PartialAddr, i2p::I2pAddr};
use std::{
net::{IpAddr, Ipv4Addr, Ipv6Addr},
str::FromStr,
};
pub type Peer = PartialAddr<HostName, 0>;
#[derive(Debug, Default)]
pub struct Buffer(pub Vec<Peer>);
impl Buffer {
pub fn from_peers6(ip_port_chunks: &[u8]) -> Result<Self> {
const L: usize = 18;
let mut b = Vec::with_capacity(ip_port_chunks.len() / L);
for chunk in ip_port_chunks.chunks_exact(L) {
let ip_bytes: [u8; 16] = chunk[0..16].try_into()?;
b.push(PartialAddr {
host: HostName::Ip(IpAddr::V6(Ipv6Addr::from(ip_bytes))),
port: Some(u16::from_be_bytes(chunk[16..L].try_into()?)),
})
}
Ok(Self(b))
}
pub fn from_peers(ip_port_chunks: &[u8]) -> Result<Self> {
const L: usize = 6;
let mut b = Vec::with_capacity(ip_port_chunks.len() / L);
for chunk in ip_port_chunks.chunks_exact(L) {
let ip_bytes: [u8; 4] = chunk[0..4].try_into()?;
b.push(PartialAddr {
host: HostName::Ip(IpAddr::V4(Ipv4Addr::from(ip_bytes))),
port: Some(u16::from_be_bytes(chunk[4..L].try_into()?)),
})
}
Ok(Self(b))
}
pub fn from_peers_i2p(host_chunks: &[u8]) -> Result<Self> {
const L: usize = 32;
let mut b = Vec::with_capacity(host_chunks.len() / L);
for chunk in host_chunks.chunks_exact(L) {
b.push(PartialAddr {
host: HostName::I2p(I2pAddr::from_str(&format!(
"{}.b32.i2p",
data_encoding::BASE32_NOPAD.encode(chunk)
))?),
port: None,
})
}
Ok(Self(b))
}
}