use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::path::PathBuf;
use clap::Parser;
use switchyard_server::config::load_server_state;
use switchyard_server::{
DEFAULT_GRACEFUL_SHUTDOWN_TIMEOUT, DEFAULT_LISTEN_BACKLOG, ServerError, ServerResult,
ServerRunOptions, ServerState, TlsOptions, run_server,
};
const DEFAULT_HOST: IpAddr = IpAddr::V4(Ipv4Addr::UNSPECIFIED);
const DEFAULT_PORT: u16 = 4000;
#[derive(Debug, Parser)]
#[command(
name = "switchyard-server",
about = "Serve explicitly configured libsy algorithms",
version
)]
pub(crate) struct ServerArgs {
#[arg(long, value_name = "PATH")]
config: PathBuf,
#[arg(long, default_value_t = DEFAULT_HOST)]
host: IpAddr,
#[arg(short, long, default_value_t = DEFAULT_PORT)]
port: u16,
#[arg(long, default_value_t = DEFAULT_LISTEN_BACKLOG)]
backlog: u32,
#[arg(long, default_value_t = humantime::Duration::from(DEFAULT_GRACEFUL_SHUTDOWN_TIMEOUT))]
shutdown_timeout: humantime::Duration,
#[arg(long)]
dry_run: bool,
#[arg(long, value_name = "PATH")]
routing_log_file: Option<PathBuf>,
#[arg(long, requires = "tls_key")]
tls_cert: Option<PathBuf>,
#[arg(long, requires = "tls_cert")]
tls_key: Option<PathBuf>,
}
impl ServerArgs {
pub(crate) fn parse_args() -> Self {
Self::parse()
}
fn into_runtime(self) -> ServerResult<(ServerState, ServerRunOptions)> {
let mut state = load_server_state(&self.config)?;
if let Some(path) = self.routing_log_file {
state = state.with_routing_log(path)?;
}
let tls = match (self.tls_cert, self.tls_key) {
(Some(cert), Some(key)) => {
if !cert.exists() || !key.exists() {
return Err(ServerError::new(format!(
"invalid --tls-cert {} or --tls-key {}: file does not exist",
cert.display(),
key.display()
)));
}
Some(TlsOptions { cert, key })
}
_ => None,
};
let options = ServerRunOptions {
addr: SocketAddr::new(self.host, self.port),
backlog: self.backlog,
dry_run: self.dry_run,
shutdown_timeout: self.shutdown_timeout.into(),
tls,
};
Ok((state, options))
}
}
pub(crate) async fn run(args: ServerArgs) -> ServerResult<()> {
let (state, options) = args.into_runtime()?;
run_server(state, options).await
}