diff options
| author | Gus Power <gus@infinitesidequests.com> | 2025-05-21 16:23:55 +0100 |
|---|---|---|
| committer | Gus Power <gus@infinitesidequests.com> | 2025-05-21 16:23:55 +0100 |
| commit | d7ce374a1741fdbb5c3aeef1218058a3d1060e88 (patch) | |
| tree | ac4297e69ce670155fcd3c37c29b085d3707decc /src/main.rs | |
| parent | 9ce9c101a10327b1eb6902133173119c3e0f3732 (diff) | |
config fallback w/ tests. introduced a macro to remove some test boilerplate around Result<T,E> and having return Ok(())
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 102 |
1 files changed, 93 insertions, 9 deletions
diff --git a/src/main.rs b/src/main.rs index 57f4c7d..66fbdee 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,10 @@ use crate::config::Config; -use crate::error::AppResult; +use crate::error::{AppError, AppResult}; +use crate::ip_service::IpService; use clap::Parser; +use homedir::my_home; +use log::info; +use reqwest::ClientBuilder; use std::path::PathBuf; use std::process::exit; @@ -13,17 +17,54 @@ mod ip_service; mod test_macros; #[derive(Parser, Debug)] -#[command(version, about, long_about = None)] +#[command(ignore_errors(true), version, about, long_about = None)] struct Args { - #[arg(short, long, default_value = "~/.config/multiwan-dyndns/config.json")] - config_file: PathBuf, + #[arg(short, long)] + config_file: Option<PathBuf>, } -fn main() { +impl Args { + fn get_config_files(&self) -> Vec<PathBuf> { + match self.config_file { + Some(ref config_file) => vec![config_file.to_path_buf()], + None => DefaultConfigFile::default().paths, + } + } +} + +struct DefaultConfigFile { + paths: Vec<PathBuf>, +} + +impl DefaultConfigFile { + fn user_home_config() -> AppResult<Option<PathBuf>> { + let home = my_home().map_err(AppError::UnableToGetHomeDirectory)?; + match home { + None => Ok(None), + Some(mut path) => { + path.push(".config/multiwan-dyndns/config.json"); + Ok(Some(path)) + } + } + } +} +impl Default for DefaultConfigFile { + fn default() -> Self { + let mut paths = Vec::new(); + paths.push(PathBuf::from("/etc/multiwan-dyndns.json")); + if let Some(user_home) = Self::user_home_config().unwrap() { + paths.push(user_home); + } + Self { paths } + } +} + +#[tokio::main] +async fn main() { env_logger::init(); let args = Args::parse(); - match run(args) { + match run(args).await { Ok(_) => exit(0), Err(e) => { log::error!("{}", e); @@ -32,10 +73,12 @@ fn main() { } } -fn run(args: Args) -> AppResult<()> { - let config = Config::load(&args.config_file)?; +async fn run(args: Args) -> AppResult<()> { + let config = Config::load(args.get_config_files())?; + let client = ClientBuilder::new().build()?; for network in config.networks { - // let ip = IpService::resolve(&network.ip_service)?; + let ip = network.ip_service.resolve(&client).await?; + info!("{:?}: {}", network.interface, ip); // for dyndns in network.providers { // DynDnsService::register(&dyndns, &ip)?; // } @@ -43,3 +86,44 @@ fn run(args: Args) -> AppResult<()> { Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + use homedir::my_home; + use std::ffi::OsString; + use std::iter; + use std::path::Path; + + macro_rules! assert_contains_config { + ($config:expr, $expected:expr) => { + assert!( + $config.contains(&$expected.to_path_buf()), + "Expected {} path {:?}\nActual paths: {:?}", + stringify!($expected), + $expected, + $config + ); + }; + } + + test! { + fn verify_default_config_path_is_in_home_directory() { + let args = Args::parse_from(iter::empty::<OsString>()); + + let global_config = Path::new("/etc/multiwan-dyndns.json"); + let user_config_path = format!("{}/.config/multiwan-dyndns/config.json", my_home()?.unwrap().to_string_lossy()); + let user_config = Path::new(&user_config_path); + + let actual = args.get_config_files(); + assert_contains_config!(actual, user_config); + assert_contains_config!(actual, global_config); + } + } + + #[tokio::test] + async fn verify_it_actually_runs() { + let args = vec!["multiwan-dyndns", "--config-file", "test/noop.json"]; + run(Args::parse_from(args)).await.expect("app didn't run!"); + } +} |
