1use std::process::Command;
2
3use anyhow::Context as _;
4
5pub fn detect_machine_id() -> anyhow::Result<String> {
6 if let Ok(val) = std::env::var("AGENTPACK_MACHINE_ID") {
7 let id = normalize_machine_id(&val);
8 if !id.is_empty() {
9 return Ok(id);
10 }
11 }
12
13 if let Ok(val) = std::env::var("HOSTNAME") {
14 let id = normalize_machine_id(&val);
15 if !id.is_empty() {
16 return Ok(id);
17 }
18 }
19
20 if let Ok(val) = std::env::var("COMPUTERNAME") {
21 let id = normalize_machine_id(&val);
22 if !id.is_empty() {
23 return Ok(id);
24 }
25 }
26
27 let out = Command::new("hostname").output().context("run hostname")?;
28 if out.status.success() {
29 let raw = String::from_utf8_lossy(&out.stdout);
30 let id = normalize_machine_id(&raw);
31 if !id.is_empty() {
32 return Ok(id);
33 }
34 }
35
36 Ok("unknown".to_string())
37}
38
39pub fn normalize_machine_id(s: &str) -> String {
40 let raw = s.trim().to_lowercase();
41 let mut out = String::new();
42 let mut last_dash = false;
43 for ch in raw.chars() {
44 let ok = ch.is_ascii_alphanumeric() || ch == '-' || ch == '_';
45 let normalized = if ok {
46 ch
47 } else if !last_dash {
48 '-'
49 } else {
50 continue;
51 };
52
53 last_dash = normalized == '-';
54 out.push(normalized);
55 }
56 out.trim_matches('-').to_string()
57}