use clap::{Parser, Subcommand};
use huddle_core::network::NetworkMode;
use libp2p::Multiaddr;
#[derive(Parser)]
#[command(name = "huddle-gui", version, about = "Huddle — decentralized encrypted chat (native GUI)")]
pub struct Cli {
#[arg(long)]
pub data_dir: Option<String>,
#[arg(long, value_parser = parse_mode)]
pub mode: Option<NetworkMode>,
#[arg(long, default_value_t = 0u16)]
pub port: u16,
#[arg(long)]
pub name: Option<String>,
#[arg(long)]
pub no_master_passphrase: bool,
#[arg(long = "relay", value_name = "MULTIADDR")]
pub relays: Vec<String>,
#[arg(long)]
pub no_relay: bool,
#[arg(long = "server", value_name = "WS_URL")]
pub server: Option<String>,
#[arg(long)]
pub no_server: bool,
#[arg(long = "tor-socks", value_name = "HOST:PORT")]
pub tor_socks: Option<String>,
#[arg(long = "clearnet-server", value_name = "WS_URL")]
pub clearnet_server: Option<String>,
#[arg(long = "transport", value_name = "ID")]
pub transport: Option<String>,
#[arg(long = "transport-order", value_name = "ID,ID,...")]
pub transport_order: Option<String>,
#[arg(long = "tor-bridge", value_name = "LINE")]
pub tor_bridge: Option<String>,
#[command(subcommand)]
pub command: Option<Commands>,
}
#[derive(Subcommand)]
pub enum Commands {
Doctor,
}
fn parse_mode(s: &str) -> std::result::Result<NetworkMode, String> {
NetworkMode::from_str(s).ok_or_else(|| format!("unknown mode `{s}` (try server, mdns or direct)"))
}
impl Cli {
pub fn parse_args() -> Self {
<Self as Parser>::parse()
}
pub fn is_doctor(&self) -> bool {
matches!(self.command, Some(Commands::Doctor))
}
pub fn resolve_relays(&self) -> Vec<Multiaddr> {
if self.no_relay {
return Vec::new();
}
let mut from = self.relays.clone();
if from.is_empty() {
from = huddle_core::config::load_relays().unwrap_or_default();
}
from.iter()
.filter_map(|s| match s.parse::<Multiaddr>() {
Ok(m) => Some(m),
Err(e) => {
tracing::warn!(%e, addr = %s, "ignoring invalid --relay addr");
None
}
})
.collect()
}
pub fn resolve_server_url(&self) -> Option<String> {
if self.no_server {
None
} else {
Some(
self.server
.clone()
.or_else(huddle_core::config::server_url)
.unwrap_or_else(|| huddle_core::app::DEFAULT_SERVER_URL.to_string()),
)
}
}
pub fn resolve_tor_socks(&self) -> Option<String> {
self.tor_socks.clone().or_else(huddle_core::config::tor_socks)
}
pub fn transport_order_vec(&self) -> Option<Vec<String>> {
self.transport_order.as_ref().map(|s| {
s.split(',')
.map(|t| t.trim().to_string())
.filter(|t| !t.is_empty())
.collect()
})
}
}
pub fn apply_data_dir_override(dir: &str) {
std::env::set_var("XDG_DATA_HOME", dir);
std::env::set_var("XDG_CONFIG_HOME", dir);
#[cfg(target_os = "macos")]
std::env::set_var("HOME", dir);
#[cfg(target_os = "windows")]
std::env::set_var("APPDATA", dir);
}