use std::sync::Arc;
use crate::client::HttpClient;
use crate::error::Result;
use crate::types::{HealthCheck, QueryMeta, QueryOptions, ServiceEntry};
pub mod status {
pub const PASSING: &str = "passing";
pub const WARNING: &str = "warning";
pub const CRITICAL: &str = "critical";
pub const MAINTENANCE: &str = "maintenance";
pub const ANY: &str = "any";
}
pub struct Health {
client: Arc<HttpClient>,
}
impl Health {
pub fn new(client: Arc<HttpClient>) -> Self {
Self { client }
}
pub async fn node(&self, node: &str, opts: Option<&QueryOptions>) -> Result<(Vec<HealthCheck>, QueryMeta)> {
let path = format!("/v1/health/node/{}", node);
let mut builder = self.client.get(&path);
if let Some(opts) = opts {
builder = self.client.apply_query_options(builder, opts);
}
self.client.query(builder).await
}
pub async fn checks(&self, service: &str, opts: Option<&QueryOptions>) -> Result<(Vec<HealthCheck>, QueryMeta)> {
let path = format!("/v1/health/checks/{}", service);
let mut builder = self.client.get(&path);
if let Some(opts) = opts {
builder = self.client.apply_query_options(builder, opts);
}
self.client.query(builder).await
}
pub async fn service(
&self,
service: &str,
tag: Option<&str>,
passing_only: bool,
opts: Option<&QueryOptions>,
) -> Result<(Vec<ServiceEntry>, QueryMeta)> {
let mut path = format!("/v1/health/service/{}", service);
let mut params = Vec::new();
if let Some(t) = tag {
params.push(format!("tag={}", t));
}
if passing_only {
params.push("passing=true".to_string());
}
if !params.is_empty() {
path.push('?');
path.push_str(¶ms.join("&"));
}
let mut builder = self.client.get(&path);
if let Some(opts) = opts {
builder = self.client.apply_query_options(builder, opts);
}
self.client.query(builder).await
}
pub async fn service_healthy(
&self,
service: &str,
opts: Option<&QueryOptions>,
) -> Result<(Vec<ServiceEntry>, QueryMeta)> {
self.service(service, None, true, opts).await
}
pub async fn state(&self, state: &str, opts: Option<&QueryOptions>) -> Result<(Vec<HealthCheck>, QueryMeta)> {
let path = format!("/v1/health/state/{}", state);
let mut builder = self.client.get(&path);
if let Some(opts) = opts {
builder = self.client.apply_query_options(builder, opts);
}
self.client.query(builder).await
}
pub async fn state_passing(&self, opts: Option<&QueryOptions>) -> Result<(Vec<HealthCheck>, QueryMeta)> {
self.state(status::PASSING, opts).await
}
pub async fn state_warning(&self, opts: Option<&QueryOptions>) -> Result<(Vec<HealthCheck>, QueryMeta)> {
self.state(status::WARNING, opts).await
}
pub async fn state_critical(&self, opts: Option<&QueryOptions>) -> Result<(Vec<HealthCheck>, QueryMeta)> {
self.state(status::CRITICAL, opts).await
}
pub async fn state_any(&self, opts: Option<&QueryOptions>) -> Result<(Vec<HealthCheck>, QueryMeta)> {
self.state(status::ANY, opts).await
}
pub async fn connect(
&self,
service: &str,
tag: Option<&str>,
passing_only: bool,
opts: Option<&QueryOptions>,
) -> Result<(Vec<ServiceEntry>, QueryMeta)> {
let mut path = format!("/v1/health/connect/{}", service);
let mut params = Vec::new();
if let Some(t) = tag {
params.push(format!("tag={}", t));
}
if passing_only {
params.push("passing=true".to_string());
}
if !params.is_empty() {
path.push('?');
path.push_str(¶ms.join("&"));
}
let mut builder = self.client.get(&path);
if let Some(opts) = opts {
builder = self.client.apply_query_options(builder, opts);
}
self.client.query(builder).await
}
pub async fn ingress(
&self,
service: &str,
tag: Option<&str>,
passing_only: bool,
opts: Option<&QueryOptions>,
) -> Result<(Vec<ServiceEntry>, QueryMeta)> {
let mut path = format!("/v1/health/ingress/{}", service);
let mut params = Vec::new();
if let Some(t) = tag {
params.push(format!("tag={}", t));
}
if passing_only {
params.push("passing=true".to_string());
}
if !params.is_empty() {
path.push('?');
path.push_str(¶ms.join("&"));
}
let mut builder = self.client.get(&path);
if let Some(opts) = opts {
builder = self.client.apply_query_options(builder, opts);
}
self.client.query(builder).await
}
}
pub fn aggregate_status(checks: &[HealthCheck]) -> &'static str {
let mut critical = false;
let mut warning = false;
for check in checks {
match check.status.as_str() {
"critical" => critical = true,
"warning" => warning = true,
_ => {}
}
}
if critical {
status::CRITICAL
} else if warning {
status::WARNING
} else {
status::PASSING
}
}