use iroh_base::NodeId;
use iroh_relay::dns::DnsResolver;
pub use iroh_relay::dns::{N0_DNS_NODE_ORIGIN_PROD, N0_DNS_NODE_ORIGIN_STAGING};
use n0_future::boxed::BoxStream;
use super::{DiscoveryContext, DiscoveryError, IntoDiscovery, IntoDiscoveryError};
use crate::{
discovery::{Discovery, DiscoveryItem},
endpoint::force_staging_infra,
};
pub(crate) const DNS_STAGGERING_MS: &[u64] = &[200, 300];
#[derive(Debug)]
pub struct DnsDiscovery {
origin_domain: String,
dns_resolver: DnsResolver,
}
#[derive(Debug)]
pub struct DnsDiscoveryBuilder {
origin_domain: String,
dns_resolver: Option<DnsResolver>,
}
impl DnsDiscoveryBuilder {
pub fn dns_resolver(mut self, dns_resolver: DnsResolver) -> Self {
self.dns_resolver = Some(dns_resolver);
self
}
pub fn build(self) -> DnsDiscovery {
DnsDiscovery {
dns_resolver: self.dns_resolver.unwrap_or_default(),
origin_domain: self.origin_domain,
}
}
}
impl DnsDiscovery {
pub fn builder(origin_domain: String) -> DnsDiscoveryBuilder {
DnsDiscoveryBuilder {
origin_domain,
dns_resolver: None,
}
}
pub fn n0_dns() -> DnsDiscoveryBuilder {
if force_staging_infra() {
Self::builder(N0_DNS_NODE_ORIGIN_STAGING.to_string())
} else {
Self::builder(N0_DNS_NODE_ORIGIN_PROD.to_string())
}
}
}
impl IntoDiscovery for DnsDiscoveryBuilder {
fn into_discovery(
mut self,
context: &DiscoveryContext,
) -> Result<impl Discovery, IntoDiscoveryError> {
if self.dns_resolver.is_none() {
self.dns_resolver = Some(context.dns_resolver().clone());
}
Ok(self.build())
}
}
impl Discovery for DnsDiscovery {
fn resolve(&self, node_id: NodeId) -> Option<BoxStream<Result<DiscoveryItem, DiscoveryError>>> {
let resolver = self.dns_resolver.clone();
let origin_domain = self.origin_domain.clone();
let fut = async move {
let node_info = resolver
.lookup_node_by_id_staggered(&node_id, &origin_domain, DNS_STAGGERING_MS)
.await
.map_err(|e| DiscoveryError::from_err("dns", e))?;
Ok(DiscoveryItem::new(node_info, "dns", None))
};
let stream = n0_future::stream::once_future(fut);
Some(Box::pin(stream))
}
}