mod auth; mod cmd; mod config; mod ui; use anyhow::Result; use auth::AuthedClient; use clap::{Args, Parser, Subcommand}; use config::Config; #[derive(Parser, Debug)] #[command(name = "rshc", version, about = "rsh operator client")] struct Cli { #[command(subcommand)] cmd: Cmd, } #[derive(Subcommand, Debug)] enum Cmd { Watch(WatchArgs), #[command(alias = "sessions", alias = "s", alias = "sess")] Session(SessionCmd), #[command(alias = "connections", alias = "conn")] Connection(ConnectionCmd), #[command(alias = "c")] Connect(ConnectArgs), #[command(alias = "sh")] Shell(ShellArgs), ServeSsh(ServeSshArgs), Keys(KeysCmd), } #[derive(Args, Debug)] struct WatchArgs { session: Option, } #[derive(Args, Debug)] struct SessionCmd { #[command(subcommand)] sub: SessionSub, } #[derive(Subcommand, Debug)] enum SessionSub { #[command(alias = "c")] Create { name: String }, #[command(alias = "del", alias = "d", alias = "rm")] Delete { name: String, #[arg(short = 'y', long)] yes: bool, #[arg(long)] disconnect: bool, }, Update { name: String, #[arg(long = "pw", num_args = 0..=1, default_missing_value = "")] pw: Option, #[arg(long)] disconnect: bool, }, #[command(alias = "l", alias = "ls")] List, } #[derive(Args, Debug)] struct ConnectionCmd { #[command(subcommand)] sub: ConnectionSub, } #[derive(Subcommand, Debug)] enum ConnectionSub { #[command(alias = "l", alias = "ls")] List { #[arg(long)] session: Option, }, } #[derive(Args, Debug)] struct ConnectArgs { session: String, connection_id: Option, #[arg(long)] no_pty: bool, } #[derive(Args, Debug)] struct ShellArgs { session: String, #[arg(long)] connection: Option, #[arg(long)] shell: Option, #[arg(long)] no_pty: bool, } #[derive(Args, Debug)] struct ServeSshArgs { session: String, #[arg(short = 'H', long, default_value = "127.0.0.1")] listen_host: String, #[arg(short = 'p', long, default_value_t = 2222)] listen_port: u16, #[arg(long)] connection: Option, #[arg(long)] shell: Option, } #[derive(Args, Debug)] struct KeysCmd { #[command(subcommand)] sub: KeysSub, } #[derive(Subcommand, Debug)] enum KeysSub { Append { key: Option, #[arg(long)] file: Option, #[arg(long)] url: Option, }, Rm { key: Option, #[arg(long)] file: Option, #[arg(long)] url: Option, }, #[command(alias = "l", alias = "ls")] List, Edit, } #[tokio::main] async fn main() { let _ = tracing_subscriber::fmt() .with_writer(std::io::stderr) .with_env_filter(tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("warn"))) .try_init(); if let Err(e) = run().await { ui::print_err(&e); std::process::exit(1); } } async fn run() -> Result<()> { let cli = Cli::parse(); let cfg = Config::load()?; if let Cmd::Watch(a) = cli.cmd { return cmd::watch::run_with_reconnect(&cfg, a.session).await; } let client = AuthedClient::connect(&cfg).await?; match cli.cmd { Cmd::Watch(_) => unreachable!(), Cmd::Session(s) => match s.sub { SessionSub::Create { name } => cmd::session::create(&client, name).await, SessionSub::Delete { name, yes, disconnect } => cmd::session::delete(&client, name, yes, disconnect).await, SessionSub::Update { name, pw, disconnect } => { let pw_flag = match pw { None => None, Some(s) if s.is_empty() => Some(None), Some(s) => Some(Some(s)), }; cmd::session::update(&client, name, pw_flag, disconnect).await } SessionSub::List => cmd::session::list(&client).await, }, Cmd::Connection(c) => match c.sub { ConnectionSub::List { session } => cmd::connection::list(&client, session).await, }, Cmd::Connect(a) => cmd::connect::run(&client, a.session, a.connection_id, a.no_pty).await, Cmd::Shell(a) => cmd::shell::run(&client, a.session, a.connection, a.shell, a.no_pty).await, Cmd::ServeSsh(a) => cmd::serve_ssh::run(cfg, client, a.session, a.listen_host, a.listen_port, a.connection, a.shell).await, Cmd::Keys(k) => match k.sub { KeysSub::Append { key, file, url } => cmd::keys::append(&client, key, file, url).await, KeysSub::Rm { key, file, url } => cmd::keys::remove(&client, key, file, url).await, KeysSub::List => cmd::keys::list(&client).await, KeysSub::Edit => cmd::keys::edit(&client).await, }, } }