Skip to main content

wayle_sysinfo/
service.rs

1use std::{sync::RwLock, time::Duration};
2
3use tokio_util::sync::CancellationToken;
4use tracing::debug;
5use wayle_core::Property;
6
7use crate::{
8    builder::SysinfoServiceBuilder,
9    polling,
10    types::{CpuData, DiskData, MemoryData, NetworkData},
11};
12
13/// System information service for monitoring CPU, memory, disk, and network.
14///
15/// Provides reactive properties that update at configurable intervals.
16/// All metrics are polled in the background and exposed via `Property<T>`
17/// for both snapshot access (`.get()`) and stream-based watching (`.watch()`).
18///
19/// Polling intervals can be changed at runtime via `set_*_interval()` methods.
20#[derive(Debug)]
21pub struct SysinfoService {
22    pub(crate) cancellation_token: CancellationToken,
23    pub(crate) cpu_token: RwLock<CancellationToken>,
24    pub(crate) memory_token: RwLock<CancellationToken>,
25    pub(crate) disk_token: RwLock<CancellationToken>,
26    pub(crate) network_token: RwLock<CancellationToken>,
27    pub(crate) cpu_interval: RwLock<Duration>,
28    pub(crate) cpu_temp_sensor: RwLock<String>,
29
30    /// CPU metrics including usage, frequency, and temperature.
31    pub cpu: Property<CpuData>,
32
33    /// Memory and swap metrics.
34    pub memory: Property<MemoryData>,
35
36    /// Disk metrics for all mounted filesystems.
37    pub disks: Property<Vec<DiskData>>,
38
39    /// Network metrics for all interfaces.
40    pub network: Property<Vec<NetworkData>>,
41}
42
43impl SysinfoService {
44    /// Returns a builder for configuring the service.
45    pub fn builder() -> SysinfoServiceBuilder {
46        SysinfoServiceBuilder::new()
47    }
48
49    /// Updates the CPU polling interval.
50    pub fn set_cpu_interval(&self, interval: Duration) {
51        debug!(?interval, "Updating CPU polling interval");
52        if let Ok(mut guard) = self.cpu_interval.write() {
53            *guard = interval;
54        }
55        self.restart_cpu_polling();
56    }
57
58    /// Updates the CPU temperature sensor label.
59    pub fn set_cpu_temp_sensor(&self, sensor: &str) {
60        debug!(?sensor, "Updating CPU temperature sensor");
61        if let Ok(mut guard) = self.cpu_temp_sensor.write() {
62            *guard = sensor.to_owned();
63        }
64        self.restart_cpu_polling();
65    }
66
67    fn restart_cpu_polling(&self) {
68        let interval = self.cpu_interval.read().map(|g| *g).unwrap_or_default();
69        let sensor = self
70            .cpu_temp_sensor
71            .read()
72            .map(|g| g.clone())
73            .unwrap_or_default();
74
75        let new_token = self.cancellation_token.child_token();
76        if let Ok(mut guard) = self.cpu_token.write() {
77            guard.cancel();
78            polling::cpu::spawn(new_token.clone(), self.cpu.clone(), interval, sensor);
79            *guard = new_token;
80        }
81    }
82
83    /// Updates the memory polling interval.
84    ///
85    /// Restarts the memory polling task with the new interval.
86    pub fn set_memory_interval(&self, interval: Duration) {
87        debug!(?interval, "Updating memory polling interval");
88        let new_token = self.cancellation_token.child_token();
89        if let Ok(mut guard) = self.memory_token.write() {
90            guard.cancel();
91            polling::memory::spawn(new_token.clone(), self.memory.clone(), interval);
92            *guard = new_token;
93        }
94    }
95
96    /// Updates the disk polling interval.
97    ///
98    /// Restarts the disk polling task with the new interval.
99    pub fn set_disk_interval(&self, interval: Duration) {
100        debug!(?interval, "Updating disk polling interval");
101        let new_token = self.cancellation_token.child_token();
102        if let Ok(mut guard) = self.disk_token.write() {
103            guard.cancel();
104            polling::disk::spawn(new_token.clone(), self.disks.clone(), interval);
105            *guard = new_token;
106        }
107    }
108
109    /// Updates the network polling interval.
110    ///
111    /// Restarts the network polling task with the new interval.
112    pub fn set_network_interval(&self, interval: Duration) {
113        debug!(?interval, "Updating network polling interval");
114        let new_token = self.cancellation_token.child_token();
115        if let Ok(mut guard) = self.network_token.write() {
116            guard.cancel();
117            polling::network::spawn(new_token.clone(), self.network.clone(), interval);
118            *guard = new_token;
119        }
120    }
121}
122
123impl Drop for SysinfoService {
124    fn drop(&mut self) {
125        self.cancellation_token.cancel();
126    }
127}