1use std::fmt::Display;
4
5use inner_future::io::{AsyncRead, AsyncReadExt};
6use sha1_smol::*;
7
8use crate::prelude::*;
9
10#[cfg(target_os = "windows")]
14pub const TARGET_OS: &str = "windows";
15#[cfg(target_os = "macos")]
19pub const TARGET_OS: &str = "osx";
20#[cfg(target_os = "linux")]
24pub const TARGET_OS: &str = "linux";
25
26#[cfg(target_arch = "x86")]
30pub const TARGET_ARCH: &str = "x86";
31#[cfg(target_arch = "x86_64")]
35pub const TARGET_ARCH: &str = "x86_64";
36#[cfg(target_arch = "arm")]
40pub const NATIVE_ARCH: &str = "arm";
41#[cfg(target_arch = "aarch64")]
45pub const TARGET_ARCH: &str = "aarch64";
46
47#[cfg(target_arch = "x86")]
51pub const NATIVE_ARCH: &str = "32";
52#[cfg(target_arch = "x86_64")]
56pub const NATIVE_ARCH: &str = "64";
57#[cfg(target_arch = "arm")]
61pub const NATIVE_ARCH: &str = "64";
62#[cfg(target_arch = "aarch64")]
66pub const NATIVE_ARCH: &str = "64";
67
68#[cfg(target_os = "windows")]
72pub const CLASSPATH_SEPARATOR: &str = ";";
73#[cfg(not(target_os = "windows"))]
77pub const CLASSPATH_SEPARATOR: &str = ":";
78
79#[cfg(target_os = "macos")]
81pub static PAGESHIFT: once_cell::sync::Lazy<libc::c_int> = once_cell::sync::Lazy::new(|| {
82 let mut pagesize = unsafe { getpagesize() };
83 let mut pageshift = 0;
84 while pagesize > 1 {
85 pageshift += 1;
86 pagesize >>= 1;
87 }
88 pageshift - 10 });
90
91#[cfg(target_os = "macos")]
92#[link(name = "c")]
93extern "C" {
94 fn getpagesize() -> libc::c_int;
95}
96
97pub async fn get_data_sha1(data: &mut (impl AsyncRead + Unpin)) -> DynResult<String> {
101 let mut buf = [0u8; 16];
102 let mut sha = Sha1::default();
103 loop {
104 let size = data.read(&mut buf).await?;
105 if size > 0 {
106 sha.update(&buf[..size]);
107 } else {
108 break;
109 }
110 }
111 Ok(sha.hexdigest())
112}
113
114pub fn get_full_path(p: impl AsRef<std::path::Path>) -> String {
120 use path_absolutize::*;
121 let p = p.as_ref();
122 match p.absolutize() {
123 Ok(p) => {
124 #[cfg(windows)]
125 if let Some(p) = p.to_string_lossy().strip_prefix("\\\\?\\") {
126 p.to_string()
127 } else {
128 p.to_string_lossy().to_string()
129 }
130 #[cfg(not(windows))]
131 p.to_string_lossy().to_string()
132 }
133 Err(e) => {
134 println!(
135 "Warning: Can't convert path {} to full path: {}",
136 p.to_string_lossy(),
137 e
138 );
139 p.to_string_lossy().to_string()
140 }
141 }
142}
143
144#[derive(Clone, Copy)]
150pub enum Arch {
151 X86,
153 X64,
155 ARM64,
157}
158
159impl Display for Arch {
160 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
161 f.write_str(self.as_ref())
162 }
163}
164
165impl AsRef<str> for Arch {
166 fn as_ref(&self) -> &str {
167 match self {
168 Arch::X86 => "x86",
169 Arch::X64 => "x86_64",
170 Arch::ARM64 => "aarch64",
171 }
172 }
173}
174
175pub static NATIVE_ARCH_LAZY: once_cell::sync::Lazy<Arch> =
179 once_cell::sync::Lazy::new(get_system_arch);
180
181fn get_system_arch() -> Arch {
182 #[cfg(windows)]
183 unsafe {
184 use windows::Win32::System::SystemInformation::*;
185 let mut info: SYSTEM_INFO = Default::default();
186 GetNativeSystemInfo(&mut info);
187 match info.Anonymous.Anonymous.wProcessorArchitecture.0 {
188 0 => Arch::X86,
189 12 => Arch::ARM64,
190 9 => Arch::X64,
191 _ => unreachable!(),
192 }
193 }
194 #[cfg(all(target_os = "linux", target_arch = "x86"))]
195 return Arch::X86;
196 #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
197 return Arch::X64;
198 #[cfg(all(target_os = "linux", target_arch = "aarch64"))]
199 return Arch::ARM64;
200 #[cfg(all(target_os = "macos", target_arch = "x86_64"))]
201 return Arch::X64;
202 #[cfg(all(target_os = "macos", target_arch = "aarch64"))]
203 return Arch::ARM64;
204}
205
206pub struct MemoryStatus {
208 pub max: u64,
210 pub free: u64,
212}
213
214#[cfg(not(target_os = "macos"))]
220pub async fn get_exec_arch(_file_path: impl AsRef<std::path::Path>) -> DynResult<Arch> {
221 unimplemented!("此函数仅 MacOS 可用")
222}
223
224#[cfg(target_os = "macos")]
230pub async fn get_exec_arch(file_path: impl AsRef<std::path::Path>) -> DynResult<Arch> {
231 let mut file = inner_future::fs::OpenOptions::new()
232 .read(true)
233 .open(file_path.as_ref())
234 .await?;
235
236 let mut buf = [0u8; 8];
237
238 file.read_exact(&mut buf).await?;
239
240 if !(buf[0] == 0xCF && buf[1] == 0xFA && buf[2] == 0xED && buf[3] == 0xFE) {
243 anyhow::bail!("文件不是一个合法的 Mach-O 可执行文件");
244 }
245
246 match (buf[4], buf[7]) {
248 (7, 0) => Ok(Arch::X86), (7, 1) => Ok(Arch::X64), (12, 1) => Ok(Arch::ARM64), (_, _) => anyhow::bail!("不支持判定此架构"),
252 }
253}
254
255pub fn get_mem_status() -> MemoryStatus {
257 #[cfg(target_os = "windows")]
258 unsafe {
259 use windows::Win32::System::SystemInformation::MEMORYSTATUSEX;
260 let mut ms = MEMORYSTATUSEX {
261 dwLength: std::mem::size_of::<MEMORYSTATUSEX>() as _,
262 ..Default::default()
263 };
264 windows::Win32::System::SystemInformation::GlobalMemoryStatusEx(&mut ms).unwrap();
265 MemoryStatus {
266 max: ms.ullTotalPhys / 1024 / 1024,
267 free: ms.ullAvailPhys / 1024 / 1024,
268 }
269 }
270 #[cfg(target_os = "linux")]
271 {
272 let stat = std::fs::read_to_string("/proc/meminfo").unwrap();
273 let mut max = None;
274 let mut free = None;
275 for line in stat.lines() {
276 if line.starts_with("MemTotal:") {
278 max = line[10..line.len() - 3]
279 .trim()
280 .parse::<u64>()
281 .map(|x| Some(x / 1024))
282 .unwrap_or_default();
283 } else if line.starts_with("MemFree:") {
284 free = line[9..line.len() - 3]
285 .trim()
286 .parse::<u64>()
287 .map(|x| Some(x / 1024))
288 .unwrap_or_default();
289 }
290 if max.is_some() && free.is_some() {
291 break;
292 }
293 }
294 MemoryStatus {
295 max: max.unwrap_or(2048),
296 free: free.unwrap_or(2048),
297 }
298 }
299 #[cfg(target_os = "macos")]
300 {
301 unsafe {
302 let total = libc::sysconf(libc::_SC_PHYS_PAGES);
303 if total == -1 {
304 return MemoryStatus {
305 max: 2048,
306 free: 2048,
307 };
308 }
309
310 let host_port = libc::mach_host_self();
311 let mut stat = std::mem::MaybeUninit::<libc::vm_statistics64>::zeroed();
312 let mut stat_count = libc::HOST_VM_INFO64_COUNT;
313
314 if libc::host_statistics64(
315 host_port,
316 libc::HOST_VM_INFO64,
317 stat.as_mut_ptr() as *mut i32,
318 &mut stat_count,
319 ) != libc::KERN_SUCCESS
320 {
321 return MemoryStatus {
322 max: 2048,
323 free: 2048,
324 };
325 }
326
327 let stat = stat.assume_init();
328
329 MemoryStatus {
330 max: ((total as u64) << *PAGESHIFT) / 1024,
331 free: (((stat.inactive_count + stat.free_count) as u64) << *PAGESHIFT) / 1024,
332 }
333 }
334 }
335}