2023-05-11 12:19:36 +00:00
|
|
|
use clap::Parser;
|
|
|
|
use futures::stream::StreamExt;
|
|
|
|
use signal_hook::consts::signal;
|
|
|
|
use signal_hook_tokio::Signals;
|
|
|
|
use tokio::sync::oneshot;
|
|
|
|
|
2023-05-15 15:42:32 +00:00
|
|
|
use std::convert::Infallible;
|
2023-05-12 09:17:15 +00:00
|
|
|
use std::net::SocketAddr;
|
2023-05-11 12:19:36 +00:00
|
|
|
use std::path;
|
2023-05-12 09:17:15 +00:00
|
|
|
use std::str::FromStr;
|
2023-05-15 15:42:32 +00:00
|
|
|
use std::sync;
|
2023-05-11 12:19:36 +00:00
|
|
|
|
|
|
|
#[derive(Parser, Debug)]
|
|
|
|
#[command(version)]
|
2023-05-13 14:39:54 +00:00
|
|
|
#[command(about = "A domiply to another dimension")]
|
2023-05-11 12:19:36 +00:00
|
|
|
struct Cli {
|
2023-05-13 14:39:54 +00:00
|
|
|
#[arg(long, default_value_t = SocketAddr::from_str("127.0.0.1:3030").unwrap(), env = "DOMIPLY_HTTP_LISTEN_ADDR")]
|
2023-05-12 09:17:15 +00:00
|
|
|
http_listen_addr: SocketAddr,
|
|
|
|
|
2023-05-13 14:39:54 +00:00
|
|
|
#[arg(long, required = true, env = "DOMIPLY_PASSPHRASE")]
|
2023-05-12 16:17:23 +00:00
|
|
|
passphrase: String,
|
|
|
|
|
2023-05-13 14:39:54 +00:00
|
|
|
#[arg(long, required = true, env = "DOMIPLY_ORIGIN_STORE_GIT_DIR_PATH")]
|
2023-05-12 13:19:24 +00:00
|
|
|
origin_store_git_dir_path: path::PathBuf,
|
2023-05-11 12:19:36 +00:00
|
|
|
|
2023-05-13 14:39:54 +00:00
|
|
|
#[arg(long, required = true, env = "DOMIPLY_DOMAIN_CHECKER_TARGET_CNAME")]
|
|
|
|
domain_checker_target_cname: domiply::domain::Name,
|
2023-05-11 12:19:36 +00:00
|
|
|
|
2023-05-13 14:39:54 +00:00
|
|
|
#[arg(long, default_value_t = String::from("1.1.1.1:53"), env = "DOMIPLY_DOMAIN_CHECKER_RESOLVER_ADDR")]
|
2023-05-11 12:19:36 +00:00
|
|
|
domain_checker_resolver_addr: String,
|
|
|
|
|
2023-05-13 14:39:54 +00:00
|
|
|
#[arg(long, required = true, env = "DOMIPLY_DOMAIN_CONFIG_STORE_DIR_PATH")]
|
2023-05-12 13:19:24 +00:00
|
|
|
domain_config_store_dir_path: path::PathBuf,
|
2023-05-11 12:19:36 +00:00
|
|
|
}
|
|
|
|
|
2023-05-14 09:18:36 +00:00
|
|
|
fn main() {
|
2023-05-11 12:19:36 +00:00
|
|
|
let config = Cli::parse();
|
|
|
|
|
2023-05-14 09:18:36 +00:00
|
|
|
let tokio_runtime = std::sync::Arc::new(
|
|
|
|
tokio::runtime::Builder::new_multi_thread()
|
|
|
|
.enable_all()
|
|
|
|
.build()
|
|
|
|
.unwrap(),
|
|
|
|
);
|
|
|
|
|
|
|
|
let (stop_ch_tx, stop_ch_rx) = tokio_runtime.block_on(async { oneshot::channel() });
|
|
|
|
|
2023-05-11 12:19:36 +00:00
|
|
|
// set up signal handling, stop_ch_rx will be used to signal that the stop signal has been
|
|
|
|
// received
|
2023-05-14 09:18:36 +00:00
|
|
|
tokio_runtime.spawn(async move {
|
2023-05-11 12:19:36 +00:00
|
|
|
let mut signals = Signals::new(&[signal::SIGTERM, signal::SIGINT, signal::SIGQUIT])
|
|
|
|
.expect("initialized signals");
|
|
|
|
|
2023-05-14 09:18:36 +00:00
|
|
|
if let Some(_) = signals.next().await {
|
|
|
|
println!("Gracefully shutting down...");
|
|
|
|
let _ = stop_ch_tx.send(());
|
|
|
|
}
|
2023-05-11 12:19:36 +00:00
|
|
|
|
2023-05-14 09:18:36 +00:00
|
|
|
if let Some(_) = signals.next().await {
|
|
|
|
println!("Forcefully shutting down");
|
|
|
|
std::process::exit(1);
|
|
|
|
};
|
|
|
|
});
|
2023-05-11 12:19:36 +00:00
|
|
|
|
2023-05-13 14:39:54 +00:00
|
|
|
let origin_store = domiply::origin::store::git::new(config.origin_store_git_dir_path)
|
2023-05-11 12:19:36 +00:00
|
|
|
.expect("git origin store initialized");
|
|
|
|
|
2023-05-13 14:39:54 +00:00
|
|
|
let domain_checker = domiply::domain::checker::new(
|
2023-05-14 09:18:36 +00:00
|
|
|
tokio_runtime.clone(),
|
2023-05-12 16:17:23 +00:00
|
|
|
config.domain_checker_target_cname.clone(),
|
2023-05-11 12:19:36 +00:00
|
|
|
&config.domain_checker_resolver_addr,
|
|
|
|
)
|
|
|
|
.expect("domain checker initialized");
|
|
|
|
|
2023-05-13 14:39:54 +00:00
|
|
|
let domain_config_store = domiply::domain::config::new(&config.domain_config_store_dir_path)
|
2023-05-12 13:19:24 +00:00
|
|
|
.expect("domain config store initialized");
|
2023-05-11 12:19:36 +00:00
|
|
|
|
2023-05-13 14:39:54 +00:00
|
|
|
let manager = domiply::domain::manager::new(origin_store, domain_config_store, domain_checker);
|
2023-05-15 15:42:32 +00:00
|
|
|
let manager = sync::Arc::new(manager);
|
2023-05-11 12:19:36 +00:00
|
|
|
|
2023-05-13 14:39:54 +00:00
|
|
|
let service = domiply::service::new(
|
2023-05-12 16:17:23 +00:00
|
|
|
manager,
|
|
|
|
config.domain_checker_target_cname,
|
|
|
|
config.passphrase,
|
2023-05-15 15:42:32 +00:00
|
|
|
);
|
2023-05-11 12:19:36 +00:00
|
|
|
|
2023-05-15 15:42:32 +00:00
|
|
|
let service = sync::Arc::new(service);
|
|
|
|
|
|
|
|
let make_service =
|
|
|
|
hyper::service::make_service_fn(move |_conn: &hyper::server::conn::AddrStream| {
|
|
|
|
let service = service.clone();
|
|
|
|
|
|
|
|
// Create a `Service` for responding to the request.
|
|
|
|
let service = hyper::service::service_fn(move |req| {
|
|
|
|
domiply::service::handle_request(service.clone(), req)
|
2023-05-14 09:18:36 +00:00
|
|
|
});
|
2023-05-11 12:19:36 +00:00
|
|
|
|
2023-05-15 15:42:32 +00:00
|
|
|
// Return the service to hyper.
|
|
|
|
async move { Ok::<_, Infallible>(service) }
|
|
|
|
});
|
|
|
|
|
|
|
|
tokio_runtime.block_on(async {
|
|
|
|
let addr = config.http_listen_addr;
|
|
|
|
|
2023-05-14 09:18:36 +00:00
|
|
|
println!("Listening on {addr}");
|
2023-05-15 15:42:32 +00:00
|
|
|
let server = hyper::Server::bind(&addr).serve(make_service);
|
|
|
|
|
|
|
|
let graceful = server.with_graceful_shutdown(async {
|
|
|
|
stop_ch_rx.await.ok();
|
|
|
|
});
|
|
|
|
|
|
|
|
if let Err(e) = graceful.await {
|
|
|
|
panic!("server error: {}", e);
|
|
|
|
}
|
2023-05-14 09:18:36 +00:00
|
|
|
});
|
2023-05-11 12:19:36 +00:00
|
|
|
|
|
|
|
println!("Graceful shutdown complete");
|
|
|
|
}
|