use serde::{Deserialize, Serialize};
use crate::error::Result;
use crate::api::{check_dns, DnsCheckRequest, Transport};
pub async fn benchmark_latency(req: &LatencyBenchRequest) -> Result<LatencyBenchResult> {
let mut results = Vec::new();
for bench_transport in &req.transports {
let mut samples_ms = Vec::new();
for _ in 0..req.rounds {
let dns_req = DnsCheckRequest {
domain: req.domain.clone(),
record_types: vec![req.record_type.clone()],
transport: bench_transport.transport.clone(),
timeout_secs: req.timeout_secs,
..Default::default()
};
let sample = match check_dns(&dns_req).await {
Ok(results) if !results.is_empty() => Some(results[0].duration_ms),
_ => None,
};
samples_ms.push(sample);
}
let valid_samples: Vec<u64> = samples_ms.iter().filter_map(|s| *s).collect();
let success_rate = if req.rounds > 0 {
valid_samples.len() as f64 / req.rounds as f64
} else {
0.0
};
let (min_ms, max_ms, avg_ms) = if !valid_samples.is_empty() {
let min = *valid_samples.iter().min().unwrap_or(&0);
let max = *valid_samples.iter().max().unwrap_or(&0);
let avg = valid_samples.iter().sum::<u64>() as f64 / valid_samples.len() as f64;
(Some(min), Some(max), Some(avg))
} else {
(None, None, None)
};
results.push(TransportLatency {
label: bench_transport.label.clone(),
transport: bench_transport.transport.clone(),
samples_ms,
min_ms,
max_ms,
avg_ms,
success_rate,
});
}
Ok(LatencyBenchResult {
domain: req.domain.clone(),
record_type: req.record_type.clone(),
results,
})
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LatencyBenchRequest {
pub domain: String,
pub record_type: String,
pub transports: Vec<BenchTransport>,
#[serde(default = "default_rounds")]
pub rounds: u32,
#[serde(default = "default_timeout")]
pub timeout_secs: u64,
}
fn default_rounds() -> u32 { 3 }
fn default_timeout() -> u64 { 5 }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BenchTransport {
pub transport: Transport,
pub label: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LatencyBenchResult {
pub domain: String,
pub record_type: String,
pub results: Vec<TransportLatency>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TransportLatency {
pub label: String,
pub transport: Transport,
pub samples_ms: Vec<Option<u64>>,
pub min_ms: Option<u64>,
pub max_ms: Option<u64>,
pub avg_ms: Option<f64>,
pub success_rate: f64,
}