nd_300/diagnostics/
shared_cache.rs1use std::collections::HashMap;
2
3pub struct SharedCache {
7 pub netstat: Option<NetstatCache>,
8 pub ipconfig: Option<IpconfigCache>,
9 pub sysinfo_networks: Option<sysinfo::Networks>,
10 pub gateway_ip: Option<String>,
11}
12
13pub struct NetstatCache {
15 pub lines: Vec<String>,
16 pub process_map: HashMap<u32, String>,
17}
18
19pub struct IpconfigCache {
21 pub raw: String,
22}
23
24impl SharedCache {
25 pub async fn build_for_tech_mode() -> Self {
28 let (netstat, ipconfig, networks, gateway) = tokio::join!(
29 fetch_netstat(),
30 fetch_ipconfig(),
31 fetch_sysinfo_networks(),
32 fetch_gateway(),
33 );
34
35 Self {
36 netstat,
37 ipconfig,
38 sysinfo_networks: networks,
39 gateway_ip: gateway,
40 }
41 }
42}
43
44#[cfg(windows)]
47async fn fetch_netstat() -> Option<NetstatCache> {
48 use sysinfo::System;
49
50 let mut cmd = tokio::process::Command::new("netstat");
51 cmd.args(["-ano"]);
52 let output = super::util::run_with_timeout(cmd, super::util::QUICK).await?;
53
54 let text = String::from_utf8_lossy(&output.stdout);
55 let lines: Vec<String> = text.lines().map(|l| l.to_string()).collect();
56
57 let process_map = tokio::task::spawn_blocking(|| {
59 let mut sys = System::new();
60 sys.refresh_processes(sysinfo::ProcessesToUpdate::All, true);
61 let mut map = HashMap::new();
62 for (pid, process) in sys.processes() {
63 map.insert(pid.as_u32(), process.name().to_string_lossy().to_string());
64 }
65 map
66 })
67 .await
68 .unwrap_or_default();
69
70 Some(NetstatCache { lines, process_map })
71}
72
73#[cfg(target_os = "macos")]
74async fn fetch_netstat() -> Option<NetstatCache> {
75 let mut cmd = tokio::process::Command::new("netstat");
76 cmd.args(["-anp", "tcp"]);
77 let output = super::util::run_with_timeout(cmd, super::util::QUICK).await?;
78
79 let text = String::from_utf8_lossy(&output.stdout);
80 let lines: Vec<String> = text.lines().map(|l| l.to_string()).collect();
81
82 Some(NetstatCache {
83 lines,
84 process_map: HashMap::new(),
85 })
86}
87
88#[cfg(target_os = "linux")]
89async fn fetch_netstat() -> Option<NetstatCache> {
90 let mut cmd = tokio::process::Command::new("netstat");
93 cmd.args(["-an"]);
94 let output = super::util::run_with_timeout(cmd, super::util::QUICK).await?;
95
96 let text = String::from_utf8_lossy(&output.stdout);
97 let lines: Vec<String> = text.lines().map(|l| l.to_string()).collect();
98
99 Some(NetstatCache {
100 lines,
101 process_map: HashMap::new(),
102 })
103}
104
105#[cfg(windows)]
108async fn fetch_ipconfig() -> Option<IpconfigCache> {
109 let mut cmd = tokio::process::Command::new("ipconfig");
110 cmd.args(["/all"]);
111 let output = super::util::run_with_timeout(cmd, super::util::QUICK).await?;
112
113 let raw = String::from_utf8_lossy(&output.stdout).to_string();
114 Some(IpconfigCache { raw })
115}
116
117#[cfg(not(windows))]
118async fn fetch_ipconfig() -> Option<IpconfigCache> {
119 None
121}
122
123async fn fetch_sysinfo_networks() -> Option<sysinfo::Networks> {
126 tokio::task::spawn_blocking(|| Some(sysinfo::Networks::new_with_refreshed_list()))
131 .await
132 .unwrap_or(None)
133}
134
135async fn fetch_gateway() -> Option<String> {
138 tokio::task::spawn_blocking(|| {
141 default_net::get_default_gateway()
142 .ok()
143 .map(|gw| gw.ip_addr.to_string())
144 })
145 .await
146 .unwrap_or(None)
147}