use anyhow::Result;
use clap::ArgMatches;
use std::net::{IpAddr, SocketAddr};
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;
use tokio::sync::Notify;
use zerodns::client::SystemClient;
pub(crate) async fn execute(sm: &ArgMatches) -> Result<()> {
let c = {
let path = {
let path = sm.get_one::<String>("config").unwrap();
PathBuf::from(path)
};
zerodns::config::read_from_toml(&path)?
};
let mut is_main_logger_ok = false;
if let Some(lc) = &c.logger {
if let Some(lc) = &lc.main {
zerodns::setup_logger(lc)?;
is_main_logger_ok = true;
}
}
if !is_main_logger_ok {
let lc = zerodns::logger::Config::default();
zerodns::setup_logger(&lc)?;
}
if !c.global.nameservers.is_empty() {
let mut bu = SystemClient::builder();
for ns in &c.global.nameservers {
if let Ok(addr) = ns.parse::<IpAddr>() {
bu = bu.nameserver(SocketAddr::new(addr, zerodns::DEFAULT_UDP_PORT), false);
continue;
}
if let Ok(addr) = ns.parse::<SocketAddr>() {
bu = bu.nameserver(addr, false);
continue;
}
}
zerodns::client::set_default_resolver(bu.build()?);
} else if let Some(path) = &c.global.resolv_file {
if path != "/etc/resolv.conf" {
let sc = SystemClient::from_resolv_file(&PathBuf::from(path));
zerodns::client::set_default_resolver(sc);
}
}
zerodns::setup();
let closer = Arc::new(Notify::new());
let stopped = Arc::new(Notify::new());
{
let closer = Clone::clone(&closer);
let stopped = Clone::clone(&stopped);
tokio::spawn(async move {
if let Err(e) = zerodns::bootstrap::run(c, closer).await {
error!("zerodns server is stopped: {:?}", e);
}
stopped.notify_one();
});
}
tokio::signal::ctrl_c().await?;
closer.notify_waiters();
const SHUTDOWN_TIMEOUT: u64 = 15;
if let Err(_e) =
tokio::time::timeout(Duration::from_secs(SHUTDOWN_TIMEOUT), stopped.notified()).await
{
warn!(
"force stop process because graceful shutdown is timeout after {}s",
SHUTDOWN_TIMEOUT
);
}
Ok(())
}