use crate::report::client::{ClientStatsReport, OsInformation};
use nym_task::ShutdownToken;
use time::{OffsetDateTime, Time};
use tokio::sync::mpsc::UnboundedSender;
pub mod gateway_conn_statistics;
pub mod nym_api_statistics;
pub mod packet_statistics;
pub mod connection;
pub type ClientStatsReceiver = tokio::sync::mpsc::UnboundedReceiver<ClientStatsEvents>;
#[derive(Clone)]
pub struct ClientStatsSender {
stats_tx: Option<UnboundedSender<ClientStatsEvents>>,
shutdown_token: ShutdownToken,
}
impl ClientStatsSender {
pub fn new(
stats_tx: Option<UnboundedSender<ClientStatsEvents>>,
shutdown_token: ShutdownToken,
) -> Self {
ClientStatsSender {
stats_tx,
shutdown_token,
}
}
pub fn report(&self, event: ClientStatsEvents) {
if let Some(tx) = &self.stats_tx
&& let Err(err) = tx.send(event)
&& !self.shutdown_token.is_cancelled()
{
log::error!("Failed to send stats event: {err}");
}
}
}
pub enum ClientStatsEvents {
PacketStatistics(packet_statistics::PacketStatisticsEvent),
GatewayConn(gateway_conn_statistics::GatewayStatsEvent),
NymApi(nym_api_statistics::NymApiStatsEvent),
Connection(connection::ConnectionStatsEvent),
}
pub struct ClientStatsController {
last_update_time: OffsetDateTime,
client_id: String,
client_type: String,
os_information: OsInformation,
packet_stats: packet_statistics::PacketStatisticsControl,
gateway_conn_stats: gateway_conn_statistics::GatewayStatsControl,
nym_api_stats: nym_api_statistics::NymApiStatsControl,
connection_stats: connection::ConnectionStatsControl,
}
impl ClientStatsController {
pub fn new(client_id: String, client_type: String) -> Self {
ClientStatsController {
last_update_time: ClientStatsController::get_update_time(),
client_id,
client_type,
os_information: OsInformation::new(),
packet_stats: Default::default(),
gateway_conn_stats: Default::default(),
nym_api_stats: Default::default(),
connection_stats: Default::default(),
}
}
pub fn build_report(&self) -> ClientStatsReport {
ClientStatsReport {
last_update_time: self.last_update_time,
client_id: self.client_id.clone(),
client_type: self.client_type.clone(),
os_information: self.os_information.clone(),
packet_stats: self.packet_stats.report(),
gateway_conn_stats: self.gateway_conn_stats.report(),
nym_api_stats: self.nym_api_stats.report(),
connection_stats: self.connection_stats.report(),
..Default::default()
}
}
pub fn handle_event(&mut self, stats_event: ClientStatsEvents) {
match stats_event {
ClientStatsEvents::PacketStatistics(event) => self.packet_stats.handle_event(event),
ClientStatsEvents::GatewayConn(event) => self.gateway_conn_stats.handle_event(event),
ClientStatsEvents::NymApi(event) => self.nym_api_stats.handle_event(event),
ClientStatsEvents::Connection(event) => self.connection_stats.handle_event(event),
}
}
pub fn reset(&mut self) {
self.nym_api_stats = Default::default();
self.gateway_conn_stats = Default::default();
self.connection_stats = Default::default();
self.last_update_time = ClientStatsController::get_update_time();
}
pub fn snapshot(&mut self) {
self.packet_stats.snapshot();
}
pub fn local_report(&mut self) {
self.packet_stats.local_report();
self.gateway_conn_stats.local_report();
self.nym_api_stats.local_report();
}
fn get_update_time() -> OffsetDateTime {
let now = OffsetDateTime::now_utc();
#[allow(clippy::unwrap_used)]
let new_time = Time::from_hms(now.hour(), now.minute(), 0).unwrap();
now.replace_time(new_time)
}
}