diff --git a/src/checker/app.rs b/src/checker/app.rs index 22ed61ba..66bbf127 100644 --- a/src/checker/app.rs +++ b/src/checker/app.rs @@ -1,57 +1,41 @@ +use std::path::PathBuf; use std::sync::Arc; +use anyhow::Context; +use clap::Parser; + use super::config::Configuration; use super::console::Console; -use super::service::{CheckError, Service}; +use super::service::{CheckResult, Service}; use crate::checker::config::parse_from_json; -pub const NUMBER_OF_ARGUMENTS: usize = 2; +#[derive(Parser, Debug)] +#[clap(author, version, about, long_about = None)] +struct Args { + config_path: PathBuf, +} /// # Errors /// -/// If some checks fails it will return a vector with all failing checks. -/// -/// # Panics -/// -/// Will panic if: -/// -/// - It can't read the json configuration file. -/// - The configuration file is invalid. -pub async fn run() -> Result<(), Vec> { - let args = parse_arguments(); - let config = setup_config(&args); +/// Will return an error if it can't read or parse the configuration file. +pub async fn run() -> anyhow::Result> { + let args = Args::parse(); + + let config = setup_config(&args)?; + let console_printer = Console {}; + let service = Service { config: Arc::new(config), console: console_printer, }; - service.run_checks().await -} - -pub struct Arguments { - pub config_path: String, -} - -fn parse_arguments() -> Arguments { - let args: Vec = std::env::args().collect(); - - if args.len() < NUMBER_OF_ARGUMENTS { - eprintln!("Usage: cargo run --bin tracker_checker "); - eprintln!("For example: cargo run --bin tracker_checker ./share/default/config/tracker_checker.json"); - std::process::exit(1); - } - - let config_path = &args[1]; - - Arguments { - config_path: config_path.to_string(), - } + Ok(service.run_checks().await) } -fn setup_config(args: &Arguments) -> Configuration { - let file_content = std::fs::read_to_string(args.config_path.clone()) - .unwrap_or_else(|_| panic!("Can't read config file {}", args.config_path)); +fn setup_config(args: &Args) -> anyhow::Result { + let file_content = + std::fs::read_to_string(&args.config_path).with_context(|| format!("can't read config file {:?}", args.config_path))?; - parse_from_json(&file_content).expect("Invalid config format") + parse_from_json(&file_content).context("invalid config format") } diff --git a/src/checker/config.rs b/src/checker/config.rs index aaf611bb..5cfee076 100644 --- a/src/checker/config.rs +++ b/src/checker/config.rs @@ -1,3 +1,4 @@ +use std::error::Error; use std::fmt; use std::net::SocketAddr; @@ -43,6 +44,8 @@ pub enum ConfigurationError { InvalidUrl(url::ParseError), } +impl Error for ConfigurationError {} + impl fmt::Display for ConfigurationError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { diff --git a/src/checker/service.rs b/src/checker/service.rs index 25471637..fd93ed8c 100644 --- a/src/checker/service.rs +++ b/src/checker/service.rs @@ -14,6 +14,8 @@ pub struct Service { pub(crate) console: Console, } +pub type CheckResult = Result<(), CheckError>; + #[derive(Debug)] pub enum CheckError { UdpError, @@ -25,7 +27,7 @@ impl Service { /// # Errors /// /// Will return OK is all checks pass or an array with the check errors. - pub async fn run_checks(&self) -> Result<(), Vec> { + pub async fn run_checks(&self) -> Vec { self.console.println("Running checks for trackers ..."); self.check_udp_trackers(); @@ -50,23 +52,19 @@ impl Service { } } - async fn run_health_checks(&self) -> Result<(), Vec> { + async fn run_health_checks(&self) -> Vec { self.console.println("Health checks ..."); - let mut check_errors = vec![]; + let mut check_results = vec![]; for health_check_url in &self.config.health_checks { match self.run_health_check(health_check_url.clone()).await { - Ok(()) => {} - Err(err) => check_errors.push(err), + Ok(()) => check_results.push(Ok(())), + Err(err) => check_results.push(Err(err)), } } - if check_errors.is_empty() { - Ok(()) - } else { - Err(check_errors) - } + check_results } fn check_udp_tracker(&self, address: &SocketAddr) {