use std::io::Write as _;
use std::process::ExitCode;
use std::time::Duration;
use clap::{CommandFactory, Parser, Subcommand};
use clap_complete::aot::generate;
use digit::protocol::{finger, finger_raw};
use digit::query::{Query, DEFAULT_PORT};
#[derive(Subcommand, Debug)]
enum Command {
Completions {
shell: clap_complete::Shell,
},
}
#[derive(Parser, Debug)]
#[command(version, about)]
struct Cli {
#[command(subcommand)]
command: Option<Command>,
query: Option<String>,
#[arg(short, long)]
long: bool,
#[arg(short, long, default_value_t = DEFAULT_PORT)]
port: u16,
#[arg(short, long, default_value_t = 10)]
timeout: u64,
#[arg(long, default_value_t = 1_048_576)]
max_size: u64,
#[arg(long)]
raw: bool,
}
fn main() -> ExitCode {
let cli = Cli::parse();
if let Some(Command::Completions { shell }) = cli.command {
let mut cmd = Cli::command();
generate(shell, &mut cmd, "digit", &mut std::io::stdout());
return ExitCode::SUCCESS;
}
let query = match Query::parse(cli.query.as_deref(), cli.long, cli.port) {
Ok(q) => q,
Err(e) => {
eprintln!("digit: {}", e);
return ExitCode::FAILURE;
}
};
let timeout = Duration::from_secs(cli.timeout);
if cli.raw {
match finger_raw(&query, timeout, cli.max_size) {
Ok(bytes) => {
if bytes.len() as u64 >= cli.max_size {
eprintln!(
"digit: warning: response truncated at {} bytes (use --max-size to increase)",
cli.max_size
);
}
std::io::stdout()
.write_all(&bytes)
.expect("failed to write to stdout");
ExitCode::SUCCESS
}
Err(e) => {
eprintln!("digit: {}", e);
ExitCode::FAILURE
}
}
} else {
match finger(&query, timeout, cli.max_size) {
Ok(response) => {
if response.len() as u64 >= cli.max_size {
eprintln!(
"digit: warning: response truncated at {} bytes (use --max-size to increase)",
cli.max_size
);
}
print!("{}", response);
ExitCode::SUCCESS
}
Err(e) => {
eprintln!("digit: {}", e);
ExitCode::FAILURE
}
}
}
}