use anyhow::{anyhow, bail, Result}; use chanora_resolver::{run, setup_log, Args}; const DEFAULT_SERVICE: &str = "ts3"; #[tokio::main] async fn main() { setup_log(); if let Err(err) = execute(std::env::args().skip(1)).await { tracing::error!(err = %err, "lookup failed"); std::process::exit(1); } } async fn execute(args: I) -> Result<()> where I: IntoIterator, S: Into, { let parsed = parse_args(args)?; run(parsed).await } fn parse_args(args: I) -> Result where I: IntoIterator, S: Into, { let mut host = String::new(); let mut service = DEFAULT_SERVICE.to_string(); let mut protocol = String::new(); let mut iter = args.into_iter().map(Into::into).peekable(); while let Some(arg) = iter.next() { match arg.as_str() { "-h" | "--help" => { print_help(); std::process::exit(0); } "-host" | "--host" => { host = next_value(&mut iter, "host")?; } "-service" | "--service" => { service = next_value(&mut iter, "service")?; } "-protocol" | "--protocol" => { protocol = next_value(&mut iter, "protocol")?; } value if value.starts_with('-') => { bail!("unknown flag: {value}"); } value => { bail!("unexpected positional argument: {value}"); } } } Ok(Args { host, service, protocol, }) } fn next_value(iter: &mut std::iter::Peekable, flag: &str) -> Result where I: Iterator, { iter.next() .ok_or_else(|| anyhow!("missing value for {flag} flag")) } fn print_help() { println!("chanora-resolver -host -service -protocol "); } #[cfg(test)] mod tests { use super::*; #[test] fn parse_args_supports_flag_pairs() { let args = parse_args([ "-host", "Example.com", "-service", "dns", "-protocol", "udp", ]) .unwrap(); assert_eq!( args, Args { host: "Example.com".into(), service: "dns".into(), protocol: "udp".into(), } ); } }