//! Minimal CLI: `cepis 01001000`. //! //! It exists for one concrete case — quickly confirming a local instance //! answers before pointing code at it: //! //! ```sh //! cepis --base-url http://localhost:8080 01001000 //! ``` //! //! A single CEP goes through the unit lookup, which carries `geo`; several go //! through the batch, which is one request instead of N and has no `geo`. //! //! It is not the library's main interface; for that, use the `cepis` crate. use std::process::ExitCode; use std::time::Duration; use cepis::{Client, DEFAULT_URL}; use serde_json::Value; const USAGE: &str = "\ usage: cepis [--base-url URL] [--timeout SECONDS] CEP [CEP ...] Look CEPs up against the cep.is API. --base-url URL API URL (default: https://cep.is) — point it at a local instance --timeout SECONDS per-socket timeout (default: 10) -h, --help show this message"; fn main() -> ExitCode { let mut base_url = DEFAULT_URL.to_owned(); let mut timeout = Duration::from_secs(10); let mut ceps: Vec = Vec::new(); let mut args = std::env::args().skip(1); while let Some(arg) = args.next() { match arg.as_str() { "-h" | "--help" => { println!("{USAGE}"); return ExitCode::SUCCESS; } "--base-url" => match args.next() { Some(value) => base_url = value, None => return fail("--base-url needs a URL"), }, "--timeout" => match args.next().map(|v| v.parse::()) { Some(Ok(seconds)) if seconds > 0.0 => timeout = Duration::from_secs_f64(seconds), _ => return fail("--timeout needs a positive number of seconds"), }, other if other.starts_with('-') => return fail(&format!("unknown option {other}")), other => ceps.push(other.to_owned()), } } if ceps.is_empty() { eprintln!("{USAGE}"); return ExitCode::FAILURE; } let client = Client::builder() .base_url(base_url) .timeout(timeout) .build(); let addresses = if ceps.len() == 1 { match client.lookup(&ceps[0]) { Ok(address) => vec![Some(address)], Err(err) => return fail(&err.to_string()), } } else { match client.lookup_many(&ceps) { Ok(found) => found, Err(err) => return fail(&err.to_string()), } }; let output: Vec = addresses .into_iter() .map(|a| a.map(|a| a.raw).unwrap_or(Value::Null)) .collect(); let rendered = if output.len() == 1 { serde_json::to_string_pretty(&output[0]) } else { serde_json::to_string_pretty(&output) }; match rendered { Ok(text) => { println!("{text}"); ExitCode::SUCCESS } Err(err) => fail(&err.to_string()), } } fn fail(message: &str) -> ExitCode { eprintln!("error: {message}"); ExitCode::FAILURE }