use crate::config::binding::TuiCommandItem;
use crate::config::theme::TuiThemeItem;
use crate::config::{
AddressFamilyConfig, AddressMode, AsMode, DnsResolveMethodConfig, GeoIpMode, IcmpExtensionMode,
LogFormat, LogSpanEvents, Mode, MultipathStrategyConfig, ProtocolConfig, TuiColor,
TuiKeyBinding,
};
use anyhow::anyhow;
use clap::builder::Styles;
use clap::Parser;
use clap_complete::Shell;
use std::net::IpAddr;
use std::str::FromStr;
use std::time::Duration;
#[allow(clippy::doc_markdown)]
#[derive(Parser, Debug)]
#[command(name = "trip", author, version, about, long_about = None, arg_required_else_help(true), styles=Styles::styled())]
pub struct Args {
#[arg(required_unless_present_any(["print_tui_theme_items", "print_tui_binding_commands", "print_config_template", "generate", "generate_man", "print_locales"]))]
pub targets: Vec<String>,
#[arg(value_enum, short = 'c', long, value_hint = clap::ValueHint::FilePath)]
pub config_file: Option<String>,
#[arg(value_enum, short = 'm', long)]
pub mode: Option<Mode>,
#[arg(short = 'u', long)]
pub unprivileged: bool,
#[arg(value_enum, short = 'p', long)]
pub protocol: Option<ProtocolConfig>,
#[arg(
long,
conflicts_with = "protocol",
conflicts_with = "tcp",
conflicts_with = "icmp"
)]
pub udp: bool,
#[arg(
long,
conflicts_with = "protocol",
conflicts_with = "udp",
conflicts_with = "icmp"
)]
pub tcp: bool,
#[arg(
long,
conflicts_with = "protocol",
conflicts_with = "udp",
conflicts_with = "tcp"
)]
pub icmp: bool,
#[arg(value_enum, short = 'F', long)]
pub addr_family: Option<AddressFamilyConfig>,
#[arg(
short = '4',
long,
conflicts_with = "ipv6",
conflicts_with = "addr_family"
)]
pub ipv4: bool,
#[arg(
short = '6',
long,
conflicts_with = "ipv4",
conflicts_with = "addr_family"
)]
pub ipv6: bool,
#[arg(long, short = 'P')]
pub target_port: Option<u16>,
#[arg(long, short = 'S')]
pub source_port: Option<u16>,
#[arg(short = 'A', long, value_parser = parse_addr, conflicts_with = "interface")]
pub source_address: Option<IpAddr>,
#[arg(short = 'I', long)]
pub interface: Option<String>,
#[arg(short = 'i', long, value_parser = parse_duration)]
pub min_round_duration: Option<Duration>,
#[arg(short = 'T', long, value_parser = parse_duration)]
pub max_round_duration: Option<Duration>,
#[arg(short = 'g', long, value_parser = parse_duration)]
pub grace_duration: Option<Duration>,
#[arg(long)]
pub initial_sequence: Option<u16>,
#[arg(value_enum, short = 'R', long)]
pub multipath_strategy: Option<MultipathStrategyConfig>,
#[arg(short = 'U', long)]
pub max_inflight: Option<u8>,
#[arg(short = 'f', long)]
pub first_ttl: Option<u8>,
#[arg(short = 't', long)]
pub max_ttl: Option<u8>,
#[arg(long)]
pub packet_size: Option<u16>,
#[arg(long)]
pub payload_pattern: Option<u8>,
#[arg(short = 'Q', long)]
pub tos: Option<u8>,
#[arg(short = 'e', long)]
pub icmp_extensions: bool,
#[arg(long, value_parser = parse_duration)]
pub read_timeout: Option<Duration>,
#[arg(value_enum, short = 'r', long)]
pub dns_resolve_method: Option<DnsResolveMethodConfig>,
#[arg(short = 'y', long)]
pub dns_resolve_all: bool,
#[arg(long, value_parser = parse_duration)]
pub dns_timeout: Option<Duration>,
#[arg(long, value_parser = parse_duration)]
pub dns_ttl: Option<Duration>,
#[arg(long, short = 'z')]
pub dns_lookup_as_info: bool,
#[arg(long, short = 's')]
pub max_samples: Option<usize>,
#[arg(long)]
pub max_flows: Option<usize>,
#[arg(value_enum, short = 'a', long)]
pub tui_address_mode: Option<AddressMode>,
#[arg(value_enum, long)]
pub tui_as_mode: Option<AsMode>,
#[arg(long)]
pub tui_custom_columns: Option<String>,
#[arg(value_enum, long)]
pub tui_icmp_extension_mode: Option<IcmpExtensionMode>,
#[arg(value_enum, long)]
pub tui_geoip_mode: Option<GeoIpMode>,
#[arg(short = 'M', long)]
pub tui_max_addrs: Option<u8>,
#[arg(long)]
pub tui_preserve_screen: bool,
#[arg(long, value_parser = parse_duration)]
pub tui_refresh_rate: Option<Duration>,
#[arg(long)]
pub tui_privacy_max_ttl: Option<u8>,
#[arg(long)]
pub tui_locale: Option<String>,
#[arg(long)]
pub tui_timezone: Option<String>,
#[arg(long, value_delimiter(','), value_parser = parse_tui_theme_color_value)]
pub tui_theme_colors: Vec<(TuiThemeItem, TuiColor)>,
#[arg(long)]
pub print_tui_theme_items: bool,
#[arg(long, value_delimiter(','), value_parser = parse_tui_binding_value)]
pub tui_key_bindings: Vec<(TuiCommandItem, TuiKeyBinding)>,
#[arg(long)]
pub print_tui_binding_commands: bool,
#[arg(short = 'C', long)]
pub report_cycles: Option<usize>,
#[arg(short = 'G', long, value_hint = clap::ValueHint::FilePath)]
pub geoip_mmdb_file: Option<String>,
#[arg(long)]
pub generate: Option<Shell>,
#[arg(long)]
pub generate_man: bool,
#[arg(long)]
pub print_config_template: bool,
#[arg(long)]
pub print_locales: bool,
#[arg(long)]
pub log_format: Option<LogFormat>,
#[arg(long)]
pub log_filter: Option<String>,
#[arg(long)]
pub log_span_events: Option<LogSpanEvents>,
#[arg(short = 'v', long, default_value_t = false)]
pub verbose: bool,
}
fn parse_tui_theme_color_value(value: &str) -> anyhow::Result<(TuiThemeItem, TuiColor)> {
let pos = value
.find('=')
.ok_or_else(|| anyhow!("invalid theme value: expected format `item=value`"))?;
let item = TuiThemeItem::try_from(&value[..pos])?;
let color = TuiColor::try_from(&value[pos + 1..])?;
Ok((item, color))
}
fn parse_tui_binding_value(value: &str) -> anyhow::Result<(TuiCommandItem, TuiKeyBinding)> {
let pos = value
.find('=')
.ok_or_else(|| anyhow!("invalid binding value: expected format `item=value`"))?;
let item = TuiCommandItem::try_from(&value[..pos])?;
let binding = TuiKeyBinding::try_from(&value[pos + 1..])?;
if item == TuiCommandItem::DeprecatedTogglePrivacy {
return Err(anyhow!(
"toggle-privacy is deprecated, use expand-privacy and contract-privacy instead"
));
}
Ok((item, binding))
}
fn parse_duration(value: &str) -> anyhow::Result<Duration> {
Ok(humantime::parse_duration(value)?)
}
fn parse_addr(value: &str) -> anyhow::Result<IpAddr> {
Ok(IpAddr::from_str(value)?)
}