yggdrasil/
sysinfo_sampler.rs1#[cfg(feature = "server")]
10use std::sync::LazyLock;
11#[cfg(feature = "server")]
12use std::time::Duration;
13
14use serde::{Deserialize, Serialize};
15
16#[derive(Clone, Default, Serialize, Deserialize, Debug)]
18pub struct SystemSnapshot {
19 pub cpu_usage: f32,
21 pub load_avg_1: f64,
23 pub total_memory: u64,
25 pub used_memory: u64,
27 pub disk_total: u64,
29 pub disk_available: u64,
31 pub os_name: String,
33 pub kernel_version: String,
35 pub uptime_secs: u64,
37}
38
39#[cfg(feature = "server")]
40static SNAPSHOT: LazyLock<tokio::sync::RwLock<SystemSnapshot>> =
41 LazyLock::new(|| tokio::sync::RwLock::new(SystemSnapshot::default()));
42
43#[cfg(feature = "server")]
45fn sample_interval() -> Duration {
46 let secs = std::env::var("SYSINFO_SAMPLE_SECS")
47 .ok()
48 .and_then(|s| s.parse::<f64>().ok())
49 .unwrap_or(0.5);
50 Duration::from_secs_f64(secs.max(0.05))
51}
52
53#[cfg(feature = "server")]
57pub fn spawn_sampler() {
58 tokio::spawn(async move {
59 use sysinfo::{Disks, System};
60
61 let mut sys = System::new();
62 let interval = sample_interval();
63 sys.refresh_cpu_usage();
65 let disks = Disks::new_with_refreshed_list();
66
67 loop {
68 tokio::time::sleep(interval).await;
69 sys.refresh_cpu_usage();
70 sys.refresh_memory();
71 let load = System::load_average();
72
73 let (disk_total, disk_available) = disks
75 .list()
76 .iter()
77 .max_by_key(|d| d.total_space())
78 .map(|d| (d.total_space(), d.available_space()))
79 .unwrap_or((0, 0));
80
81 let snap = SystemSnapshot {
82 cpu_usage: sys.global_cpu_usage(),
83 load_avg_1: load.one,
84 total_memory: sys.total_memory(),
85 used_memory: sys.used_memory(),
86 disk_total,
87 disk_available,
88 os_name: System::long_os_version().unwrap_or_default(),
89 kernel_version: System::kernel_version().unwrap_or_default(),
90 uptime_secs: System::uptime(),
91 };
92 *SNAPSHOT.write().await = snap;
93 }
94 });
95}
96
97#[cfg(feature = "server")]
99pub async fn read_snapshot() -> SystemSnapshot {
100 SNAPSHOT.read().await.clone()
101}
102
103#[cfg(not(feature = "server"))]
104#[allow(dead_code)]
105pub async fn read_snapshot() -> SystemSnapshot {
106 SystemSnapshot::default()
107}