1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
use std::process::Command;

#[derive(Debug, Clone)]
pub struct SystemInfo {
    /// CPU核心数量
    pub cores: usize,
    /// 内存容量
    pub memory: String,
    /// 硬盘的序列号
    pub serial_number: Vec<String>,
    /// 硬件uuid
    pub hardware_uuid: String,
}

impl SystemInfo {
    pub fn new() -> Result<Self, String> {
        let mut that = Self {
            cores: 0,
            memory: "".to_string(),
            serial_number: vec![],
            hardware_uuid: "".to_string(),
        };
        #[cfg(target_os = "macos")]
        return match that.mac_os() {
            Ok(e) => Ok(e.clone()),
            Err(e) => Err(e)
        };
        #[cfg(target_os = "windows")]
        return match that.windows() {
            Ok(e) => Ok(e.clone()),
            Err(e) => Err(e)
        };
        Err("无信息".to_string())
    }

    pub fn mac_os(&mut self) -> Result<&mut Self, String> {
        let output = match Command::new("system_profiler")
            .args(&["SPHardwareDataType"])
            .output() {
            Ok(e) => e,
            Err(e) => {
                return Err(format!("{}", e.to_string()));
            }
        };

        let serial_number = String::from_utf8_lossy(&output.stdout);
        for line in serial_number.lines() {
            let text = line.trim();
            if text.contains("Total Number of Cores: ") {
                self.cores = text.trim_start_matches("Total Number of Cores: ").parse::<usize>().unwrap();
            }
            if text.contains("Memory: ") {
                self.memory = text.trim_start_matches("Memory: ").to_string();
            }
            if text.contains("Serial Number (system): ") {
                self.serial_number.push(text.trim_start_matches("Serial Number (system): ").to_string());
            }
            if text.contains("Hardware UUID: ") {
                self.hardware_uuid = text.trim_start_matches("Hardware UUID: ").to_string();
            }
        }
        Ok(self)
    }

    pub fn windows(&mut self) -> Result<&mut Self, String> {
        // 硬盘序列号
        let disk_output = match Command::new("wmic")
            .args(&["diskdrive", "get", "SerialNumber"])
            .output() {
            Ok(e) => e,
            Err(e) => {
                return Err(format!("{}", e.to_string()));
            }
        };
        let serial_number = String::from_utf8_lossy(&disk_output.stdout);
        for line in serial_number.lines() {
            let text = line.trim();
            if !text.contains("SerialNumber") && !text.is_empty() {
                self.serial_number.push(text.to_string())
            }
        }

        // cpu信息
        let cpu_output = match Command::new("wmic")
            .args(&["cpu", "get", "NumberOfCores"])
            .output() {
            Ok(e) => e,
            Err(e) => {
                return Err(format!("Failed to get CPU info: {}", e.to_string()));
            }
        };
        let cpu_info = String::from_utf8_lossy(&cpu_output.stdout);
        for line in cpu_info.lines() {
            let text = line.trim();
            if text.chars().all(|c| c.is_digit(10)) && !text.is_empty() {
                // 找到就退出
                self.cores = text.parse::<usize>().unwrap();
                break
            }
        }

        // 内存信息
        let memory_output = match Command::new("wmic")
            .args(&["memorychip", "get", "capacity"])
            .output() {
            Ok(e) => e,
            Err(e) => {
                return Err(format!("Failed to get memory info: {}", e.to_string()));
            }
        };
        let memory_info = String::from_utf8_lossy(&memory_output.stdout);
        let mut total_memory: u64 = 0;
        for line in memory_info.lines() {
            let text = line.trim();
            if text.chars().all(|c| c.is_digit(10)) && !text.is_empty() {
                if let Ok(capacity) = text.parse::<u64>() {
                    // 将每个内存条的容量累加以获得总的物理内存量(以字节为单位)
                    total_memory += capacity;
                }
            }
        }
        // 除以 1024 的三次方 将字节转换为 GB,并存储在结构体中
        self.memory = format!("{} GB", total_memory / 1024u64.pow(3));

        // 解析硬盘 UUID
        let uuid_output = match Command::new("powershell")
            .args(&["Get-WmiObject", "Win32_DiskDrive", "|", "Select-Object", "-ExpandProperty", "Signature"])
            .output() {
            Ok(e) => e,
            Err(e) => {
                return Err(format!("Failed to get disk UUIDs: {}", e.to_string()));
            }
        };
        let uuid = String::from_utf8_lossy(&uuid_output.stdout);
        for line in uuid.lines() {
            let text = line.trim();
            if !text.is_empty() {
                self.hardware_uuid = text.to_string();
                break
            }
        }

        Ok(self)
    }
}