use std::{collections::BTreeSet, net::SocketAddr};
use serde::{Deserialize, Serialize};
use crate::{EndpointId, PublicKey, RelayUrl};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct EndpointAddr {
pub id: EndpointId,
pub addrs: BTreeSet<TransportAddr>,
}
#[derive(
derive_more::Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash,
)]
#[non_exhaustive]
pub enum TransportAddr {
#[debug("Relay({_0})")]
Relay(RelayUrl),
Ip(SocketAddr),
}
impl TransportAddr {
pub fn is_relay(&self) -> bool {
matches!(self, Self::Relay(_))
}
pub fn is_ip(&self) -> bool {
matches!(self, Self::Ip(_))
}
}
impl EndpointAddr {
pub fn new(id: PublicKey) -> Self {
EndpointAddr {
id,
addrs: Default::default(),
}
}
pub fn from_parts(id: PublicKey, addrs: impl IntoIterator<Item = TransportAddr>) -> Self {
Self {
id,
addrs: addrs.into_iter().collect(),
}
}
pub fn with_relay_url(mut self, relay_url: RelayUrl) -> Self {
self.addrs.insert(TransportAddr::Relay(relay_url));
self
}
pub fn with_ip_addr(mut self, addr: SocketAddr) -> Self {
self.addrs.insert(TransportAddr::Ip(addr));
self
}
pub fn with_addrs(mut self, addrs: impl IntoIterator<Item = TransportAddr>) -> Self {
for addr in addrs.into_iter() {
self.addrs.insert(addr);
}
self
}
pub fn is_empty(&self) -> bool {
self.addrs.is_empty()
}
pub fn ip_addrs(&self) -> impl Iterator<Item = &SocketAddr> {
self.addrs.iter().filter_map(|addr| match addr {
TransportAddr::Ip(addr) => Some(addr),
_ => None,
})
}
pub fn relay_urls(&self) -> impl Iterator<Item = &RelayUrl> {
self.addrs.iter().filter_map(|addr| match addr {
TransportAddr::Relay(url) => Some(url),
_ => None,
})
}
}
impl From<EndpointId> for EndpointAddr {
fn from(endpoint_id: EndpointId) -> Self {
EndpointAddr::new(endpoint_id)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[non_exhaustive]
enum NewAddrType {
Relay(RelayUrl),
Ip(SocketAddr),
Cool(u16),
}
#[test]
fn test_roundtrip_new_addr_type() {
let old = vec![
TransportAddr::Ip("127.0.0.1:9".parse().unwrap()),
TransportAddr::Relay("https://example.com".parse().unwrap()),
];
let old_ser = postcard::to_stdvec(&old).unwrap();
let old_back: Vec<TransportAddr> = postcard::from_bytes(&old_ser).unwrap();
assert_eq!(old, old_back);
let new = vec![
NewAddrType::Ip("127.0.0.1:9".parse().unwrap()),
NewAddrType::Relay("https://example.com".parse().unwrap()),
NewAddrType::Cool(4),
];
let new_ser = postcard::to_stdvec(&new).unwrap();
let new_back: Vec<NewAddrType> = postcard::from_bytes(&new_ser).unwrap();
assert_eq!(new, new_back);
let old_new_back: Vec<NewAddrType> = postcard::from_bytes(&old_ser).unwrap();
assert_eq!(
old_new_back,
vec![
NewAddrType::Ip("127.0.0.1:9".parse().unwrap()),
NewAddrType::Relay("https://example.com".parse().unwrap()),
]
);
}
}