use std::collections::HashMap;
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::{Duration, SystemTime};
use tokio::sync::Mutex;
#[derive(Debug, Clone)]
pub struct ResolverStats {
pub avg_response_time_ms: f64,
pub success_count: u64,
pub failure_count: u64,
pub timeout_count: u64,
pub last_used: SystemTime,
weight_factor: f64,
}
impl ResolverStats {
pub fn new() -> Self {
Self {
avg_response_time_ms: 0.0,
success_count: 0,
failure_count: 0,
timeout_count: 0,
last_used: SystemTime::now(),
weight_factor: 0.2, }
}
pub fn update_response_time(&mut self, response_time: Duration) {
let response_time_ms = response_time.as_millis() as f64;
if self.avg_response_time_ms == 0.0 {
self.avg_response_time_ms = response_time_ms;
} else {
self.avg_response_time_ms = (1.0 - self.weight_factor) * self.avg_response_time_ms
+ self.weight_factor * response_time_ms;
}
}
pub fn record_success(&mut self, response_time: Duration) {
self.success_count += 1;
self.last_used = SystemTime::now();
self.update_response_time(response_time);
}
pub fn record_failure(&mut self) {
self.failure_count += 1;
self.last_used = SystemTime::now();
}
pub fn record_timeout(&mut self) {
self.timeout_count += 1;
self.last_used = SystemTime::now();
}
}
impl Default for ResolverStats {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct GlobalStats {
pub total_queries: u64,
pub total_successful: u64,
pub total_failed: u64,
pub total_timeouts: u64,
pub client_queries: u64,
pub cache_hits: u64,
pub cache_misses: u64,
pub active_udp_clients: u64,
pub active_tcp_clients: u64,
pub active_inflight_queries: u64,
pub udp_receive_errors: u64,
pub tcp_accept_errors: u64,
pub resolver_stats: HashMap<SocketAddr, ResolverStats>,
}
impl GlobalStats {
pub fn new() -> Self {
Self {
total_queries: 0,
total_successful: 0,
total_failed: 0,
total_timeouts: 0,
client_queries: 0,
cache_hits: 0,
cache_misses: 0,
active_udp_clients: 0,
active_tcp_clients: 0,
active_inflight_queries: 0,
udp_receive_errors: 0,
tcp_accept_errors: 0,
resolver_stats: HashMap::new(),
}
}
pub fn record_success(&mut self, resolver: SocketAddr, response_time: Duration) {
self.total_queries += 1;
self.total_successful += 1;
let stats = self.resolver_stats.entry(resolver).or_default();
stats.record_success(response_time);
}
pub fn record_failure(&mut self, resolver: SocketAddr) {
self.total_queries += 1;
self.total_failed += 1;
let stats = self.resolver_stats.entry(resolver).or_default();
stats.record_failure();
}
pub fn record_timeout(&mut self, resolver: SocketAddr) {
self.total_queries += 1;
self.total_timeouts += 1;
let stats = self.resolver_stats.entry(resolver).or_default();
stats.record_timeout();
}
pub fn get_resolver_stats(&self, resolver: &SocketAddr) -> Option<&ResolverStats> {
self.resolver_stats.get(resolver)
}
pub fn record_client_query(&mut self) {
self.client_queries += 1;
}
pub fn record_cache_hit(&mut self) {
self.cache_hits += 1;
}
pub fn record_cache_miss(&mut self) {
self.cache_misses += 1;
}
pub fn increment_active_udp_clients(&mut self) {
self.active_udp_clients += 1;
}
pub fn decrement_active_udp_clients(&mut self) {
if self.active_udp_clients > 0 {
self.active_udp_clients -= 1;
}
}
pub fn increment_active_tcp_clients(&mut self) {
self.active_tcp_clients += 1;
}
pub fn decrement_active_tcp_clients(&mut self) {
if self.active_tcp_clients > 0 {
self.active_tcp_clients -= 1;
}
}
pub fn increment_active_inflight_queries(&mut self) {
self.active_inflight_queries += 1;
}
pub fn decrement_active_inflight_queries(&mut self) {
if self.active_inflight_queries > 0 {
self.active_inflight_queries -= 1;
}
}
pub fn increment_udp_receive_errors(&mut self) {
self.udp_receive_errors += 1;
}
pub fn increment_tcp_accept_errors(&mut self) {
self.tcp_accept_errors += 1;
}
pub fn get_resolvers_by_speed(&self) -> Vec<(SocketAddr, f64)> {
let mut resolvers: Vec<(SocketAddr, f64)> = self
.resolver_stats
.iter()
.map(|(addr, stats)| (*addr, stats.avg_response_time_ms))
.collect();
resolvers.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(std::cmp::Ordering::Equal));
resolvers
}
}
impl Default for GlobalStats {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct SharedStats {
inner: Arc<Mutex<GlobalStats>>,
}
impl SharedStats {
pub fn new() -> Self {
Self {
inner: Arc::new(Mutex::new(GlobalStats::new())),
}
}
pub async fn record_success(&self, resolver: SocketAddr, response_time: Duration) {
let mut stats = self.inner.lock().await;
stats.record_success(resolver, response_time);
}
pub async fn record_failure(&self, resolver: SocketAddr) {
let mut stats = self.inner.lock().await;
stats.record_failure(resolver);
}
pub async fn record_timeout(&self, resolver: SocketAddr) {
let mut stats = self.inner.lock().await;
stats.record_timeout(resolver);
}
pub async fn get_stats(&self) -> GlobalStats {
let stats = self.inner.lock().await;
stats.clone()
}
pub async fn record_client_query(&self) {
let mut stats = self.inner.lock().await;
stats.record_client_query();
}
pub async fn record_cache_hit(&self) {
let mut stats = self.inner.lock().await;
stats.record_cache_hit();
}
pub async fn record_cache_miss(&self) {
let mut stats = self.inner.lock().await;
stats.record_cache_miss();
}
pub async fn increment_active_udp_clients(&self) {
let mut stats = self.inner.lock().await;
stats.increment_active_udp_clients();
}
pub async fn decrement_active_udp_clients(&self) {
let mut stats = self.inner.lock().await;
stats.decrement_active_udp_clients();
}
pub async fn increment_active_tcp_clients(&self) {
let mut stats = self.inner.lock().await;
stats.increment_active_tcp_clients();
}
pub async fn decrement_active_tcp_clients(&self) {
let mut stats = self.inner.lock().await;
stats.decrement_active_tcp_clients();
}
pub async fn increment_active_inflight_queries(&self) {
let mut stats = self.inner.lock().await;
stats.increment_active_inflight_queries();
}
pub async fn decrement_active_inflight_queries(&self) {
let mut stats = self.inner.lock().await;
stats.decrement_active_inflight_queries();
}
pub async fn get_resolvers_by_speed(&self) -> Vec<(SocketAddr, f64)> {
let stats = self.inner.lock().await;
stats.get_resolvers_by_speed()
}
pub async fn increment_udp_receive_errors(&self) {
let mut stats = self.inner.lock().await;
stats.increment_udp_receive_errors();
}
pub async fn increment_tcp_accept_errors(&self) {
let mut stats = self.inner.lock().await;
stats.increment_tcp_accept_errors();
}
}
impl Default for SharedStats {
fn default() -> Self {
Self::new()
}
}