jam_std_common/net/
mod.rs1mod peer_id;
2
3pub use peer_id::{ParseErr as PeerIdParseErr, PeerId};
4use scale::{Decode, Encode, MaxEncodedLen};
5use std::{net::SocketAddr, str::FromStr};
6
7#[derive(Clone, Copy, Encode, Decode, MaxEncodedLen, PartialEq, Eq)]
11pub struct PeerAddr {
12 pub ip: [u8; 16],
15 pub port: u16,
17}
18
19impl core::fmt::Debug for PeerAddr {
20 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
21 SocketAddr::from(*self).fmt(f)
22 }
23}
24
25impl core::fmt::Display for PeerAddr {
26 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
27 SocketAddr::from(*self).fmt(f)
28 }
29}
30
31impl TryFrom<&str> for PeerAddr {
32 type Error = std::net::AddrParseError;
33
34 fn try_from(s: &str) -> Result<Self, Self::Error> {
35 Ok(SocketAddr::from_str(s)?.into())
36 }
37}
38
39impl FromStr for PeerAddr {
40 type Err = std::net::AddrParseError;
41
42 fn from_str(s: &str) -> Result<Self, Self::Err> {
43 s.try_into()
44 }
45}
46
47impl From<SocketAddr> for PeerAddr {
48 fn from(addr: SocketAddr) -> Self {
49 let ip = match addr.ip() {
50 std::net::IpAddr::V4(ip) => ip.to_ipv6_mapped(),
51 std::net::IpAddr::V6(ip) => ip,
52 };
53 Self { ip: ip.octets(), port: addr.port() }
54 }
55}
56
57impl From<PeerAddr> for SocketAddr {
58 fn from(addr: PeerAddr) -> Self {
59 Self::new(std::net::Ipv6Addr::from(addr.ip).to_canonical(), addr.port)
60 }
61}
62
63#[derive(Clone, Encode, Decode, MaxEncodedLen, PartialEq, Eq)]
65pub struct PeerDetails {
66 pub id: PeerId,
67 pub addr: PeerAddr,
68}
69
70impl core::fmt::Debug for PeerDetails {
71 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
72 write!(f, "{:?}@{:?}", self.id, self.addr)
73 }
74}
75
76impl core::fmt::Display for PeerDetails {
77 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
78 write!(f, "{}@{}", self.id, self.addr)
79 }
80}
81
82#[derive(Debug, thiserror::Error)]
84pub enum PeerDetailsParseErr {
85 #[error("No @ character; expected between peer ID and address")]
86 NoSeparator,
87 #[error("Bad peer ID: {0}")]
88 Id(#[from] PeerIdParseErr),
89 #[error("Bad address: {0}")]
90 Addr(#[from] std::net::AddrParseError),
91}
92
93impl TryFrom<&str> for PeerDetails {
94 type Error = PeerDetailsParseErr;
95
96 fn try_from(s: &str) -> Result<Self, Self::Error> {
97 let Some((id, addr)) = s.split_once('@') else {
98 return Err(PeerDetailsParseErr::NoSeparator)
99 };
100 Ok(Self { id: id.try_into()?, addr: addr.try_into()? })
101 }
102}
103
104impl FromStr for PeerDetails {
105 type Err = PeerDetailsParseErr;
106
107 fn from_str(s: &str) -> Result<Self, Self::Err> {
108 s.try_into()
109 }
110}
111
112#[cfg(any(test, feature = "rand"))]
113impl rand::distr::Distribution<PeerAddr> for rand::distr::StandardUniform {
114 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> PeerAddr {
115 let ip = if rng.random() {
116 (rng.random::<u32>() as u128) | (0xffff << 32)
118 } else {
119 (rng.random::<u128>() & !(0x7 << 125)) | (1 << 125)
121 };
122 PeerAddr { ip: ip.to_be_bytes(), port: rng.random() }
123 }
124}
125
126#[cfg(any(test, feature = "rand"))]
127impl rand::distr::Distribution<PeerDetails> for rand::distr::StandardUniform {
128 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> PeerDetails {
129 PeerDetails { id: rng.random(), addr: rng.random() }
130 }
131}