Minimal functionality implemented
Minimal functionality implemented
This commit is contained in:
176
src/main.rs
Normal file
176
src/main.rs
Normal file
@@ -0,0 +1,176 @@
|
||||
#[macro_use]
|
||||
extern crate ini;
|
||||
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use std::process::Command;
|
||||
|
||||
/// Rule description structure
|
||||
pub struct Rule {
|
||||
/// Monitored service name
|
||||
pub service: String,
|
||||
/// Monitored URI
|
||||
pub address: String,
|
||||
/// E-mail address for messages
|
||||
pub email: String,
|
||||
/// This command will be executed on state change
|
||||
pub command: String,
|
||||
/// Last state
|
||||
pub last_state: bool,
|
||||
}
|
||||
|
||||
/// Checks service availability
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `uri` - Service URI to be checked
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// if if check("https://somesite.local/api/v1/".to_string()).await {
|
||||
/// println!("ok");
|
||||
/// } else {
|
||||
/// println!("uh-oh... something wrong!");
|
||||
/// }
|
||||
/// ```
|
||||
async fn check(uri: String) -> bool {
|
||||
if let Err(_e) = reqwest::get(uri).await {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// Output to console only in debug version
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `text` - Message text
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// debug_log("Debug version started".to_string());
|
||||
/// ```
|
||||
fn debug_log(text: String) {
|
||||
if cfg!(debug_assertions) {
|
||||
println!("{}", text);
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute shell command
|
||||
///
|
||||
/// In linux sh command interpreter will be called.
|
||||
/// In Windows PowerShell command interpreter will be called.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `command` - Command to be executed
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// execute("gedit".to_string());
|
||||
/// ```
|
||||
fn execute(command: String) {
|
||||
debug_log(format!("execute {}", command));
|
||||
|
||||
let output = if cfg!(target_os = "windows") {
|
||||
Command::new("powershell")
|
||||
.args(["-NoLogo", "-NonInteractive", "-Command", &command])
|
||||
.output()
|
||||
.expect("failed to execute process")
|
||||
} else {
|
||||
Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(&command)
|
||||
.output()
|
||||
.expect("failed to execute process")
|
||||
};
|
||||
|
||||
let result = output.stdout;
|
||||
debug_log(format!("{:?}", result));
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let cfg_file = if cfg!(windows) {
|
||||
"cai-watchdog.cfg"
|
||||
} else {
|
||||
"/etc/cai-watchdog.cfg"
|
||||
};
|
||||
|
||||
let cfg = ini!(cfg_file);
|
||||
|
||||
let check_interval = cfg["main"]["check_interval"].clone().unwrap().parse::<u64>().unwrap();
|
||||
let rules_count = cfg["main"]["rules_count"].clone().unwrap().parse::<u8>().unwrap();
|
||||
|
||||
let mut tasks = vec![];
|
||||
|
||||
for i in 1..rules_count + 1 {
|
||||
let service = cfg[&format!("{}{}", "rule", i)]["service"].clone().unwrap();
|
||||
let address = cfg[&format!("{}{}", "rule", i)]["address"].clone().unwrap();
|
||||
let email = cfg[&format!("{}{}", "rule", i)]["email"].clone().unwrap();
|
||||
let command = cfg[&format!("{}{}", "rule", i)]["command"].clone().unwrap();
|
||||
|
||||
debug_log(format!("rule {}", i));
|
||||
debug_log(format!("service {}", service));
|
||||
debug_log(format!("address {}", address));
|
||||
debug_log(format!("email {}", email));
|
||||
debug_log(format!("command {}", command));
|
||||
|
||||
tasks.push(
|
||||
Rule{
|
||||
service: cfg[&format!("{}{}", "rule", i)]["service"].clone().unwrap().to_string(),
|
||||
address: cfg[&format!("{}{}", "rule", i)]["address"].clone().unwrap().to_string(),
|
||||
email: cfg[&format!("{}{}", "rule", i)]["email"].clone().unwrap().to_string(),
|
||||
command: cfg[&format!("{}{}", "rule", i)]["command"].clone().unwrap().to_string(),
|
||||
last_state: false,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
loop {
|
||||
for i in 0..tasks.len() {
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
if check(tasks[i].address.clone()).await {
|
||||
if tasks[i].last_state != true {
|
||||
debug_log(format!("{} state changed to true", tasks[i].address));
|
||||
|
||||
let shell_cmd = tasks[i].command.to_string()
|
||||
.replace("<email>", &tasks[i].email)
|
||||
.replace("<header>", &format!("\"Service {} ({}) online\"", tasks[i].service, tasks[i].address))
|
||||
.replace("<message>", &format!("\"Service {} ({}) is now online\"", tasks[i].service, tasks[i].address));
|
||||
|
||||
debug_log(format!("execute {}", shell_cmd));
|
||||
|
||||
execute(shell_cmd);
|
||||
}
|
||||
|
||||
debug_log(format!("{} check is ok", tasks[i].address));
|
||||
|
||||
tasks[i].last_state = true
|
||||
} else {
|
||||
if tasks[i].last_state != false {
|
||||
debug_log(format!("{} state changed to false", tasks[i].address));
|
||||
|
||||
let shell_cmd = tasks[i].command.to_string()
|
||||
.replace("<email>", &tasks[i].email)
|
||||
.replace("<header>", &format!("\"Service {} ({}) offline\"", tasks[i].service, tasks[i].address))
|
||||
.replace("<message>", &format!("\"Service {} ({}) is now offline\"", tasks[i].service, tasks[i].address));
|
||||
|
||||
debug_log(format!("execute {}", shell_cmd));
|
||||
execute(shell_cmd);
|
||||
}
|
||||
|
||||
debug_log(format!("{} check failed", tasks[i].address));
|
||||
|
||||
tasks[i].last_state = false
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
thread::sleep(Duration::from_millis(check_interval));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user