use std::time::Duration;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum HealthStatus {
Healthy,
Degraded,
Unhealthy,
Error,
NotApplicable,
}
impl std::fmt::Display for HealthStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
Self::Healthy => "HEALTHY",
Self::Degraded => "DEGRADED",
Self::Unhealthy => "UNHEALTHY",
Self::Error => "ERROR",
Self::NotApplicable => "N/A",
};
write!(f, "{s}")
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum CheckSeverity {
Info,
Warning,
Error,
Critical,
}
impl std::fmt::Display for CheckSeverity {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
Self::Info => "INFO",
Self::Warning => "WARNING",
Self::Error => "ERROR",
Self::Critical => "CRITICAL",
};
write!(f, "{s}")
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct HealthCheckResult {
pub status: HealthStatus,
pub message: String,
pub severity: CheckSeverity,
pub details: Option<String>,
pub latency: Option<Duration>,
}
impl HealthCheckResult {
#[must_use]
pub fn healthy(message: impl Into<String>) -> Self {
Self {
status: HealthStatus::Healthy,
message: message.into(),
severity: CheckSeverity::Info,
details: None,
latency: None,
}
}
#[must_use]
pub fn degraded(message: impl Into<String>) -> Self {
Self {
status: HealthStatus::Degraded,
message: message.into(),
severity: CheckSeverity::Warning,
details: None,
latency: None,
}
}
#[must_use]
pub fn unhealthy(message: impl Into<String>) -> Self {
Self {
status: HealthStatus::Unhealthy,
message: message.into(),
severity: CheckSeverity::Error,
details: None,
latency: None,
}
}
#[must_use]
pub fn error(message: impl Into<String>) -> Self {
Self {
status: HealthStatus::Error,
message: message.into(),
severity: CheckSeverity::Critical,
details: None,
latency: None,
}
}
#[must_use]
pub fn with_details(mut self, details: impl Into<String>) -> Self {
self.details = Some(details.into());
self
}
#[must_use]
pub fn with_latency(mut self, latency: Duration) -> Self {
self.latency = Some(latency);
self
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SslCheckResult {
pub status: HealthStatus,
pub message: String,
pub severity: CheckSeverity,
pub details: Option<String>,
pub expires_at: Option<chrono::DateTime<chrono::Utc>>,
pub days_until_expiry: Option<i64>,
pub issuer: Option<String>,
pub subject: Option<String>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PortCheckResult {
pub status: HealthStatus,
pub message: String,
pub severity: CheckSeverity,
pub details: Option<String>,
pub port: u16,
pub address: String,
pub is_listening: bool,
pub latency: Option<Duration>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct DnsCheckResult {
pub status: HealthStatus,
pub message: String,
pub severity: CheckSeverity,
pub details: Option<String>,
pub hostname: String,
pub addresses: Vec<String>,
pub resolution_time: Option<Duration>,
}
#[derive(Debug, Clone)]
#[allow(clippy::struct_excessive_bools)]
pub struct NetworkCheckOptions {
pub check_upstreams: bool,
pub check_ssl: bool,
pub check_ports: bool,
pub check_dns: bool,
pub timeout: Duration,
pub retries: usize,
pub parallel: bool,
pub continue_on_error: bool,
}
impl Default for NetworkCheckOptions {
fn default() -> Self {
Self {
check_upstreams: true,
check_ssl: true,
check_ports: true,
check_dns: true,
timeout: Duration::from_secs(5),
retries: 3,
parallel: true,
continue_on_error: true,
}
}
}
impl NetworkCheckOptions {
#[must_use]
pub fn upstreams_only() -> Self {
Self {
check_upstreams: true,
check_ssl: false,
check_ports: false,
check_dns: false,
..Default::default()
}
}
#[must_use]
pub fn ssl_only() -> Self {
Self {
check_upstreams: false,
check_ssl: true,
check_ports: false,
check_dns: false,
..Default::default()
}
}
#[must_use]
pub fn ports_only() -> Self {
Self {
check_upstreams: false,
check_ssl: false,
check_ports: true,
check_dns: false,
..Default::default()
}
}
#[must_use]
pub fn dns_only() -> Self {
Self {
check_upstreams: false,
check_ssl: false,
check_ports: false,
check_dns: true,
..Default::default()
}
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct DnsValidationResult {
pub domain: String,
pub ns_records: Option<Vec<String>>,
pub soa_record: Option<String>,
pub is_valid: bool,
}