iroh_dns_server/
server.rs1#[cfg(test)]
3use std::path::Path;
4use std::{net::SocketAddr, sync::Arc};
5
6use n0_error::Result;
7use tracing::info;
8#[cfg(test)]
9use url::Url;
10
11#[cfg(test)]
12use crate::http::HttpsConfig;
13use crate::{
14 config::Config,
15 dns::{DnsHandler, DnsServer},
16 http::HttpServer,
17 metrics::Metrics,
18 state::AppState,
19 store::ZoneStore,
20};
21
22#[derive(Debug)]
28pub struct Server {
29 http_server: HttpServer,
30 dns_server: DnsServer,
31 metrics_server: Option<iroh_metrics::service::MetricsServer>,
32 metrics: Arc<Metrics>,
33}
34
35impl Server {
36 pub async fn bind(config: Config) -> Result<Self> {
42 let metrics = Arc::new(Metrics::default());
43 let mut store = ZoneStore::persistent(
44 config.signed_packet_store_path()?,
45 config.zone_store.clone().unwrap_or_default().into(),
46 metrics.clone(),
47 )?;
48 if let Some(bootstrap) = config.mainline_enabled() {
49 info!("mainline fallback enabled");
50 store = store.with_mainline_fallback(bootstrap);
51 };
52 Self::bind_with_store(config, store, metrics).await
53 }
54
55 async fn bind_with_store(
62 config: Config,
63 store: ZoneStore,
64 metrics: Arc<Metrics>,
65 ) -> Result<Self> {
66 let cert_cache_dir = config.data_dir()?.join("cert_cache");
67 let dns_handler = DnsHandler::new(store.clone(), &config.dns, metrics.clone())?;
68
69 let state = AppState {
70 store,
71 dns_handler,
72 metrics: metrics.clone(),
73 };
74
75 let metrics_server = if let Some(addr) = config.metrics_addr() {
76 let mut registry = iroh_metrics::Registry::default();
77 registry.register(metrics.clone());
78 let server =
79 iroh_metrics::service::MetricsServer::spawn(addr, Arc::new(registry)).await?;
80 Some(server)
81 } else {
82 None
83 };
84
85 let http_server = HttpServer::spawn(
86 config.http,
87 config.https,
88 config.pkarr_put_rate_limit,
89 state.clone(),
90 cert_cache_dir,
91 )
92 .await?;
93 let dns_server = DnsServer::spawn(config.dns, state.dns_handler.clone()).await?;
94
95 Ok(Self {
96 http_server,
97 dns_server,
98 metrics_server,
99 metrics,
100 })
101 }
102
103 pub async fn shutdown(mut self) -> Result<()> {
105 if let Some(server) = self.metrics_server.take() {
106 server.shutdown().await;
107 }
108 let (res1, res2) = tokio::join!(self.dns_server.shutdown(), self.http_server.shutdown(),);
109 res1?;
110 res2?;
111 Ok(())
112 }
113
114 pub async fn join(mut self) -> Result<()> {
118 tokio::select! {
119 res = self.dns_server.run_until_done() => res?,
120 res = self.http_server.run_until_done() => res?,
121 }
122 if let Some(server) = self.metrics_server.take() {
123 server.shutdown().await;
124 }
125
126 Ok(())
127 }
128
129 pub fn metrics(&self) -> &Arc<Metrics> {
131 &self.metrics
132 }
133
134 #[cfg(test)]
141 pub(crate) async fn spawn_for_tests(dir: impl AsRef<Path>) -> Result<Self> {
142 Self::spawn_for_tests_with_options(dir, None, None, None).await
143 }
144
145 #[cfg(test)]
148 pub(crate) async fn spawn_for_tests_with_options(
149 dir: impl AsRef<Path>,
150 mainline: Option<crate::config::BootstrapOption>,
151 options: Option<crate::store::Options>,
152 https: Option<HttpsConfig>,
153 ) -> Result<Self> {
154 use std::net::{IpAddr, Ipv4Addr};
155
156 use crate::config::MetricsConfig;
157
158 let mut config = Config::default();
159 config.dns.port = 0;
160 config.dns.bind_addr = Some(IpAddr::V4(Ipv4Addr::LOCALHOST));
161 config.http.as_mut().unwrap().port = 0;
162 config.http.as_mut().unwrap().bind_addr = Some(IpAddr::V4(Ipv4Addr::LOCALHOST));
163 config.https = https;
164 config.metrics = Some(MetricsConfig::disabled());
165 config.data_dir = Some(dir.as_ref().to_owned());
166
167 let mut store = ZoneStore::in_memory(options.unwrap_or_default(), Default::default())?;
168 if let Some(bootstrap) = mainline {
169 info!("mainline fallback enabled");
170 store = store.with_mainline_fallback(bootstrap);
171 }
172 let server = Self::bind_with_store(config, store, Default::default()).await?;
173 Ok(server)
174 }
175
176 pub fn dns_addr(&self) -> SocketAddr {
178 self.dns_server.local_addr()
179 }
180
181 pub fn http_addr(&self) -> Option<SocketAddr> {
184 self.http_server.http_addr()
185 }
186
187 pub fn https_addr(&self) -> Option<SocketAddr> {
190 self.http_server.https_addr()
191 }
192
193 #[cfg(test)]
194 pub(crate) fn http_url(&self) -> Option<Url> {
195 let http_addr = self.http_server.http_addr()?;
196 Some(
197 format!("http://{http_addr}")
198 .parse::<url::Url>()
199 .expect("valid url"),
200 )
201 }
202
203 #[cfg(test)]
204 pub(crate) fn https_url(&self) -> Option<Url> {
205 let https_addr = self.https_addr()?;
206 Some(
207 format!("https://{https_addr}")
208 .parse::<url::Url>()
209 .expect("valid url"),
210 )
211 }
212}