p2panda_net/
addrs.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3use 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
15/// Default STUN port used by the relay server.
16///
17/// The STUN port as defined by [RFC 8489](<https://www.rfc-editor.org/rfc/rfc8489#section-18.6>)
18pub const DEFAULT_STUN_PORT: u16 = 3478;
19
20/// URL identifying a relay server.
21#[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
51/// Converts a `iroh` relay url type to the `p2panda-net` implementation.
52pub(crate) fn to_relay_url(url: IrohRelayUrl) -> RelayUrl {
53    RelayUrl(url)
54}
55
56/// Node address including public key, socket address(es) and an optional relay URL.
57#[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
74/// Converts an `iroh` node address type to the `p2panda-net` implementation.
75pub(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
87/// Converts a `p2panda-net` node address type to the `iroh` implementation.
88pub(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}