Skip to main content

Mountain/Binary/IPC/ProcessCommand/
process_get_memory_info.rs

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