Live video on the AT Protocol
1use iroh_base::ticket::NodeTicket;
2use std::{str::FromStr, sync::Arc};
3
4use crate::public_key::PublicKey;
5
6/// A peer and it's addressing information.
7#[derive(Debug, Clone, PartialEq, Eq, uniffi::Object)]
8pub struct NodeAddr {
9 node_id: Arc<PublicKey>,
10 relay_url: Option<String>,
11 addresses: Vec<String>,
12}
13
14#[uniffi::export]
15impl NodeAddr {
16 /// Create a new [`NodeAddr`] with empty [`AddrInfo`].
17 #[uniffi::constructor]
18 pub fn new(node_id: &PublicKey, derp_url: Option<String>, addresses: Vec<String>) -> Self {
19 Self {
20 node_id: Arc::new(node_id.clone()),
21 relay_url: derp_url,
22 addresses,
23 }
24 }
25
26 pub fn node_id(&self) -> PublicKey {
27 self.node_id.as_ref().clone()
28 }
29
30 /// Get the direct addresses of this peer.
31 pub fn direct_addresses(&self) -> Vec<String> {
32 self.addresses.clone()
33 }
34
35 /// Get the home relay URL for this peer
36 pub fn relay_url(&self) -> Option<String> {
37 self.relay_url.clone()
38 }
39
40 /// Returns true if both NodeAddr's have the same values
41 pub fn equal(&self, other: &NodeAddr) -> bool {
42 self == other
43 }
44}
45
46/// Error when converting from ffi NodeAddr to iroh::NodeAddr
47#[derive(Debug, snafu::Snafu, uniffi::Error)]
48#[uniffi(flat_error)]
49#[snafu(visibility(pub(crate)))]
50pub enum NodeAddrError {
51 #[snafu(display("Invalid URL"), context(false))]
52 InvalidUrl { source: url::ParseError },
53 #[snafu(display("Invalid network address"), context(false))]
54 InvalidNetworkAddress { source: std::net::AddrParseError },
55}
56
57impl TryFrom<NodeAddr> for iroh::NodeAddr {
58 type Error = NodeAddrError;
59
60 fn try_from(value: NodeAddr) -> Result<Self, Self::Error> {
61 let mut node_addr = iroh::NodeAddr::new((&*value.node_id).into());
62 let addresses = value
63 .direct_addresses()
64 .into_iter()
65 .map(|addr| std::net::SocketAddr::from_str(&addr))
66 .collect::<Result<Vec<_>, _>>()?;
67
68 if let Some(derp_url) = value.relay_url() {
69 let url = url::Url::parse(&derp_url)?;
70
71 node_addr = node_addr.with_relay_url(url.into());
72 }
73 node_addr = node_addr.with_direct_addresses(addresses);
74 Ok(node_addr)
75 }
76}
77
78impl From<iroh::NodeAddr> for NodeAddr {
79 fn from(value: iroh::NodeAddr) -> Self {
80 NodeAddr {
81 node_id: Arc::new(value.node_id.into()),
82 relay_url: value.relay_url.map(|url| url.to_string()),
83 addresses: value
84 .direct_addresses
85 .into_iter()
86 .map(|d| d.to_string())
87 .collect(),
88 }
89 }
90}
91
92/// Error when converting from ffi NodeAddr to iroh::NodeAddr
93#[derive(Debug, snafu::Snafu, uniffi::Error)]
94#[uniffi(flat_error)]
95pub enum TicketError {
96 ParseError { message: String },
97}
98
99/// Get this node's ticket.
100#[uniffi::export]
101pub fn node_id_from_ticket(
102 ticket_str: String,
103) -> Result<Arc<crate::public_key::PublicKey>, TicketError> {
104 let ticket = NodeTicket::from_str(&ticket_str).map_err(|e| TicketError::ParseError {
105 message: e.to_string(),
106 })?;
107 let node_addr = ticket.node_addr();
108 Ok(Arc::new(node_addr.node_id.into()))
109}