Skip to main content

Mountain/Binary/IPC/ProcessCommand/
process_get_memory_info.rs

1#![allow(non_snake_case)]
2
3//! Tauri command - return process memory in `{ private, shared,
4//! residentSet }` form (bytes). Per-platform: `ps` on macOS, `tasklist`
5//! on Windows, `/proc/self/statm` on Linux. Errors fall back to zero
6//! triple so the renderer keeps working in the rare case the platform
7//! probe fails.
8
9use serde_json::{Value, json};
10
11#[tauri::command]
12pub async fn process_get_memory_info() -> Result<Value, String> {
13	#[cfg(target_os = "macos")]
14	{
15		let Output = std::process::Command::new("ps")
16			.args(["-o", "rss=,vsz=", "-p", &std::process::id().to_string()])
17			.output();
18
19		match Output {
20			Ok(Out) => {
21				let Text = String::from_utf8_lossy(&Out.stdout);
22
23				let Parts:Vec<&str> = Text.split_whitespace().collect();
24
25				let Rss = Parts.first().and_then(|V| V.parse::<u64>().ok()).unwrap_or(0) * 1024;
26
27				let _Vsz = Parts.get(1).and_then(|V| V.parse::<u64>().ok()).unwrap_or(0) * 1024;
28
29				Ok(json!({ "private": Rss, "shared": 0, "residentSet": Rss }))
30			},
31
32			Err(_) => Ok(json!({ "private": 0, "shared": 0, "residentSet": 0 })),
33		}
34	}
35
36	#[cfg(target_os = "windows")]
37	{
38		let Output = std::process::Command::new("tasklist")
39			.args(["/FI", &format!("PID eq {}", std::process::id()), "/FO", "CSV", "/NH"])
40			.output();
41
42		match Output {
43			Ok(Out) => {
44				let Text = String::from_utf8_lossy(&Out.stdout);
45
46				let MemStr = Text.split(',').nth(4).unwrap_or("\"0 K\"");
47
48				let MemKb:u64 = MemStr
49					.chars()
50					.filter(|C| C.is_ascii_digit())
51					.collect::<String>()
52					.parse()
53					.unwrap_or(0);
54
55				let MemBytes = MemKb * 1024;
56
57				Ok(json!({ "private": MemBytes, "shared": 0, "residentSet": MemBytes }))
58			},
59
60			Err(_) => Ok(json!({ "private": 0, "shared": 0, "residentSet": 0 })),
61		}
62	}
63
64	#[cfg(target_os = "linux")]
65	{
66		match tokio::fs::read_to_string("/proc/self/statm").await {
67			Ok(Content) => {
68				let Parts:Vec<&str> = Content.split_whitespace().collect();
69
70				let PageSize:u64 = 4096;
71
72				let _Vsz = Parts.first().and_then(|V| V.parse::<u64>().ok()).unwrap_or(0) * PageSize;
73
74				let Rss = Parts.get(1).and_then(|V| V.parse::<u64>().ok()).unwrap_or(0) * PageSize;
75
76				let Shared = Parts.get(2).and_then(|V| V.parse::<u64>().ok()).unwrap_or(0) * PageSize;
77
78				Ok(json!({
79					"private": Rss.saturating_sub(Shared),
80					"shared": Shared,
81					"residentSet": Rss
82				}))
83			},
84
85			Err(_) => Ok(json!({ "private": 0, "shared": 0, "residentSet": 0 })),
86		}
87	}
88
89	#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))]
90	{
91		Ok(json!({ "private": 0, "shared": 0, "residentSet": 0 }))
92	}
93}