use std::net::SocketAddr;
use std::path::PathBuf;
use clap::Parser;
use clap::builder::Styles;
use clap::builder::styling::{AnsiColor, Style};
use ombrac_transport::quic::Congestion;
use crate::config::{TlsMode, TransportConfig};
#[derive(Parser, Debug)]
#[command(version, about, long_about = None, styles = styles())]
pub struct Args {
#[clap(long, short = 'c', value_name = "FILE")]
pub config: Option<PathBuf>,
#[clap(
long,
short = 'k',
help_heading = "Required",
value_name = "STR",
required_unless_present = "config"
)]
pub secret: Option<String>,
#[clap(
long,
short = 'l',
help_heading = "Required",
value_name = "ADDR",
required_unless_present = "config"
)]
pub listen: Option<SocketAddr>,
#[clap(flatten)]
pub transport: CliTransportConfig,
#[cfg(feature = "tracing")]
#[clap(flatten)]
pub logging: CliLoggingConfig,
}
#[derive(Parser, Debug, Clone)]
pub struct CliTransportConfig {
#[clap(long, value_enum, help_heading = "Transport")]
pub tls_mode: Option<TlsMode>,
#[clap(long, help_heading = "Transport", value_name = "FILE")]
pub ca_cert: Option<PathBuf>,
#[clap(long, help_heading = "Transport", value_name = "FILE")]
pub tls_cert: Option<PathBuf>,
#[clap(long, help_heading = "Transport", value_name = "FILE")]
pub tls_key: Option<PathBuf>,
#[clap(long, help_heading = "Transport", value_name = "BOOL")]
pub zero_rtt: Option<bool>,
#[clap(
long,
help_heading = "Transport",
value_name = "PROTOCOLS",
value_delimiter = ','
)]
pub alpn_protocols: Option<Vec<Vec<u8>>>,
#[clap(long, help_heading = "Transport", value_name = "ALGORITHM")]
pub congestion: Option<Congestion>,
#[clap(long, help_heading = "Transport", value_name = "NUM")]
pub cwnd_init: Option<u64>,
#[clap(long, help_heading = "Transport", value_name = "TIME")]
pub idle_timeout: Option<u64>,
#[clap(long, help_heading = "Transport", value_name = "TIME")]
pub keep_alive: Option<u64>,
#[clap(long, help_heading = "Transport", value_name = "NUM")]
pub max_streams: Option<u64>,
}
#[cfg(feature = "tracing")]
#[derive(Parser, Debug, Clone)]
pub struct CliLoggingConfig {
#[clap(long, help_heading = "Logging", value_name = "LEVEL")]
pub log_level: Option<String>,
}
impl CliTransportConfig {
pub fn into_transport_config(self) -> TransportConfig {
TransportConfig {
tls_mode: self.tls_mode,
ca_cert: self.ca_cert,
tls_cert: self.tls_cert,
tls_key: self.tls_key,
zero_rtt: self.zero_rtt,
alpn_protocols: self.alpn_protocols,
congestion: self.congestion,
cwnd_init: self.cwnd_init,
idle_timeout: self.idle_timeout,
keep_alive: self.keep_alive,
max_streams: self.max_streams,
}
}
}
#[cfg(feature = "tracing")]
impl CliLoggingConfig {
pub fn into_logging_config(self) -> crate::config::LoggingConfig {
crate::config::LoggingConfig {
log_level: self.log_level,
}
}
}
#[derive(Debug)]
pub struct CliConfig {
pub secret: Option<String>,
pub listen: Option<SocketAddr>,
pub transport: TransportConfig,
#[cfg(feature = "tracing")]
pub logging: crate::config::LoggingConfig,
}
impl Args {
pub fn parse_to_config() -> CliConfig {
let args = Self::parse();
CliConfig {
secret: args.secret,
listen: args.listen,
transport: args.transport.into_transport_config(),
#[cfg(feature = "tracing")]
logging: args.logging.into_logging_config(),
}
}
pub fn config_path() -> Option<PathBuf> {
Self::parse().config
}
}
fn styles() -> Styles {
Styles::styled()
.header(Style::new().bold().fg_color(Some(AnsiColor::Green.into())))
.usage(Style::new().bold().fg_color(Some(AnsiColor::Green.into())))
.literal(Style::new().bold().fg_color(Some(AnsiColor::Cyan.into())))
.placeholder(Style::new().fg_color(Some(AnsiColor::Cyan.into())))
.valid(Style::new().bold().fg_color(Some(AnsiColor::Cyan.into())))
.invalid(Style::new().bold().fg_color(Some(AnsiColor::Yellow.into())))
.error(Style::new().bold().fg_color(Some(AnsiColor::Red.into())))
}