use std::path::PathBuf;
use std::process::ExitCode;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use clap::{ArgMatches, Args, Command, FromArgMatches, Subcommand};
use clap_complete::engine::ArgValueCandidates;
use cerulion_cli_engine::{connect_cmd, rcp_cmd};
use super::VerbFamily;
use crate::cli::VerbLogClass;
use crate::network_switch::{NetworkRefusal, SwitchEnv};
#[derive(Subcommand)]
enum RcpCmd {
Rcp(RcpCliArgs),
}
#[derive(Args)]
struct RcpCliArgs {
#[arg(value_name = "ROBOT", add = ArgValueCandidates::new(crate::completion::robot_names))]
robot: Option<String>,
#[arg(long, value_name = "HEX")]
eid: Option<String>,
#[arg(long = "addr", value_name = "IP:PORT")]
addrs: Vec<String>,
#[arg(long, value_name = "PATH", value_hint = clap::ValueHint::FilePath)]
key_file: Option<PathBuf>,
#[arg(long, value_name = "URL")]
relay_url: Option<String>,
#[arg(long)]
relay_disabled: bool,
#[arg(long)]
network: Option<String>,
}
pub(crate) struct Rcp;
impl VerbFamily for Rcp {
fn name(&self) -> &'static str {
"rcp"
}
fn listed_after(&self) -> Option<&'static str> {
Some("pair")
}
fn command(&self) -> Command {
super::derived_verb::<RcpCmd>()
}
fn log_class(&self, _matches: &ArgMatches) -> VerbLogClass {
VerbLogClass::LongRunning
}
fn network_refusal(&self, matches: &ArgMatches, env: &SwitchEnv) -> Option<NetworkRefusal> {
rcp_cmd::network_refusal(
matches.get_one::<String>("network").map(String::as_str),
env.network.clone(),
)
.map(|refusal| NetworkRefusal::error(refusal, rcp_cmd::EXIT_NETWORK_REFUSED))
}
fn needs_identity(&self, _matches: &ArgMatches) -> bool {
true
}
fn run(&self, matches: &ArgMatches) -> ExitCode {
let cli = RcpCliArgs::from_arg_matches(matches).unwrap_or_else(|e| e.exit());
let args = rcp_cmd::RcpArgs {
robot: cli.robot,
eid: cli.eid,
addrs: cli.addrs,
key_file: cli.key_file,
relay_url: cli.relay_url,
relay_disabled: cli.relay_disabled,
network: cli.network,
};
let plan = match rcp_cmd::plan(&args) {
Ok(p) => p,
Err(e) => {
eprintln!("Error: {e}");
return ExitCode::FAILURE;
}
};
let running = match crate::setup_ctrlc_handler() {
Ok(r) => r,
Err(e) => {
eprintln!("warning: could not install a signal handler: {e}");
Arc::new(AtomicBool::new(true))
}
};
match connect_cmd::spawn_and_wait(&plan, running) {
Ok(code) => ExitCode::from(code as u8),
Err(e) => {
eprintln!("Error: {e}");
ExitCode::FAILURE
}
}
}
}