use rand::RngCore;
#[cfg(target_os = "macos")]
use sysctl::{Sysctl, SysctlError};
pub fn get() -> [u8; 3] {
let id = match machine_id().unwrap_or_default() {
x if !x.is_empty() => x,
_ => hostname_fallback(),
};
let mut bytes = [0_u8; 3];
if id.is_empty() {
rand::thread_rng().fill_bytes(&mut bytes);
} else {
bytes.copy_from_slice(&md5::compute(id)[0..3]);
}
bytes
}
#[cfg(not(target_arch = "wasm32"))]
fn hostname_fallback() -> String {
hostname::get()
.map(|s| s.into_string().unwrap_or_default())
.unwrap_or_default()
}
#[cfg(target_arch = "wasm32")]
fn hostname_fallback() -> String {
"".to_owned()
}
#[cfg(target_os = "linux")]
fn machine_id() -> std::io::Result<String> {
use std::fs;
fs::read_to_string("/var/lib/dbus/machine-id")
.or_else(|_| fs::read_to_string("/etc/machine-id"))
.map(|s| s.trim_end().to_string())
}
#[cfg(target_os = "macos")]
fn machine_id() -> Result<String, SysctlError> {
sysctl::Ctl::new("kern.uuid")?
.value()
.map(|v| v.to_string())
}
#[cfg(target_os = "windows")]
fn machine_id() -> std::io::Result<String> {
let hklm = winreg::RegKey::predef(winreg::enums::HKEY_LOCAL_MACHINE);
let guid: String = hklm
.open_subkey("SOFTWARE\\Microsoft\\Cryptography")?
.get_value("MachineGuid")?;
Ok(guid)
}
#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
fn machine_id() -> std::io::Result<String> {
Ok("".to_string())
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(target_os = "linux")]
#[test]
fn test_linux() {
assert_eq!(machine_id().unwrap().len(), 32);
}
#[cfg(target_os = "macos")]
#[test]
fn test_macos() {
assert!(machine_id().unwrap().len() > 0);
}
#[cfg(target_os = "windows")]
#[test]
fn test_windows() {
assert_eq!(machine_id().unwrap().len(), 36);
}
}