puniyu_system_info/
lib.rs

1#[cfg(feature = "gpu")]
2use gfxinfo::active_gpu;
3use rust_decimal::{
4	Decimal,
5	prelude::{FromPrimitive, ToPrimitive},
6};
7#[cfg(feature = "process")]
8pub use sysinfo::Pid;
9#[cfg(feature = "network")]
10use {
11	std::net::IpAddr,
12	sysinfo::{MacAddr, Networks},
13};
14
15#[derive(Debug, Clone)]
16#[cfg(feature = "host")]
17pub struct HostInfo {
18	/// 主机名
19	pub host_name: String,
20	/// 操作系统名
21	pub os_name: String,
22	/// 操作系统版本
23	pub os_version: String,
24	/// 操作系统类型
25	pub os_type: String,
26	/// 系统架构
27	pub arch: String,
28	/// 系统启动时间
29	pub boot_time: u64,
30	/// 系统运行时间, 单位:秒
31	pub uptime: u64,
32}
33
34#[derive(Debug, Clone)]
35#[cfg(feature = "network")]
36pub struct NetworkInfo {
37	/// 网卡名称
38	pub name: String,
39	/// 网卡ip信息
40	pub ip_info: Vec<IpInfo>,
41	/// 网卡接收字节数(单位: KB/S)
42	pub upload: f64,
43	/// 网卡发送字节数(单位: KB/S)
44	pub download: f64,
45	/// 网卡mac地址
46	pub mac_addr: MacAddr,
47}
48
49#[derive(Debug, Clone)]
50#[cfg(feature = "network")]
51pub struct IpInfo {
52	/// ip地址
53	pub ip_address: IpAddr,
54	/// 子网掩码
55	pub netmask: u8,
56}
57
58#[derive(Debug, Clone)]
59pub struct ProcessInfo {
60	/// 进程ID
61	pub pid: Pid,
62	/// 进程名称
63	pub name: String,
64	/// 进程启动时间
65	pub start_time: u64,
66	/// 进程运行时间,单位:秒
67	pub run_time: u64,
68	/// 进程CPU使用率
69	pub cpu_usage: Option<u8>,
70	/// 进程内存使用率
71	pub memory_usage: Option<u8>,
72	/// 进程已用内存(单位: MB)
73	pub used_memory: f32,
74}
75#[derive(Debug, Clone)]
76#[cfg(feature = "cpu")]
77pub struct CpuInfo {
78	/// CPU型号
79	pub cpu_model: String,
80	/// CPU核心数
81	pub cpu_cores: usize,
82	/// CPU频率(单位: GHz)
83	pub cpu_frequency: Option<f32>,
84	/// CPU使用率
85	pub cpu_usage: Option<u8>,
86}
87
88#[derive(Debug, Clone)]
89#[cfg(feature = "gpu")]
90pub struct GpuInfo {
91	/// GPU型号
92	pub gpu_model: String,
93	///  GPU已用内存(单位: MB)
94	pub gpu_memory_used: f32,
95	/// GPU总内存(单位: MB)
96	pub gpu_memory_total: f32,
97	///  GPU可用内存(单位: MB)
98	pub gpu_memory_free: f32,
99	/// GPU使用率
100	pub gpu_usage: u8,
101}
102
103#[derive(Debug, Clone)]
104#[cfg(feature = "memory")]
105pub struct MemoryInfo {
106	/// 总内存(单位: MB)
107	pub total_memory: f32,
108	/// 已用内存(单位: MB)
109	pub used_memory: f32,
110	/// 可用内存(单位: MB)
111	pub free_memory: f32,
112	/// 交换内存(单位: MB)
113	pub swap_memory_total: f32,
114	/// 交换内存已用(单位: MB)
115	pub swap_memory_used: f32,
116	/// 交换内存可用(单位: MB)
117	pub swap_memory_free: f32,
118	/// 交换内存使用率
119	pub swap_memory_usage: Option<u8>,
120	/// 内存使用率
121	pub memory_usage: Option<u8>,
122}
123
124#[derive(Debug, Clone)]
125#[cfg(feature = "disk")]
126pub struct DiskDetail {
127	/// 磁盘名称
128	pub name: String,
129	/// 总磁盘空间(单位: GB)
130	pub total_space: f32,
131	/// 已用磁盘空间(单位: GB)
132	pub used_space: f32,
133	/// 可用磁盘空间(单位: GB)
134	pub free_space: f32,
135	/// 磁盘使用率
136	pub usage: f32,
137}
138
139#[derive(Debug, Clone)]
140#[cfg(feature = "disk")]
141pub struct DiskInfo {
142	/// 总磁盘空间(单位: GB)
143	pub total_disk_space: f32,
144	/// 总已用磁盘空间(单位: GB)
145	pub total_used_space: f32,
146	/// 总可用磁盘空间(单位: GB)
147	pub total_free_space: f32,
148	/// 总体磁盘使用率
149	pub total_usage: f32,
150	/// 各个磁盘详细信息
151	pub disks: Vec<DiskDetail>,
152}
153
154#[derive(Debug, Clone)]
155pub struct SystemInfo;
156
157impl SystemInfo {
158	/// 获取主机信息
159	///
160	/// 此函数可以获取主机信息,包括主机名、操作系统名、操作系统版本、操作系统类型、系统启动时间等
161	/// # 返回值
162	///
163	/// * [HostInfo] - 主机信息
164	///
165	#[cfg(feature = "host")]
166	pub fn host() -> HostInfo {
167		use std::env;
168		use sysinfo::System;
169		let hostname = System::host_name().unwrap();
170		let os_name = System::name().unwrap();
171		let arch = System::cpu_arch();
172		let os_version = System::os_version().unwrap();
173		let os_type = env::consts::OS.to_string();
174		let boot_time = System::boot_time();
175		let uptime = System::uptime();
176		HostInfo { host_name: hostname, os_name, arch, os_version, os_type, boot_time, uptime }
177	}
178
179	/// 获取CPU信息
180	///
181	/// 此函数可以获取CPU信息,包括型号、核心数、频率、使用率等
182	/// # 返回值
183	///
184	/// * [CpuInfo] - CPU信息
185	///
186	#[cfg(feature = "cpu")]
187	pub fn cpu() -> CpuInfo {
188		use std::thread::sleep;
189		use sysinfo::System;
190		let mut system = System::new();
191		system.refresh_cpu_all();
192
193		sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
194		system.refresh_cpu_usage();
195
196		let cpus = system.cpus();
197
198		let cpu_usage = if !cpus.is_empty() {
199			let usage = cpus.iter().map(|cpu| cpu.cpu_usage()).sum::<f32>() / cpus.len() as f32;
200			Some(usage.round() as u8)
201		} else {
202			None
203		};
204
205		let cpu_cores = cpus.len();
206
207		let cpu_model =
208			if !cpus.is_empty() { cpus[0].brand().to_string() } else { "Unknown".to_string() };
209
210		let cpu_frequency = if !cpus.is_empty() { Some(cpus[0].frequency() as f32) } else { None };
211
212		CpuInfo { cpu_usage, cpu_frequency, cpu_cores, cpu_model }
213	}
214
215	/// 获取内存信息
216	///
217	/// 此函数可以获取内存信息,包括总内存、已用内存、可用内存、内存使用率等
218	/// # 返回值
219	///
220	/// * [MemoryInfo] - 内存信息
221	///
222	#[cfg(feature = "memory")]
223	#[inline]
224	pub fn memory() -> MemoryInfo {
225		use sysinfo::System;
226		let mut system = System::new();
227		system.refresh_memory();
228
229		let total_memory = system.total_memory() / 1024 / 1024;
230		let used_memory = system.used_memory() / 1024 / 1024;
231		let free_memory = total_memory - used_memory;
232
233		let swap_memory_total = system.total_swap() / 1024 / 1024;
234		let swap_memory_used = system.used_swap() / 1024 / 1024;
235		let swap_memory_free = swap_memory_total - swap_memory_used;
236
237		let total_memory_f32 = format_float(total_memory as f64, 2);
238		let used_memory_f32 = format_float(used_memory as f64, 2);
239		let free_memory_f32 = format_float(free_memory as f64, 2);
240
241		let swap_memory_usage_f32 = format_float(swap_memory_used as f64, 2);
242		let swap_memory_free_f32 = format_float(swap_memory_free as f64, 2);
243		let swap_memory_total_f32 = format_float(swap_memory_total as f64, 2);
244
245		let memory_usage = if total_memory > 0 {
246			Some(((used_memory as f32 / total_memory as f32) * 100.0) as u8)
247		} else {
248			None
249		};
250		let swap_memory_usage = if swap_memory_total > 0 {
251			Some(((swap_memory_used as f32 / swap_memory_total as f32) * 100.0) as u8)
252		} else {
253			None
254		};
255
256		MemoryInfo {
257			total_memory: total_memory_f32 as f32,
258			used_memory: used_memory_f32 as f32,
259			free_memory: free_memory_f32 as f32,
260			memory_usage,
261			swap_memory_total: swap_memory_total_f32 as f32,
262			swap_memory_used: swap_memory_usage_f32 as f32,
263			swap_memory_free: swap_memory_free_f32 as f32,
264			swap_memory_usage,
265		}
266	}
267
268	/// 获取磁盘信息
269	///
270	/// 此函数可以获取磁盘信息,包括总磁盘空间、已用磁盘空间、可用磁盘空间、磁盘使用率等
271	/// # 返回值
272	///
273	/// * [DiskInfo] - 磁盘信息
274	///
275	#[cfg(feature = "disk")]
276	#[inline]
277	pub fn disk() -> DiskInfo {
278		use sysinfo::Disks;
279		let disks = Disks::new_with_refreshed_list();
280
281		let mut total_disk_space = 0f32;
282		let mut total_used_space = 0f32;
283		let mut total_free_space = 0f32;
284		let mut disk_details = Vec::new();
285
286		for disk in disks.list() {
287			let total_space = disk.total_space() as f32 / (1024.0 * 1024.0 * 1024.0);
288			let free_space = disk.available_space() as f32 / (1024.0 * 1024.0 * 1024.0);
289			let used_space = total_space - free_space;
290
291			let usage =
292				if disk.total_space() > 0 { (used_space / total_space) * 100.0 } else { 0.0 };
293
294			let disk_detail = DiskDetail {
295				name: disk.name().to_string_lossy().to_string(),
296				total_space: format_float(total_space as f64, 2) as f32,
297				used_space: format_float(used_space as f64, 2) as f32,
298				free_space: format_float(free_space as f64, 2) as f32,
299				usage: format_float(usage as f64, 2) as f32,
300			};
301
302			total_disk_space += total_space;
303			total_used_space += used_space;
304			total_free_space += free_space;
305			disk_details.push(disk_detail);
306		}
307
308		let total_usage = if total_disk_space > 0.0 {
309			(total_used_space / total_disk_space) * 100.0
310		} else {
311			0.0
312		};
313
314		DiskInfo {
315			total_disk_space: format_float(total_disk_space as f64, 2) as f32,
316			total_used_space: format_float(total_used_space as f64, 2) as f32,
317			total_free_space: format_float(total_free_space as f64, 2) as f32,
318			total_usage: format_float(total_usage as f64, 2) as f32,
319			disks: disk_details,
320		}
321	}
322
323	/// 获取网卡信息
324	///
325	/// 此函数可以获取网络信息,包括网络名称、MAC地址、上传速度、下载速度、IP地址等
326	/// # 返回值
327	///
328	/// * [NetworkInfo] - 网络信息
329	///
330	#[cfg(feature = "network")]
331	pub fn network() -> Vec<NetworkInfo> {
332		let networks = Networks::new_with_refreshed_list();
333		let mut network_infos = Vec::new();
334		for (network, data) in networks.list() {
335			let mut ip_info_list: Vec<IpInfo> = Vec::new();
336
337			for ip_network in data.ip_networks() {
338				ip_info_list
339					.push(IpInfo { ip_address: ip_network.addr, netmask: ip_network.prefix });
340			}
341			network_infos.push(NetworkInfo {
342				name: network.to_string(),
343				mac_addr: data.mac_address(),
344				upload: format_float((data.total_received() as f32 / 1024.0) as f64, 2),
345				download: format_float((data.total_transmitted() as f32 / 1024.0) as f64, 2),
346				ip_info: ip_info_list,
347			});
348		}
349		network_infos
350	}
351
352	/// 获取当前网络信息
353	///
354	/// 此函数可以获取当前网络信息,包括网络名称、MAC地址、上传速度、下载速度、IP地址等
355	/// # 返回值
356	///
357	/// * [NetworkInfo] - 当前网络信息
358	///
359	#[cfg(feature = "network")]
360	pub fn current_network() -> NetworkInfo {
361		use std::thread::sleep;
362		use std::time::Duration;
363		let mut networks = Networks::new_with_refreshed_list();
364
365		sleep(Duration::from_millis(100));
366
367		networks.refresh(true);
368
369		let process_network_data = |_: &str, data: &sysinfo::NetworkData| -> (Vec<IpInfo>, bool) {
370			let mut ip_info_list: Vec<IpInfo> = Vec::new();
371			let mut has_ipv4 = false;
372
373			for ip_network in data.ip_networks() {
374				ip_info_list
375					.push(IpInfo { ip_address: ip_network.addr, netmask: ip_network.prefix });
376
377				if ip_network.addr.is_ipv4() {
378					has_ipv4 = true;
379				}
380			}
381
382			(ip_info_list, has_ipv4)
383		};
384		let is_loopback = |name: &str| -> bool {
385			name.starts_with("lo") || name.starts_with("Loopback") || name.contains("loopback")
386		};
387
388		for (network_name, data) in networks.list() {
389			let (ip_info_list, has_ipv4) = process_network_data(network_name, data);
390
391			let recent_traffic = data.received() + data.transmitted();
392			if !is_loopback(network_name)
393				&& has_ipv4 && !ip_info_list.is_empty()
394				&& recent_traffic > 0
395			{
396				return NetworkInfo {
397					name: network_name.to_string(),
398					mac_addr: data.mac_address(),
399					upload: format_float(data.received() as f64 / 1024.0, 2),
400					download: format_float(data.transmitted() as f64 / 1024.0, 2),
401					ip_info: ip_info_list,
402				};
403			}
404		}
405
406		for (network_name, data) in networks.list() {
407			let (ip_info_list, has_ipv4) = process_network_data(network_name, data);
408
409			if !is_loopback(network_name) && has_ipv4 && !ip_info_list.is_empty() {
410				return NetworkInfo {
411					name: network_name.to_string(),
412					mac_addr: data.mac_address(),
413					upload: 0.0,
414					download: 0.0,
415					ip_info: ip_info_list,
416				};
417			}
418		}
419
420		NetworkInfo {
421			name: "unknown".to_string(),
422			mac_addr: MacAddr([0, 0, 0, 0, 0, 0]),
423			upload: 0.0,
424			download: 0.0,
425			ip_info: vec![],
426		}
427	}
428
429	/// 获取进程信息
430	/// 此函数可以获取进程信息,包括进程ID、进程名称、CPU使用率、内存使用率、已用内存等
431	/// # 返回值
432	///
433	/// * [ProcessInfo] - 进程信息
434	#[cfg(feature = "process")]
435	pub fn process() -> ProcessInfo {
436		use std::process;
437		Self::process_with_pid(process::id())
438	}
439
440	#[cfg(feature = "process")]
441	pub fn process_with_pid(pid: u32) -> ProcessInfo {
442		use std::time::{SystemTime, UNIX_EPOCH};
443		use sysinfo::{ProcessesToUpdate, System};
444		let mut system = System::new();
445		let pid = Pid::from_u32(pid);
446		system.refresh_processes(ProcessesToUpdate::Some(&[pid]), true);
447		let process = system.process(pid);
448
449		let name = if let Some(process) = process {
450			process.name().to_string_lossy().into_owned()
451		} else {
452			"Unknown".to_string()
453		};
454		let start_time = process.map(|p| p.start_time()).unwrap_or(0);
455		let run_time = process
456			.map(|p| {
457				let current_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
458				let process_start_time = p.start_time();
459				current_time.saturating_sub(process_start_time)
460			})
461			.unwrap_or(0);
462
463		let cpu_usage = process.map(|p| format_float(p.cpu_usage() as f64, 2) as u8);
464
465		let memory_usage = process.map(|p| {
466			format_float(p.memory() as f64 / (system.total_memory() as f64) * 100.0, 2) as u8
467		});
468
469		let used_memory = match process {
470			Some(process) => process.memory() as f32 / 1024.0 / 1024.0,
471			None => 0.0,
472		};
473
474		ProcessInfo { pid, name, start_time, run_time, cpu_usage, memory_usage, used_memory }
475	}
476
477	/// 获取GPU信息
478	///
479	/// 此函数可以获取GPU信息,包括型号、已用内存、总内存、可用内存、使用率等
480	/// # 返回值
481	///
482	/// * [GpuInfo] - GPU信息
483	///
484	#[cfg(feature = "gpu")]
485	pub fn gpu() -> Option<GpuInfo> {
486		let gpu = active_gpu();
487		match gpu {
488			Ok(gpu) => {
489				let info = gpu.info();
490				let gpu_usage = format_float(info.used_vram() as f64 / (1024.0 * 1024.0), 2) as f32;
491				let gpu_total =
492					format_float(info.total_vram() as f64 / (1024.0 * 1024.0), 2) as f32;
493				Some(GpuInfo {
494					gpu_model: gpu.model().to_string(),
495					gpu_memory_used: gpu_usage,
496					gpu_memory_total: gpu_total as f32,
497					gpu_memory_free: gpu_total - gpu_usage,
498					gpu_usage: info.load_pct() as u8,
499				})
500			}
501			Err(_) => None,
502		}
503	}
504}
505
506fn format_float(value: f64, decimals: u32) -> f64 {
507	let decimal_value = Decimal::from_f64(value).unwrap_or(Decimal::ZERO);
508	let rounded = decimal_value.round_dp(decimals);
509	rounded.to_f64().unwrap_or(0.0)
510}