use crate::error::NetPulseError;
use serde::{Deserialize, Serialize};
use std::path::Path;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NetPulseConfig {
#[serde(default)]
pub targets: Vec<String>,
#[serde(default = "default_interval_ms")]
pub interval_ms: u64,
#[serde(default = "default_timeout_ms")]
pub timeout_ms: u64,
#[serde(default = "default_window_size")]
pub window_size: usize,
#[serde(default = "default_report_every")]
pub report_every: u64,
#[serde(default = "default_probe_type")]
pub probe_type: ProbeType,
#[serde(default = "default_tcp_port")]
pub tcp_port: u16,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum ProbeType {
Icmp,
Tcp,
Udp,
}
impl std::fmt::Display for ProbeType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ProbeType::Icmp => write!(f, "icmp"),
ProbeType::Tcp => write!(f, "tcp"),
ProbeType::Udp => write!(f, "udp"),
}
}
}
impl std::str::FromStr for ProbeType {
type Err = NetPulseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"icmp" => Ok(ProbeType::Icmp),
"tcp" => Ok(ProbeType::Tcp),
"udp" => Ok(ProbeType::Udp),
_ => Err(NetPulseError::ConfigError(format!(
"unknown probe type '{}', must be 'icmp', 'tcp', or 'udp'",
s
))),
}
}
}
fn default_interval_ms() -> u64 {
1000
}
fn default_timeout_ms() -> u64 {
3000
}
fn default_window_size() -> usize {
300
} fn default_report_every() -> u64 {
10
} fn default_probe_type() -> ProbeType {
ProbeType::Icmp
}
fn default_tcp_port() -> u16 {
80
}
impl Default for NetPulseConfig {
fn default() -> Self {
Self {
targets: vec![],
interval_ms: default_interval_ms(),
timeout_ms: default_timeout_ms(),
window_size: default_window_size(),
report_every: default_report_every(),
probe_type: default_probe_type(),
tcp_port: default_tcp_port(),
}
}
}
impl NetPulseConfig {
pub fn from_file(path: &Path) -> Result<Self, NetPulseError> {
if !path.exists() {
return Ok(Self::default());
}
let content = std::fs::read_to_string(path)
.map_err(|e| NetPulseError::ConfigError(format!("cannot read config file: {}", e)))?;
toml::from_str(&content)
.map_err(|e| NetPulseError::ConfigError(format!("invalid TOML: {}", e)))
}
}