use std::{collections::HashMap, fmt::Display}; use futures::{stream::FuturesOrdered, TryStreamExt}; use http::Http; use serde::Deserialize; use systemd::Systemd; use tcp::Tcp; use crate::{Error, Status}; pub mod http; pub mod systemd; pub mod tcp; #[derive(Debug, Clone, Deserialize)] pub struct Services { #[serde(flatten)] inner: HashMap, #[serde(skip, default = "Services::default_client")] client: reqwest::Client, } impl Services { pub fn new(services: HashMap) -> Self { let client = reqwest::Client::new(); Self { inner: services, client, } } fn default_client() -> reqwest::Client { reqwest::Client::new() } pub async fn check(&self) -> Result, Error> { let checks = self .inner .values() .map(|service| service.check(self.client.clone())) .collect::>() .try_collect::>() .await?; Ok(self .inner .keys() .cloned() .zip(checks) .collect::>()) } pub async fn check_one(&self, name: &str) -> Option> { Some(self.inner.get(name)?.check(self.client.clone()).await) } pub async fn check_filtered

(&self, mut predicate: P) -> Result, Error> where P: FnMut(&String) -> bool, { let checks = self .inner .iter() .filter_map(|(s, service)| predicate(s).then_some(service)) .map(|service| service.check(self.client.clone())) .collect::>() .try_collect::>() .await?; Ok(self .inner .keys() .cloned() .zip(checks) .collect::>()) } } #[derive(Debug, Clone, Deserialize)] #[serde(untagged)] pub enum Service { Http(Http), Tcp(Tcp), Systemd(Systemd), } impl Service { pub async fn check(&self, client: reqwest::Client) -> Result { match self { Service::Http(http) => http.check(client).await, Service::Tcp(tcp) => tcp.check().await, Service::Systemd(systemd) => systemd.check().await, } } } impl Display for Service { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Service::Http(http) => http.fmt(f), Service::Tcp(tcp) => tcp.fmt(f), Service::Systemd(systemd) => systemd.fmt(f), } } }