1use serde::Deserialize;
2
3#[derive(Deserialize)]
4pub struct Envelope {
5 pub success: bool,
6 pub data: serde_json::Value,
7 pub error: Option<String>,
8 pub meta: Option<Meta>,
9}
10
11#[derive(Deserialize)]
12pub struct Meta {
13 pub duration_ms: Option<f64>,
14 pub daemon_rss_kb: Option<u64>,
15 pub daemon_uptime_secs: Option<u64>,
16 pub daemon_connections: Option<u32>,
17}
18
19pub fn daemon_alive(port: u16) -> bool {
20 let url = format!("http://127.0.0.1:{}/api/health", port);
21 reqwest::blocking::get(&url).is_ok()
22}
23
24pub fn health(port: u16, json_output: bool) -> Result<(), Box<dyn std::error::Error>> {
25 let url = format!("http://127.0.0.1:{}/api/health", port);
26 match reqwest::blocking::get(&url) {
27 Ok(resp) => {
28 if let Ok(e) = resp.json::<Envelope>() {
29 if e.success {
30 let d = &e.data;
31 let pid = d.get("pid").and_then(|v| v.as_u64()).unwrap_or(0);
32 let rss = d.get("rss_kb").and_then(|v| v.as_u64()).unwrap_or(0);
33 let uptime = d.get("uptime_secs").and_then(|v| v.as_u64()).unwrap_or(0);
34 let conns = d.get("connections").and_then(|v| v.as_u64()).unwrap_or(0);
35 let ver = d.get("version").and_then(|v| v.as_str()).unwrap_or("?");
36 if json_output {
37 println!("{}", serde_json::to_string_pretty(&e.data)?);
38 } else {
39 let rss_mb = rss as f64 / 1024.0;
40 let (uptime_str, _) = format_duration(uptime);
41 println!(" ● nomad-daemon: RUNNING");
42 println!(" PID: {pid}");
43 println!(" Port: {port}");
44 println!(" RSS: {rss_mb:.1} MB");
45 println!(" Uptime: {uptime_str}");
46 println!(" Conns: {conns}");
47 println!(" Ver: {ver}");
48 }
49 } else {
50 let err = e.error.unwrap_or_else(|| "unknown".into());
51 if json_output {
52 println!(r#"{{"running":false,"error":"{err}"}}"#);
53 } else {
54 println!(" ● nomad-daemon: ERROR {err}");
55 }
56 }
57 }
58 }
59 Err(_) => {
60 if json_output {
61 println!(r#"{{"running":false}}"#);
62 } else {
63 println!(" ● nomad-daemon: STOPPED. Start with: nom daemon start");
64 }
65 }
66 }
67 Ok(())
68}
69
70fn format_duration(secs: u64) -> (String, u64) {
71 let h = secs / 3600;
72 let m = (secs % 3600) / 60;
73 let s = secs % 60;
74 if h > 0 {
75 (format!("{h}h {m}m"), secs)
76 } else if m > 0 {
77 (format!("{m}m {s}s"), secs)
78 } else {
79 (format!("{s}s"), secs)
80 }
81}