use std::net::SocketAddr;
use std::path::PathBuf;
use clap::{Parser, Subcommand, Args, ValueEnum};
#[derive(Parser, Debug)]
#[command(
name = "triglav",
author,
version,
about = "High-performance multi-path VPN with intelligent uplink management",
long_about = r#"
Triglav is a sophisticated multi-path VPN that provides:
- True virtual network interface (TUN) for transparent tunneling
- Encrypted, redundant connections across multiple network interfaces
- Intelligent uplink selection based on real-time quality metrics
- Automatic failover and bandwidth aggregation
- ECMP-aware flow routing for connection consistency
QUICK START:
Server: triglav server --generate-key
Client: triglav tun <key> --full-tunnel
Legacy: triglav connect <key> --socks 1080
For more information, visit https://github.com/triglav/triglav
"#
)]
#[command(propagate_version = true)]
pub struct Cli {
#[arg(short, long, global = true)]
pub config: Option<PathBuf>,
#[arg(short, long, global = true, default_value = "info")]
pub log_level: String,
#[arg(long, global = true, default_value = "text")]
pub format: OutputFormat,
#[arg(long, global = true)]
pub no_color: bool,
#[command(subcommand)]
pub command: Commands,
}
#[derive(Subcommand, Debug)]
pub enum Commands {
Server(ServerArgs),
Tun(TunArgs),
Connect(ConnectArgs),
Keygen(KeygenArgs),
Status(StatusArgs),
Uplink(UplinkArgs),
Diagnose(DiagnoseArgs),
Benchmark(BenchmarkArgs),
Completions(CompletionsArgs),
Config(ConfigArgs),
}
#[derive(Args, Debug)]
pub struct ServerArgs {
#[arg(short, long, default_value = "0.0.0.0:7443")]
pub listen: Vec<SocketAddr>,
#[arg(short, long)]
pub key: Option<PathBuf>,
#[arg(long)]
pub generate_key: bool,
#[arg(long)]
pub print_key: bool,
#[arg(long, default_value = "10000")]
pub max_connections: usize,
#[arg(long, default_value = "true")]
pub tcp_fallback: bool,
#[arg(short, long)]
pub daemon: bool,
#[arg(long)]
pub pid_file: Option<PathBuf>,
}
#[derive(Args, Debug)]
pub struct TunArgs {
pub key: String,
#[arg(short, long)]
pub interface: Vec<String>,
#[arg(long, default_value = "true")]
pub auto_discover: bool,
#[arg(long, default_value = "tg0")]
pub tun_name: String,
#[arg(long, default_value = "10.0.85.1")]
pub ipv4: String,
#[arg(long)]
pub ipv6: Option<String>,
#[arg(long)]
pub full_tunnel: bool,
#[arg(long)]
pub route: Vec<String>,
#[arg(long)]
pub exclude: Vec<String>,
#[arg(long)]
pub dns: bool,
#[arg(long, default_value = "1.1.1.1:53")]
pub dns_server: Vec<String>,
#[arg(long, default_value = "adaptive")]
pub strategy: SchedulingStrategy,
#[arg(short, long)]
pub verbose: bool,
#[arg(short, long)]
pub foreground: bool,
}
#[derive(Args, Debug)]
pub struct ConnectArgs {
pub key: String,
#[arg(short, long)]
pub interface: Vec<String>,
#[arg(long)]
pub auto_discover: bool,
#[arg(long)]
pub socks: Option<u16>,
#[arg(long)]
pub http_proxy: Option<u16>,
#[arg(short, long)]
pub foreground: bool,
#[arg(long, default_value = "adaptive")]
pub strategy: SchedulingStrategy,
#[arg(short, long)]
pub verbose: bool,
}
#[derive(Args, Debug)]
pub struct KeygenArgs {
#[arg(short, long)]
pub output: Option<PathBuf>,
#[arg(short, long)]
pub address: Vec<SocketAddr>,
#[arg(long)]
pub qr: bool,
#[arg(long = "key-format", default_value = "base64")]
pub key_format: KeyFormat,
}
#[derive(Args, Debug, Clone)]
pub struct StatusArgs {
#[arg(short, long)]
pub detailed: bool,
#[arg(short, long)]
pub watch: bool,
#[arg(long, default_value = "1")]
pub interval: u64,
#[arg(long)]
pub json: bool,
}
#[derive(Args, Debug)]
pub struct UplinkArgs {
#[command(subcommand)]
pub command: UplinkCommands,
}
#[derive(Subcommand, Debug)]
pub enum UplinkCommands {
List,
Add {
#[arg(short, long)]
interface: String,
#[arg(short, long, default_value = "100")]
weight: u32,
},
Remove {
id: String,
},
Show {
id: String,
},
Enable {
id: String,
},
Disable {
id: String,
},
}
#[derive(Args, Debug)]
pub struct DiagnoseArgs {
#[arg(short, long)]
pub full: bool,
#[arg(short, long)]
pub interface: Option<String>,
#[arg(long)]
pub connectivity: bool,
#[arg(long)]
pub mtu: bool,
}
#[derive(Args, Debug)]
pub struct BenchmarkArgs {
pub key: String,
#[arg(short, long, default_value = "10")]
pub duration: u64,
#[arg(short, long, default_value = "4")]
pub streams: u32,
#[arg(long, default_value = "both")]
pub direction: BenchmarkDirection,
}
#[derive(Args, Debug)]
pub struct CompletionsArgs {
pub shell: Shell,
}
#[derive(Args, Debug)]
pub struct ConfigArgs {
#[arg(long)]
pub server: bool,
#[arg(long)]
pub client: bool,
#[arg(short, long)]
pub output: Option<PathBuf>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub enum OutputFormat {
Text,
Json,
Table,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub enum SchedulingStrategy {
Wrr,
Latency,
Loss,
Adaptive,
Redundant,
PrimaryBackup,
}
impl From<SchedulingStrategy> for crate::multipath::SchedulingStrategy {
fn from(s: SchedulingStrategy) -> Self {
match s {
SchedulingStrategy::Wrr => Self::WeightedRoundRobin,
SchedulingStrategy::Latency => Self::LowestLatency,
SchedulingStrategy::Loss => Self::LowestLoss,
SchedulingStrategy::Adaptive => Self::Adaptive,
SchedulingStrategy::Redundant => Self::Redundant,
SchedulingStrategy::PrimaryBackup => Self::PrimaryBackup,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub enum KeyFormat {
Base64,
Hex,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub enum BenchmarkDirection {
Upload,
Download,
Both,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub enum Shell {
Bash,
Zsh,
Fish,
PowerShell,
}