clone

a self-hosted sync node for lofi apps: jazz sync over iroh, ticket-gated, with no static ip or cloud needed

feat/browser-cors-sync-tickets
lofi-node / native / iroh-js / src / net.rs
net.rs 3.1K
1use std::{collections::BTreeSet, net::SocketAddr, str::FromStr};23use iroh_base::{RelayUrl, TransportAddr};4use napi_derive::napi;56use crate::EndpointId;78/// An endpoint's id together with the network-level addresses where it can be9/// reached. Mirrors the uniffi `EndpointAddr` object surface.10#[derive(Debug, Clone, PartialEq, Eq)]11#[napi]12pub struct EndpointAddr {13 pub(crate) id: [u8; 32],14 pub(crate) relay_url: Option<String>,15 pub(crate) addresses: Vec<String>,16}1718#[napi]19impl EndpointAddr {20 /// Create a new [`EndpointAddr`].21 #[napi(constructor)]22 pub fn new(id: &EndpointId, relay_url: Option<String>, addresses: Option<Vec<String>>) -> Self {23 Self {24 id: id.raw_bytes(),25 relay_url,26 addresses: addresses.unwrap_or_default(),27 }28 }2930 /// The endpoint id.31 #[napi]32 pub fn id(&self) -> EndpointId {33 EndpointId::from_raw_bytes(self.id)34 }3536 /// The direct (ip:port) addresses of this peer.37 #[napi]38 pub fn direct_addresses(&self) -> Vec<String> {39 self.addresses.clone()40 }4142 /// The home relay URL for this peer, if known.43 #[napi]44 pub fn relay_url(&self) -> Option<String> {45 self.relay_url.clone()46 }4748 /// Returns true if both [`EndpointAddr`]s have the same values.49 #[napi]50 pub fn equal(&self, other: &EndpointAddr) -> bool {51 self == other52 }5354 /// Clean string representation.55 #[napi]56 pub fn to_string(&self) -> String {57 let id = iroh::EndpointId::from_bytes(&self.id)58 .map(|i| i.to_string())59 .unwrap_or_else(|_| "<invalid>".to_string());60 let mut s = id;61 if let Some(relay) = &self.relay_url {62 s.push_str(&format!(" relay={relay}"));63 }64 if !self.addresses.is_empty() {65 s.push_str(&format!(" addrs=[{}]", self.addresses.join(", ")));66 }67 s68 }69}7071impl TryFrom<&EndpointAddr> for iroh::EndpointAddr {72 type Error = anyhow::Error;7374 fn try_from(value: &EndpointAddr) -> anyhow::Result<Self> {75 let id = iroh::EndpointId::from_bytes(&value.id)?;76 let mut addrs: BTreeSet<TransportAddr> = BTreeSet::new();77 for addr in &value.addresses {78 let socket = SocketAddr::from_str(addr)?;79 addrs.insert(TransportAddr::Ip(socket));80 }81 if let Some(relay) = &value.relay_url {82 let url = RelayUrl::from_str(relay)?;83 addrs.insert(TransportAddr::Relay(url));84 }85 Ok(iroh::EndpointAddr { id, addrs })86 }87}8889impl From<iroh::EndpointAddr> for EndpointAddr {90 fn from(value: iroh::EndpointAddr) -> Self {91 let mut relay_url = None;92 let mut addresses = Vec::new();93 for addr in &value.addrs {94 match addr {95 TransportAddr::Relay(url) => relay_url = Some(url.to_string()),96 TransportAddr::Ip(socket) => addresses.push(socket.to_string()),97 _ => {}98 }99 }100 EndpointAddr {101 id: *value.id.as_bytes(),102 relay_url,103 addresses,104 }105 }106}