Files

103 lines
2.4 KiB
Rust

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<I, S>(args: I) -> Result<()>
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
let parsed = parse_args(args)?;
run(parsed).await
}
fn parse_args<I, S>(args: I) -> Result<Args>
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
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<I>(iter: &mut std::iter::Peekable<I>, flag: &str) -> Result<String>
where
I: Iterator<Item = String>,
{
iter.next()
.ok_or_else(|| anyhow!("missing value for {flag} flag"))
}
fn print_help() {
println!("chanora-resolver -host <host> -service <dns|ts3|tsdns|nick> -protocol <udp|tcp>");
}
#[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(),
}
);
}
}