anti_sys/
lib.rs

1use sysinfo::{CpuExt, DiskExt, NetworkExt, NetworksExt, System, SystemExt};
2
3/// Information about a single CPU
4#[derive(Debug, Clone, PartialEq)]
5pub struct CpuInfo {
6    pub name: String,
7    pub usage: f32,
8}
9
10/// Information about a disk
11#[derive(Debug, Clone, PartialEq)]
12pub struct DiskInfo {
13    pub name: String,
14    pub total_space: u64,
15    pub available_space: u64,
16}
17
18/// Information about a network interface
19#[derive(Debug, Clone, PartialEq)]
20pub struct NetworkInfo {
21    pub interface: String,
22    pub received: u64,
23    pub transmitted: u64,
24}
25
26/// Aggregate system information
27#[derive(Debug, Clone, PartialEq)]
28pub struct SystemInfo {
29    pub uptime: u64,
30    pub total_memory: u64,
31    pub used_memory: u64,
32    pub cpus: Vec<CpuInfo>,
33    pub disks: Vec<DiskInfo>,
34    pub networks: Vec<NetworkInfo>,
35}
36
37/// Gather system information using `sysinfo`
38pub fn gather() -> SystemInfo {
39    let mut sys = System::new_all();
40    sys.refresh_all();
41
42    let cpus = sys
43        .cpus()
44        .iter()
45        .map(|c| CpuInfo {
46            name: c.name().to_string(),
47            usage: c.cpu_usage(),
48        })
49        .collect();
50
51    let disks = sys
52        .disks()
53        .iter()
54        .map(|d| DiskInfo {
55            name: d.name().to_string_lossy().into_owned(),
56            total_space: d.total_space(),
57            available_space: d.available_space(),
58        })
59        .collect();
60
61    let networks = sys
62        .networks()
63        .iter()
64        .map(|(iface, data)| NetworkInfo {
65            interface: iface.to_string(),
66            received: data.received(),
67            transmitted: data.transmitted(),
68        })
69        .collect();
70
71    SystemInfo {
72        uptime: sys.uptime(),
73        total_memory: sys.total_memory(),
74        used_memory: sys.used_memory(),
75        cpus,
76        disks,
77        networks,
78    }
79}
80
81/// Format system information as simple human readable text
82pub fn format_plain(info: &SystemInfo) -> String {
83    let mut out = String::new();
84    out.push_str(&format!("Uptime: {}s\n", info.uptime));
85    out.push_str(&format!(
86        "Memory: {}/{} KB\n",
87        info.used_memory, info.total_memory
88    ));
89
90    out.push_str("CPU usage:\n");
91    for cpu in &info.cpus {
92        out.push_str(&format!(" - {}: {:.1}%\n", cpu.name, cpu.usage));
93    }
94
95    out.push_str("Disks:\n");
96    for disk in &info.disks {
97        out.push_str(&format!(
98            " - {}: {} / {} bytes free\n",
99            disk.name, disk.available_space, disk.total_space
100        ));
101    }
102
103    out.push_str("Networks:\n");
104    for net in &info.networks {
105        out.push_str(&format!(
106            " - {}: rx {} bytes tx {} bytes\n",
107            net.interface, net.received, net.transmitted
108        ));
109    }
110
111    out
112}
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117
118    #[test]
119    fn test_format_plain() {
120        let info = SystemInfo {
121            uptime: 10,
122            total_memory: 1000,
123            used_memory: 500,
124            cpus: vec![CpuInfo {
125                name: "cpu0".into(),
126                usage: 20.0,
127            }],
128            disks: vec![DiskInfo {
129                name: "disk".into(),
130                total_space: 2000,
131                available_space: 1000,
132            }],
133            networks: vec![NetworkInfo {
134                interface: "eth0".into(),
135                received: 100,
136                transmitted: 200,
137            }],
138        };
139        let out = format_plain(&info);
140        assert!(out.contains("Uptime: 10s"));
141        assert!(out.contains("Memory: 500/1000"));
142        assert!(out.contains("cpu0"));
143        assert!(out.contains("disk"));
144        assert!(out.contains("eth0"));
145    }
146}