use clap::{Parser, Subcommand};
#[derive(Parser, Debug)]
#[command(name = "gout", version, about = "轻量内网穿透工具")]
pub struct Cli {
#[command(subcommand)]
pub command: Command,
}
#[derive(Subcommand, Debug)]
pub enum Command {
Login {
name: Option<String>,
server: String,
key: String,
},
Tcp {
port: u16,
#[arg(long, short = 'd')]
detach: bool,
#[arg(long, short = 's')]
server: Option<String>,
},
Udp {
port: u16,
#[arg(long, short = 'd')]
detach: bool,
#[arg(long, short = 's')]
server: Option<String>,
},
Http {
port: u16,
#[arg(long, short = 'd')]
detach: bool,
#[arg(long, short = 's')]
server: Option<String>,
},
#[clap(alias = "ls")]
List,
Log {
port: u16,
#[arg(long, short = 'f')]
follow: bool,
},
Kill {
port: u16,
},
#[command(subcommand)]
Server(ServerCmd),
}
#[derive(Subcommand, Debug)]
pub enum ServerCmd {
Set {
name: String,
host: String,
key: String,
},
Default {
name: String,
},
Unset {
name: String,
},
Show,
}
impl Cli {
pub fn run() -> anyhow::Result<()> {
let cli = Cli::parse();
if let Some(pidfile) = std::env::var("GOUT_DAEMON_PIDFILE").ok() {
let result = match cli.command {
Command::Tcp { port, .. } => crate::cmd_tunnel("tcp", port, None),
Command::Udp { port, .. } => crate::cmd_tunnel("udp", port, None),
Command::Http { port, .. } => crate::cmd_tunnel("http", port, None),
_ => anyhow::bail!("daemon mode unsupported for this command"),
};
std::fs::remove_file(&pidfile).ok();
return result;
}
match cli.command {
Command::Login { name, server, key } => {
let n = name.unwrap_or_else(|| {
server.split(':').next().unwrap_or(&server).to_string()
});
crate::cmd_server_set(&n, &server, &key)
}
Command::Tcp { port, detach: true, server } => crate::cmd_start_daemon("tcp", port, server.as_deref()),
Command::Tcp { port, detach: false, server } => crate::cmd_tunnel("tcp", port, server.as_deref()),
Command::Udp { port, detach: true, server } => crate::cmd_start_daemon("udp", port, server.as_deref()),
Command::Udp { port, detach: false, server } => crate::cmd_tunnel("udp", port, server.as_deref()),
Command::Http { port, detach: true, server } => crate::cmd_start_daemon("http", port, server.as_deref()),
Command::Http { port, detach: false, server } => crate::cmd_tunnel("http", port, server.as_deref()),
Command::Log { port, follow } => crate::cmd_log(port, follow),
Command::Kill { port } => crate::cmd_kill(port),
Command::List => crate::cmd_list(),
Command::Server(cmd) => match cmd {
ServerCmd::Set { name, host, key } => crate::cmd_server_set(&name, &host, &key),
ServerCmd::Default { name } => crate::cmd_server_default(&name),
ServerCmd::Unset { name } => crate::cmd_server_unset(&name),
ServerCmd::Show => crate::cmd_server_show(),
},
}
}
}