cyfs_util/util/
system_info.rs1use serde::{Deserialize, Serialize};
2use std::sync::{Arc, Mutex};
3use std::time::{Duration, Instant};
4use sysinfo::{CpuExt, DiskExt, DiskType, NetworkExt, RefreshKind, System, SystemExt};
5
6#[derive(Clone, Debug, Serialize, Deserialize)]
7pub struct SystemInfo {
8 pub name: String,
9
10 pub uptime: u64,
12
13 pub boot_time: u64,
15
16 pub cpu_usage: f32,
17
18 pub total_memory: u64,
20 pub used_memory: u64,
21
22 pub received_bytes: u64,
24 pub transmitted_bytes: u64,
25
26 pub total_received_bytes: u64,
28 pub total_transmitted_bytes: u64,
29
30 pub ssd_disk_total: u64,
32 pub ssd_disk_avail: u64,
33
34 pub hdd_disk_total: u64,
36 pub hdd_disk_avail: u64,
37}
38
39impl Default for SystemInfo {
40 fn default() -> Self {
41 let sys = System::new();
42 let uptime = sys.uptime() * 1000 * 1000;
43 let boot_time = cyfs_base::unix_time_to_bucky_time(sys.boot_time() * 1000 * 1000);
44
45 Self {
46 name: "".to_owned(),
47 uptime,
48 boot_time,
49 cpu_usage: 0.0,
50 total_memory: 0,
51 used_memory: 0,
52 received_bytes: 0,
53 transmitted_bytes: 0,
54 total_received_bytes: 0,
55 total_transmitted_bytes: 0,
56 ssd_disk_total: 0,
57 ssd_disk_avail: 0,
58 hdd_disk_total: 0,
59 hdd_disk_avail: 0,
60 }
61 }
62}
63
64struct SystemInfoManagerInner {
65 running: bool,
66 last_access_time: Instant,
67 max_idle_time: Duration,
68
69 info_inner: SystemInfo,
70 handler: System,
71}
72
73impl SystemInfoManagerInner {
74 pub fn new() -> Self {
75 let r = RefreshKind::new()
76 .with_networks()
77 .with_networks_list()
78 .with_memory()
79 .with_cpu(sysinfo::CpuRefreshKind::new().with_cpu_usage())
80 .with_disks()
81 .with_disks_list();
82 let handler = System::new_with_specifics(r);
83
84 let mut info_inner = SystemInfo::default();
85
86 let s = System::new();
87 info_inner.name = match s.host_name() {
88 Some(name) => {
89 let trim = '\0';
90 if name.ends_with(trim) {
91 name[..name.len() - 1].to_owned()
92 } else {
93 name
94 }
95 }
96 None => "MY PC".to_owned(),
97 };
98
99 info!("os name: {:?}", info_inner.name);
100
101 Self {
102 running: false,
103
104 last_access_time: Instant::now(),
105 max_idle_time: Duration::from_secs(15),
106
107 info_inner,
108 handler,
109 }
110 }
111
112 pub fn check_idle(&mut self) {
113 let now = Instant::now();
114 if now - self.last_access_time >= self.max_idle_time {
115 info!(
116 "system info extend max idle duration, now will stop: last_access={:?}",
117 self.last_access_time
118 );
119 self.running = false;
120 }
121 }
122
123 pub fn refresh(&mut self) {
124 self.handler.refresh_all();
125 self.update_memory();
126 self.update_cpu();
127 self.update_network();
128 self.update_disks();
129 }
130
131 fn update_memory(&mut self) {
132 self.info_inner.total_memory = self.handler.total_memory();
133 self.info_inner.used_memory = self.handler.used_memory();
134 }
135
136 fn update_disks(&mut self) {
137 self.info_inner.hdd_disk_total = 0;
138 self.info_inner.hdd_disk_avail = 0;
139 self.info_inner.ssd_disk_total = 0;
140 self.info_inner.ssd_disk_avail = 0;
141 for disk in self.handler.disks() {
142 if disk.is_removable() {
143 continue;
144 }
145 match disk.type_() {
146 DiskType::HDD => {
147 self.info_inner.hdd_disk_total += disk.total_space();
148 self.info_inner.hdd_disk_avail += disk.available_space();
149 }
150 DiskType::SSD => {
151 self.info_inner.ssd_disk_total += disk.total_space();
152 self.info_inner.ssd_disk_avail += disk.available_space();
153 }
154 DiskType::Unknown(_) => {
158 }
161 }
162 }
163 }
164
165 fn update_cpu(&mut self) {
166 self.info_inner.cpu_usage = self.handler.global_cpu_info().cpu_usage();
167 }
168
169 fn update_network(&mut self) {
170 let networks = self.handler.networks();
171 let mut received_bytes = 0;
172 let mut transmitted_bytes = 0;
173 let mut total_received_bytes = 0;
174 let mut total_transmitted_bytes = 0;
175
176
177 for (interface_name, network) in networks {
178 if interface_name
179 .find("Hyper-V Virtual Ethernet Adapter")
180 .is_some()
181 {
182 continue;
184 }
185
186 if interface_name.find("VMware").is_some() {
187 continue;
189 }
190
191 if network.mac_address().is_unspecified() {
192 warn!("will ignore unspecified addr network interface: {}", interface_name);
193 continue;
194 }
195
196 received_bytes += network.received();
200 transmitted_bytes += network.transmitted();
201
202 total_received_bytes += network.total_received();
203 total_transmitted_bytes += network.total_transmitted();
204 }
205
206 self.info_inner.received_bytes = received_bytes;
207 self.info_inner.transmitted_bytes = transmitted_bytes;
208
209 self.info_inner.total_received_bytes = total_received_bytes;
210 self.info_inner.total_transmitted_bytes = total_transmitted_bytes;
211 }
212}
213
214#[derive(Clone)]
215pub struct SystemInfoManager(Arc<Mutex<SystemInfoManagerInner>>);
216
217impl SystemInfoManager {
218 fn new() -> Self {
219 Self(Arc::new(Mutex::new(SystemInfoManagerInner::new())))
220 }
221
222 pub async fn get_system_info(&self) -> SystemInfo {
223 if !self.0.lock().unwrap().running {
224 self.start();
225 async_std::task::sleep(Duration::from_secs(2)).await;
226 }
227
228 let mut item = self.0.lock().unwrap();
229 item.last_access_time = Instant::now();
230 item.info_inner.clone()
231 }
232
233 pub fn start(&self) {
234 let start = {
235 let mut item = self.0.lock().unwrap();
236 if !item.running {
237 item.running = true;
238 true
239 } else {
240 false
241 }
242 };
243
244 if !start {
245 info!("system info already in refreshing!");
246 return;
247 }
248
249 info!("start refresh system info...");
250
251 let this = self.clone();
252 async_std::task::spawn(async move { this.run_refresh().await });
253 }
254
255 async fn run_refresh(&self) {
256 loop {
257 {
258 let mut item = self.0.lock().unwrap();
259 item.check_idle();
260 if !item.running {
261 break;
262 }
263
264 item.refresh();
265 }
266
267 async_std::task::sleep(std::time::Duration::from_secs(1)).await;
268 }
269 }
270
271 pub fn stop(&self) {
272 let mut item = self.0.lock().unwrap();
273 if item.running {
274 item.running = false;
275 info!("will stop refresh system info!");
276 } else {
277 info!("refresh system info stopped already!");
278 }
279 }
280}
281
282lazy_static::lazy_static! {
284 pub static ref SYSTEM_INFO_MANAGER: SystemInfoManager = SystemInfoManager::new();
285}