use std::sync::OnceLock;
const TEST_SEAM_ENV: &str = "OPENLATCH_TEST_HOSTNAME";
const MAX_HOSTNAME_LEN: usize = 253;
static HOSTNAME: OnceLock<Option<String>> = OnceLock::new();
pub fn hostname() -> Option<String> {
HOSTNAME.get_or_init(resolve).clone()
}
fn resolve() -> Option<String> {
std::env::var(TEST_SEAM_ENV)
.ok()
.filter(|v| !v.is_empty())
.or_else(system_hostname)
.filter(|name| name.len() <= MAX_HOSTNAME_LEN)
}
pub fn system_hostname() -> Option<String> {
#[cfg(unix)]
{
use std::ffi::CStr;
let mut buf = [0u8; 256];
let ret = unsafe { libc::gethostname(buf.as_mut_ptr() as *mut libc::c_char, buf.len()) };
if ret != 0 {
return None;
}
let s = CStr::from_bytes_until_nul(&buf).ok()?.to_str().ok()?.trim();
if s.is_empty() {
None
} else {
Some(s.to_string())
}
}
#[cfg(windows)]
{
let s = std::env::var("COMPUTERNAME").ok()?;
let trimmed = s.trim();
if trimmed.is_empty() {
None
} else {
Some(trimmed.to_string())
}
}
#[cfg(not(any(unix, windows)))]
{
None
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::daemon::identity::test_support::EnvGuard;
use crate::daemon::identity::ENV_LOCK;
#[test]
fn seam_is_honoured_and_an_over_long_name_is_omitted() {
let _lock = ENV_LOCK.blocking_lock();
let env = EnvGuard::clear();
env.set(TEST_SEAM_ENV, "devbox-01");
assert_eq!(resolve().as_deref(), Some("devbox-01"));
env.set(TEST_SEAM_ENV, "");
assert_ne!(resolve().as_deref(), Some(""));
assert_eq!(resolve(), system_hostname());
env.unset(TEST_SEAM_ENV);
let at_limit = "a".repeat(MAX_HOSTNAME_LEN);
env.set(TEST_SEAM_ENV, &at_limit);
assert_eq!(resolve().as_deref(), Some(at_limit.as_str()));
let past_limit = "a".repeat(MAX_HOSTNAME_LEN + 1);
env.set(TEST_SEAM_ENV, &past_limit);
assert_eq!(resolve(), None);
}
#[test]
fn the_real_hostname_is_a_name_or_nothing() {
let _lock = ENV_LOCK.blocking_lock();
let _env = EnvGuard::clear();
#[cfg(unix)]
assert!(
matches!(system_hostname().as_deref(), Some(s) if !s.is_empty()),
"a real host resolves to a real name, never None or an empty string"
);
#[cfg(windows)]
assert_eq!(
system_hostname(),
None,
"with COMPUTERNAME cleared there is no name to find"
);
}
}