1use std::fmt::Display;
4use std::net::SocketAddr;
5use std::str::FromStr;
6
7use anyhow::Context;
8use iroh::RelayUrl as IrohRelayUrl;
9use iroh::{NodeAddr as IrohNodeAddr, NodeId};
10use p2panda_core::PublicKey;
11use serde::{Deserialize, Serialize};
12
13use crate::to_public_key;
14
15pub const DEFAULT_STUN_PORT: u16 = 3478;
19
20#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
22pub struct RelayUrl(IrohRelayUrl);
23
24impl RelayUrl {
25 pub fn port(&self) -> Option<u16> {
26 self.0.port()
27 }
28}
29
30impl FromStr for RelayUrl {
31 type Err = anyhow::Error;
32
33 fn from_str(s: &str) -> Result<Self, Self::Err> {
34 let inner = IrohRelayUrl::from_str(s).context("invalid URL")?;
35 Ok(Self(inner))
36 }
37}
38
39impl Display for RelayUrl {
40 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41 f.write_str(&self.0.to_string())
42 }
43}
44
45impl From<RelayUrl> for IrohRelayUrl {
46 fn from(value: RelayUrl) -> Self {
47 value.0
48 }
49}
50
51pub(crate) fn to_relay_url(url: IrohRelayUrl) -> RelayUrl {
53 RelayUrl(url)
54}
55
56#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)]
58pub struct NodeAddress {
59 pub public_key: PublicKey,
60 pub direct_addresses: Vec<SocketAddr>,
61 pub relay_url: Option<RelayUrl>,
62}
63
64impl NodeAddress {
65 pub fn from_public_key(public_key: PublicKey) -> Self {
66 Self {
67 public_key,
68 direct_addresses: Vec::new(),
69 relay_url: None,
70 }
71 }
72}
73
74pub(crate) fn to_node_addr(addr: IrohNodeAddr) -> NodeAddress {
76 NodeAddress {
77 public_key: to_public_key(addr.node_id),
78 direct_addresses: addr
79 .direct_addresses
80 .iter()
81 .map(|addr| addr.to_owned())
82 .collect(),
83 relay_url: addr.relay_url.map(to_relay_url),
84 }
85}
86
87pub(crate) fn from_node_addr(addr: NodeAddress) -> IrohNodeAddr {
89 let node_id = NodeId::from_bytes(addr.public_key.as_bytes()).expect("invalid public key");
90 let mut node_addr =
91 IrohNodeAddr::new(node_id).with_direct_addresses(addr.direct_addresses.to_vec());
92 if let Some(url) = addr.relay_url {
93 node_addr = node_addr.with_relay_url(url.into());
94 }
95 node_addr
96}