aboutsummaryrefslogtreecommitdiff
path: root/src/check.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/check.rs')
-rw-r--r--src/check.rs77
1 files changed, 50 insertions, 27 deletions
diff --git a/src/check.rs b/src/check.rs
index 4b6bc95..a979e96 100644
--- a/src/check.rs
+++ b/src/check.rs
@@ -1,16 +1,24 @@
-use crate::{log::update_service, Check, Config, Success, GLOBAL_ERROR, STATUS};
+use crate::{log::update_service, Config, Status, GLOBAL_ERROR, STATUS};
use anyhow::{anyhow, bail, Context, Result};
+use chrono::Utc;
use futures::{stream::FuturesUnordered, StreamExt};
use log::info;
-use std::{
- sync::Arc,
- time::{Duration, Instant},
-};
+use serde::Deserialize;
+use std::{sync::Arc, time::Duration};
use tokio::{
process::Command,
time::{sleep, timeout},
};
+#[derive(Debug, Deserialize)]
+#[serde(rename_all = "snake_case")]
+pub enum Check {
+ Systemd(String),
+ Pacman(String),
+ Http { title: Option<String>, url: String },
+ Shell { title: String, command: String },
+}
+
pub async fn check_loop(config: Arc<Config>, i: usize) {
loop {
check_service(&config, i).await;
@@ -27,19 +35,18 @@ async fn check_service(config: &Arc<Config>, i: usize) {
Ok(Err(e)) => Err(e),
Err(_) => Err(anyhow!("timed out")),
};
- let r2 = r
- .as_ref()
- .err()
- .map(|e| (format!("{e}"), format!("{e:?}")))
- .to_owned();
info!("check {i}:{j} => {r:?}");
+ let status = Status {
+ time: Utc::now(),
+ status: r.map_err(|e| format!("{e:?}")),
+ };
{
let mut g = STATUS.write().await;
- g.insert((i, j), r);
+ g.insert((i, j), status.clone());
}
let config = config.clone();
tokio::task::spawn(async move {
- if let Err(e) = update_service(config.clone(), i, j, r2).await {
+ if let Err(e) = update_service(config.clone(), i, j, status).await {
*GLOBAL_ERROR.write().await = Some(e);
}
})
@@ -49,29 +56,43 @@ async fn check_service(config: &Arc<Config>, i: usize) {
}
impl Check {
- pub async fn check(&self) -> Result<Success> {
+ pub async fn check(&self) -> Result<String> {
match self {
+ Check::Pacman(package) => {
+ let output = Command::new("pacman")
+ .arg("-Q")
+ .arg(package)
+ .output()
+ .await?;
+ output.status.exit_ok()?;
+ Ok(String::from_utf8(output.stdout)?)
+ }
Check::Systemd(sname) => {
let output = Command::new("systemctl")
.arg("show")
.arg("--no-pager")
.arg(sname)
.output()
- .await
- .context("systemctl")?;
+ .await?;
let output = String::from_utf8(output.stdout).context("systemctl output")?;
+ let mut active = "";
+ let mut sub = "";
for line in output.split("\n") {
if let Some((key, value)) = line.split_once("=") {
match key {
- "ActiveState" if value != "active" => {
- bail!("{value}")
- }
+ "ActiveState" => active = value,
+ "SubState" => sub = value,
_ => (),
}
}
}
- Ok(Success::default())
+ let s = format!("{active} ({sub})");
+ if active != "active" {
+ Err(anyhow!(s))
+ } else {
+ Ok(s)
+ }
}
Check::Shell { command, .. } => {
let args = shlex::split(&command).ok_or(anyhow!("command syntax invalid"))?;
@@ -81,21 +102,23 @@ impl Check {
.await;
match status {
- Ok(status) if status.success() => Ok(Success::default()),
+ Ok(status) if status.success() => Ok(Default::default()),
Ok(status) => bail!("failed with code {}", status.code().unwrap_or(1)),
Err(e) => bail!("command failed to execute: {e}"),
}
}
Check::Http { url, .. } => {
- let k = Instant::now();
let r = reqwest::get(url).await?;
- if !r.status().is_success() {
- bail!("http status: {}", r.status().as_str())
+ let s = format!(
+ "{} {}",
+ r.status().as_str(),
+ r.status().canonical_reason().unwrap_or_default()
+ );
+ if r.status().is_success() {
+ Ok(s)
+ } else {
+ bail!("{s}")
}
- Ok(Success {
- latency: Some(k.elapsed()),
- ..Default::default()
- })
}
}
}