use anyhow::Result; use bore_cli::{client::Client, server::Server}; use clap::{error::ErrorKind, CommandFactory, Parser, Subcommand}; #[derive(Parser, Debug)] #[clap(author, version, about)] struct Args { #[clap(subcommand)] command: Command, } #[derive(Subcommand, Debug)] enum Command { /// Starts a local proxy to the remote server. Local { /// The local port to expose. local_port: u16, /// The local host to expose. #[clap(short, long, value_name = "HOST", default_value = "localhost")] local_host: String, /// Address of the remote server to expose local ports to. #[clap(short, long, env = "BORE_SERVER")] to: String, /// Optional port on the remote server to select. #[clap(short, long, default_value_t = 0)] port: u16, /// Optional secret for authentication. #[clap(short, long, env = "BORE_SECRET", hide_env_values = true)] secret: Option, }, /// Runs the remote proxy server. Server { /// Minimum accepted TCP port number. #[clap(long, default_value_t = 1024, env = "BORE_MIN_PORT")] min_port: u16, /// Maximum accepted TCP port number. #[clap(long, default_value_t = 65535, env = "BORE_MAX_PORT")] max_port: u16, /// Optional secret for authentication. #[clap(short, long, env = "BORE_SECRET", hide_env_values = true)] secret: Option, }, } #[tokio::main] async fn run(command: Command) -> Result<()> { match command { Command::Local { local_host, local_port, to, port, secret, } => { let client = Client::new(&local_host, local_port, &to, port, secret.as_deref()).await?; client.listen().await?; } Command::Server { min_port, max_port, secret, } => { let port_range = min_port..=max_port; if port_range.is_empty() { Args::command() .error(ErrorKind::InvalidValue, "port range is empty") .exit(); } Server::new(port_range, secret.as_deref()).listen().await?; } } Ok(()) } fn main() -> Result<()> { tracing_subscriber::fmt::init(); run(Args::parse().command) }