1
0
mirror of https://github.com/pcvolkmer/checkbar.git synced 2025-04-19 19:16:50 +00:00

Add commands to be executed on mouse click

This commit is contained in:
Paul-Christian Volkmer 2022-03-05 14:14:30 +01:00
parent fb312d2102
commit fbc5237a8e
4 changed files with 1142 additions and 24 deletions

1040
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -2,13 +2,13 @@
name = "checkbar" name = "checkbar"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
author = "Paul-Christian Volkmer <code@pcvolkmer.de>"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
dirs = "4" dirs = "4"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "*"
chrono = { version = "*", features = ["serde"] } chrono = { version = "*", features = ["serde"] }
tokio = { version = "1", features = ["full"] } tokio = { version = "1", features = ["full"] }
toml = "*" toml = "*"

View File

@ -32,3 +32,19 @@ You can optionally specify `check_type`:
* `Html`: Default value, checks if a request is succeessful and returns HTTP OK - 200. * `Html`: Default value, checks if a request is succeessful and returns HTTP OK - 200.
* `Actuator`: Like `Html`, but checks if _Actuator_ shows that the application is up and running. * `Actuator`: Like `Html`, but checks if _Actuator_ shows that the application is up and running.
=== Execute commands
_This feature is experimental and starts further commands only after previous commands have been finished._
You can also specify a command to be executed when a mouse click occurs on a checked host.
Use `click_cmd` to specifiy the command to be executed, e.g.
----
...
[[checks]]
name = "Host 1"
url = "http://host1.example.com"
click_cmd = "xterm -e ssh admin@host1.example.com"
...
----

View File

@ -13,6 +13,7 @@ struct CheckConfig {
name: String, name: String,
url: String, url: String,
check_type: Option<CheckType>, check_type: Option<CheckType>,
click_cmd: Option<String>,
} }
#[derive(Deserialize)] #[derive(Deserialize)]
@ -26,6 +27,11 @@ struct ActuatorResponse {
status: String, status: String,
} }
#[derive(Deserialize)]
struct ClickEvent {
name: String,
}
struct CheckResult { struct CheckResult {
name: String, name: String,
state: CheckState, state: CheckState,
@ -40,8 +46,8 @@ impl Display for CheckResult {
}; };
write!( write!(
f, f,
"{{\"full_text\":\"{}\",\"separator_block_width\":16,\"color\":\"{}\"}}", "{{\"full_text\":\"{}\",\"name\":\"{}\",\"separator_block_width\":16,\"color\":\"{}\"}}",
self.name, color self.name, self.name, color
) )
} }
} }
@ -96,30 +102,86 @@ async fn print_states(check_configs: &[CheckConfig]) {
println!("{}],", entries.join(",")); println!("{}],", entries.join(","));
} }
#[tokio::main(flavor = "current_thread")] async fn get_config() -> Config {
async fn main() { let home_dir = dirs::home_dir().unwrap();
println!("{{\"version\":1,\"click_events\":false}}"); match std::fs::read_to_string(format!(
println!("["); "{}/.checkbar.toml",
loop { home_dir.to_str().unwrap_or("")
let home_dir = dirs::home_dir().unwrap(); )) {
let config = match std::fs::read_to_string(format!( Ok(config) => match toml::from_str(config.as_str()) {
"{}/.checkbar.toml", Ok(config) => config,
home_dir.to_str().unwrap_or("")
)) {
Ok(config) => match toml::from_str(config.as_str()) {
Ok(config) => config,
Err(_e) => Config {
interval: None,
checks: vec![],
},
},
Err(_e) => Config { Err(_e) => Config {
interval: None, interval: None,
checks: vec![], checks: vec![],
}, },
}; },
Err(_e) => Config {
print_states(&config.checks).await; interval: None,
std::thread::sleep(Duration::from_secs(config.interval.unwrap_or(60))); checks: vec![],
},
} }
} }
async fn get_click_cmd(name: String) -> Option<String> {
for check in get_config().await.checks {
if check.name == name {
return check.click_cmd;
}
}
None
}
async fn run_click_cmd(cmd: String) {
let _r = match std::process::Command::new("sh")
.stdin(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.spawn()
{
Ok(mut child) => {
use std::io::Write;
let _r = child.stdin.as_mut().unwrap().write_all(cmd.as_bytes());
child.wait()
}
Err(e) => Err(e),
};
}
#[tokio::main(flavor = "multi_thread", worker_threads = 2)]
async fn main() {
println!("{{\"version\":1,\"click_events\":true}}");
println!("[");
let inputs = tokio::task::spawn(async {
let stdin = std::io::stdin();
loop {
let mut input = String::new();
if stdin.read_line(&mut input).is_err() {
continue;
}
if input.is_empty() {
continue;
}
// Remove leading comma
let input = input.replace(",{", "{");
if let Ok(click_event) = serde_json::from_str::<ClickEvent>(input.as_str()) {
if let Some(click_cmd) = get_click_cmd(click_event.name).await {
run_click_cmd(click_cmd).await;
}
}
}
});
let checks = tokio::task::spawn(async {
loop {
let config = get_config().await;
print_states(&config.checks).await;
std::thread::sleep(Duration::from_secs(config.interval.unwrap_or(60)));
}
});
let _r = tokio::join!(inputs, checks);
}