mod build;
mod config;
mod host;
mod sni;
mod upstream;
use clap::Parser;
use clap_verbosity_flag::Verbosity;
use config::Config;
use std::{fmt::Debug, path::PathBuf};
use trillium_server_common::Swansong;
#[derive(Parser, Debug)]
pub struct GatewayCli {
#[arg(
short,
long,
env = "TRILLIUM_GATEWAY_CONFIG",
default_value = "gateway.kdl"
)]
config: PathBuf,
#[arg(long)]
check: bool,
#[command(flatten)]
verbose: Verbosity,
}
impl GatewayCli {
pub fn run(self) {
env_logger::Builder::new()
.filter_level(self.verbose.log_level_filter())
.init();
let config = match Config::load(&self.config) {
Ok(config) => config,
Err(report) => {
eprintln!("{report:?}");
std::process::exit(1);
}
};
if self.check {
println!("{config:#?}");
return;
}
if config.bindings.is_empty() {
eprintln!("no `binding` declared in {}", self.config.display());
std::process::exit(1);
}
build::print_startup(&config);
let client = build::build_client(&config);
let swansong = Swansong::new();
let mut handles = Vec::with_capacity(config.bindings.len());
for binding in &config.bindings {
handles.push(build::spawn_binding(binding, &config, &swansong, &client));
}
wait_for_shutdown_signal();
log::info!("shutting down {} binding(s)", handles.len());
swansong.shut_down();
swansong.block_on_shutdown_completion();
}
}
#[cfg(unix)]
fn wait_for_shutdown_signal() {
use signal_hook::{
consts::signal::{SIGINT, SIGQUIT, SIGTERM},
iterator::Signals,
};
let mut signals = Signals::new([SIGINT, SIGTERM, SIGQUIT]).expect("registering signals");
signals.forever().next();
}
#[cfg(not(unix))]
fn wait_for_shutdown_signal() {
loop {
std::thread::park();
}
}