//! CAI-Watchdog is a lightweigth watchdog for *nix and Windows //! Author: Alexander I. Chebykin (CAI) #[macro_use] extern crate ini; extern crate exitcode; use std::env; use std::ffi::OsStr; use std::path::Path; use std::thread; use std::time::Duration; use sysinfo::System; mod mods; use crate::mods::mod_debug::*; use crate::mods::mod_fs::*; use crate::mods::mod_i18n::*; use crate::mods::mod_os::*; use crate::mods::mod_tasks::*; /// Check rule /// /// # Arguments /// /// * `rule` Rule to be checked /// /// # Example /// /// ``` /// if check(&tasks[i]).await { /// println!("ok"); /// } else { /// println!("uh-oh... something wrong!"); /// } /// ``` async fn check(rule: &Rule) -> bool { return if rule.uri.to_string() != "".to_string() { check_uri(rule.uri.clone()).await } else { check_process(rule.process.clone()) }; } /// Check is process running /// /// # Arguments /// /// * `process_name` Process name to be checked /// /// # Example /// /// ``` /// if check_process("httpd".to_string()).await { /// println!("ok"); /// } else { /// println!("uh-oh... something wrong!"); /// } /// ``` fn check_process(process_name: String) -> bool { let mut sys = System::new_all(); let mut result: bool = false; sys.refresh_all(); for _process in sys.processes_by_exact_name(OsStr::new(&process_name)) { result = true; } return result; } /// Checks web-service availability /// /// # Arguments /// /// * `uri` - Service URI to be checked /// /// # Example /// /// ``` /// if check_uri("https://somesite.local/api/v1/".to_string()).await { /// println!("ok"); /// } else { /// println!("uh-oh... something wrong!"); /// } /// ``` async fn check_uri(uri: String) -> bool { if let Err(_e) = reqwest::get(uri).await { return false; } else { return true; } } /// Print help and program version information /// /// # Arguments /// /// * `args` - Command-line arguments /// /// # Example /// /// ``` /// let args: Vec = env::args().collect(); /// /// print_help(args.clone()); /// ``` fn print_help(args: Vec) { let locale = Locale::new(); if cfg!(windows) { if args.len() > 1 && (args[1].to_string() == "/help".to_string() || args[1].to_string() == "/?".to_string()) { const VERSION: &str = env!("CARGO_PKG_VERSION"); println!("CAI Watchdog {} {}", locale.t().ver, VERSION); println!(""); println!("Usage: {} [/? | /help | /v | /ver | config_file]", &args[0]); println!(" /? | /help : {}", locale.t().this_help_message); println!(" /v | /ver : {}", locale.t().version_info); println!(" config_file : {}", locale.t().configuration_file); std::process::exit(exitcode::OK); } else if args.len() > 1 && (args[1].to_string() == "/ver".to_string() || args[1].to_string() == "/v".to_string()) { const VERSION: &str = env!("CARGO_PKG_VERSION"); println!("CAI Watchdog {} {}", locale.t().ver, VERSION); std::process::exit(exitcode::OK); } } else { if args.len() > 1 && (args[1].to_string() == "--help".to_string() || args[1].to_string() == "-h".to_string()) { const VERSION: &str = env!("CARGO_PKG_VERSION"); println!("CAI Watchdog {} {}", locale.t().ver, VERSION); println!(""); println!("{}: {} [-h | --help | -v | --ver | config_file]", locale.t().usage, &args[0]); println!(" -h | --help : {}", locale.t().this_help_message); println!(" -v | --ver : {}", locale.t().version_info); println!(" config_file : {}", locale.t().configuration_file); std::process::exit(exitcode::OK); } else if args.len() > 1 && (args[1].to_string() == "--ver".to_string() || args[1].to_string() == "-v".to_string()) { const VERSION: &str = env!("CARGO_PKG_VERSION"); println!("CAI Watchdog {} {}", locale.t().ver, VERSION); std::process::exit(exitcode::OK); } } } fn main() { let locale = Locale::new(); let args: Vec = env::args().collect(); print_help(args.clone()); let mut config_file = get_exe_path(); if cfg!(windows) { config_file = format!("{}\\cai-watchdog.ini", config_file); } else { config_file = "/etc/cai-watchdog/cai-watchdog.conf".to_string(); } let cfg_file = if args.len() > 1 { &args[1] } else { &config_file }; if !Path::new(cfg_file).exists() { println!("\u{26a0} {}! {}.", locale.t().error, locale.t().cant_find_config_file ); println!("{}", locale.t().exiting); std::process::exit(exitcode::CONFIG); } let cfg = ini!(cfg_file); let check_interval = if cfg["main"].contains_key("check_interval") { cfg["main"]["check_interval"].clone().unwrap().parse::().unwrap() * 1000 } else { 10000 }; let rules_count = if cfg["main"].contains_key("check_interval") { cfg["main"]["rules_count"].clone().unwrap().parse::().unwrap() } else { 0 }; let mut tasks_prc = vec![]; let mut tasks_web = vec![]; for i in 1..rules_count + 1 { let service = if cfg[&format!("rule{}", i)].contains_key("service") { cfg[&format!("rule{}", i)]["service"].clone().unwrap() } else { format!("Service {}", i) }; let uri = if cfg[&format!("rule{}", i)].contains_key("uri") { cfg[&format!("rule{}", i)]["uri"].clone().unwrap() } else { "".to_string() }; let process = if cfg[&format!("rule{}", i)].contains_key("process") { cfg[&format!("rule{}", i)]["process"].clone().unwrap() } else { "".to_string() }; let email = if cfg[&format!("rule{}", i)].contains_key("email") { cfg[&format!("rule{}", i)]["email"].clone().unwrap() } else { "".to_string() }; let command = if cfg[&format!("rule{}", i)].contains_key("command") { cfg[&format!("rule{}", i)]["command"].clone().unwrap() } else { "".to_string() }; debug_log(format!("rule {}", i)); debug_log(format!("service {}", service)); debug_log(format!("uri {}", uri)); debug_log(format!("process {}", process)); debug_log(format!("email {}", email)); debug_log(format!("command {}", command)); if uri != "".to_string() { tasks_web.push( Rule{ service: service, uri: uri, process: process, email: email, command: command, last_state: false, } ); } else { tasks_prc.push( Rule{ service: service, uri: uri, process: process, email: email, command: command, last_state: false, } ); } } let on_start_command = if cfg["main"].contains_key("on_start_command") { cfg["main"]["on_start_command"].clone().unwrap() } else { "".to_string() }; debug_log(format!("\u{2139} {}", locale.t().service_started)); if on_start_command.to_string() != "" { execute(on_start_command); } let mut just_started_web = true; std::thread::spawn(move || { loop { for i in 0..tasks_web.len() { let rt = tokio::runtime::Runtime::new().unwrap(); rt.block_on(async { if check(&tasks_web[i]).await { execute_web_task(&mut tasks_web[i], true, just_started_web); } else { execute_web_task(&mut tasks_web[i], false, just_started_web); } }); } just_started_web = false; thread::sleep(Duration::from_millis(check_interval)); } }); let mut just_started_prc = true; loop { for i in 0..tasks_prc.len() { let rt = tokio::runtime::Runtime::new().unwrap(); rt.block_on(async { if check(&tasks_prc[i]).await { execute_os_task(&mut tasks_prc[i], true, just_started_prc); } else { execute_os_task(&mut tasks_prc[i], false, just_started_prc); } }); } just_started_prc = false; thread::sleep(Duration::from_millis(check_interval)); } }