modbus_relay/connection/stats/
connection.rs1use std::{
2 collections::HashMap,
3 net::SocketAddr,
4 time::{Duration, SystemTime},
5};
6
7use serde::Serialize;
8
9use super::{ClientStats, IpStats};
10
11#[derive(Debug, Serialize)]
12pub struct Stats {
13 pub total_connections: u64,
14 pub active_connections: usize,
15 pub total_requests: u64,
16 pub total_errors: u64,
17 pub requests_per_second: f64,
18 pub avg_response_time_ms: u64,
19 pub per_ip_stats: HashMap<SocketAddr, IpStats>,
20}
21
22impl Stats {
23 pub fn from_client_stats(stats: &HashMap<SocketAddr, ClientStats>) -> Self {
24 let mut total_active = 0;
25 let mut total_requests = 0;
26 let mut total_errors = 0;
27 let mut total_response_time = 0u64;
28 let mut response_time_count = 0;
29 let mut per_ip = HashMap::new();
30
31 for (addr, client) in stats {
33 total_active += client.active_connections;
34 total_requests += client.total_requests;
35 total_errors += client.total_errors;
36
37 if client.avg_response_time_ms > 0 {
38 total_response_time += client.avg_response_time_ms;
39 response_time_count += 1;
40 }
41
42 per_ip.insert(
43 *addr,
44 IpStats {
45 active_connections: client.active_connections,
46 total_requests: client.total_requests,
47 total_errors: client.total_errors,
48 last_active: client.last_active,
49 last_error: client.last_error,
50 avg_response_time_ms: client.avg_response_time_ms,
51 },
52 );
53 }
54
55 Self {
56 total_connections: total_active as u64,
57 active_connections: total_active,
58 total_requests,
59 total_errors,
60 requests_per_second: Self::calculate_requests_per_second(stats),
61 avg_response_time_ms: if response_time_count > 0 {
62 total_response_time / response_time_count
63 } else {
64 0
65 },
66 per_ip_stats: per_ip,
67 }
68 }
69
70 fn calculate_requests_per_second(stats: &HashMap<SocketAddr, ClientStats>) -> f64 {
71 let now = SystemTime::now();
72 let window = Duration::from_secs(60);
73 let mut recent_requests = 0;
74
75 for client in stats.values() {
76 if let Ok(duration) = now.duration_since(client.last_active)
77 && duration <= window
78 {
79 recent_requests += client.total_requests as usize;
80 }
81 }
82
83 recent_requests as f64 / window.as_secs_f64()
84 }
85}