1use bevy::prelude::*;
2use serde::{Deserialize, Serialize};
3use std::time::{Instant, SystemTime, UNIX_EPOCH};
4
5#[derive(Clone, Debug, Resource, Serialize, Deserialize)]
7pub struct SessionInfo {
8 pub session_id: String,
10
11 pub session_start_time: u64,
13
14 #[serde(
16 skip_serializing,
17 skip_deserializing,
18 default = "default_session_instant"
19 )]
20 pub(crate) session_start_instant: Instant,
21
22 pub stats: SessionStats,
24}
25
26#[derive(Clone, Debug, Default, Serialize, Deserialize)]
28pub struct SessionStats {
29 pub payloads_published: u64,
31
32 pub metrics_collected: u64,
34
35 pub events_tracked: u64,
37
38 pub diagnostics_recorded: u64,
40
41 pub panics_captured: u64,
43
44 pub uptime_seconds: u64,
46}
47
48impl SessionInfo {
49 pub fn new() -> Self {
51 let session_id = generate_session_id();
52 let session_start_time = SystemTime::now()
53 .duration_since(UNIX_EPOCH)
54 .expect("System time is before UNIX epoch")
55 .as_secs();
56
57 info!("New session created: {}", session_id);
58
59 Self {
60 session_id,
61 session_start_time,
62 session_start_instant: Instant::now(),
63 stats: SessionStats::default(),
64 }
65 }
66
67 pub fn update_stats(
69 &mut self,
70 metrics_count: usize,
71 events_count: usize,
72 diagnostics_count: usize,
73 panics_count: usize,
74 ) {
75 self.stats.payloads_published += 1;
76 self.stats.metrics_collected += metrics_count as u64;
77 self.stats.events_tracked += events_count as u64;
78 self.stats.diagnostics_recorded += diagnostics_count as u64;
79 self.stats.panics_captured += panics_count as u64;
80
81 self.stats.uptime_seconds = self.session_start_instant.elapsed().as_secs();
83 }
84}
85
86impl Default for SessionInfo {
87 fn default() -> Self {
88 Self::new()
89 }
90}
91
92fn generate_session_id() -> String {
94 use std::time::SystemTime;
95
96 let now = SystemTime::now()
98 .duration_since(UNIX_EPOCH)
99 .expect("System time is before UNIX epoch");
100
101 let pid = std::process::id();
103 let nanos = now.subsec_nanos();
104
105 format!("session-{:x}-{:x}-{:x}", now.as_secs(), pid, nanos)
106}
107
108pub fn initialize_session(app: &mut App) {
110 let session_info = SessionInfo::new();
111 app.insert_resource(session_info);
112}
113
114fn default_session_instant() -> Instant {
115 Instant::now()
116}