CAI-Watchdog/src/main.rs
2025-01-28 01:23:23 +03:00

322 lines
8.7 KiB
Rust

//! CAI-Watchdog is a lightweigth watchdog for *nix and Windows
//! Author: Alexander I. Chebykin (CAI) <alex.chebykin@gmail.com>
#[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<String> = env::args().collect();
///
/// print_help(args.clone());
/// ```
fn print_help(args: Vec<String>) {
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<String> = 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::<u64>().unwrap() * 1000
} else {
10000
};
let rules_count = if cfg["main"].contains_key("check_interval") {
cfg["main"]["rules_count"].clone().unwrap().parse::<u8>().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));
}
}