use bevy::prelude::*;
use serde::{Deserialize, Serialize};
use std::time::{Instant, SystemTime, UNIX_EPOCH};
#[derive(Clone, Debug, Resource, Serialize, Deserialize)]
pub struct SessionInfo {
pub session_id: String,
pub session_start_time: u64,
#[serde(
skip_serializing,
skip_deserializing,
default = "default_session_instant"
)]
pub(crate) session_start_instant: Instant,
pub stats: SessionStats,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct SessionStats {
pub payloads_published: u64,
pub metrics_collected: u64,
pub events_tracked: u64,
pub diagnostics_recorded: u64,
pub panics_captured: u64,
pub uptime_seconds: u64,
}
impl SessionInfo {
pub fn new() -> Self {
let session_id = generate_session_id();
let session_start_time = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("System time is before UNIX epoch")
.as_secs();
info!("New session created: {}", session_id);
Self {
session_id,
session_start_time,
session_start_instant: Instant::now(),
stats: SessionStats::default(),
}
}
pub fn update_stats(
&mut self,
metrics_count: usize,
events_count: usize,
diagnostics_count: usize,
panics_count: usize,
) {
self.stats.payloads_published += 1;
self.stats.metrics_collected += metrics_count as u64;
self.stats.events_tracked += events_count as u64;
self.stats.diagnostics_recorded += diagnostics_count as u64;
self.stats.panics_captured += panics_count as u64;
self.stats.uptime_seconds = self.session_start_instant.elapsed().as_secs();
}
}
impl Default for SessionInfo {
fn default() -> Self {
Self::new()
}
}
fn generate_session_id() -> String {
use std::time::SystemTime;
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("System time is before UNIX epoch");
let pid = std::process::id();
let nanos = now.subsec_nanos();
format!("session-{:x}-{:x}-{:x}", now.as_secs(), pid, nanos)
}
pub fn initialize_session(app: &mut App) {
let session_info = SessionInfo::new();
app.insert_resource(session_info);
}
fn default_session_instant() -> Instant {
Instant::now()
}