pipeworks_core/
node_id.rs

1use anyhow::{Context, Result};
2use bitcode::{Decode, Encode};
3use core::fmt;
4use once_cell::sync::Lazy;
5use rand::RngCore;
6use std::fs;
7use std::path::PathBuf;
8
9pub static NODE_ID: Lazy<NodeId> = Lazy::new(|| NodeId::new());
10
11#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
12pub struct Id([u8; 32]);
13
14#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
15pub struct NodeId {
16    pub node: Id,
17    pub machine: Id,
18}
19
20impl Id {
21    pub fn new() -> Self {
22        let mut rng = rand::rng();
23        let mut new_id = [0u8; 32];
24        rng.fill_bytes(&mut new_id);
25
26        Self(new_id)
27    }
28
29    pub fn new_fs(path: &PathBuf) -> Result<Self> {
30        let id = Self::new();
31
32        // Create the parent directory if we need to
33        if let Some(parent) = path.parent() {
34            if !parent.exists() {
35                fs::create_dir_all(parent).with_context(|| parent.to_string_lossy().to_string())?;
36            }
37        }
38
39        fs::write(path, bitcode::encode(&id))?;
40
41        Ok(id)
42    }
43
44    pub fn load_from_path(path: &PathBuf) -> Result<Self> {
45        Ok(bitcode::decode(&fs::read(path)?)?)
46    }
47}
48
49impl NodeId {
50    pub fn new() -> Self {
51        let path = dirs::home_dir()
52            .expect("Could not find home directory")
53            .join(".local/share/wlabs/machine_id");
54
55        Self {
56            node: Id::new(),
57            machine: Id::load_from_path(&path)
58                .or_else(|_| Id::new_fs(&path))
59                .unwrap(),
60        }
61    }
62
63    pub fn is_me(&self) -> bool {
64        self.node == NODE_ID.node
65    }
66
67    pub fn is_my_machine(&self) -> bool {
68        self.machine == NODE_ID.machine
69    }
70}
71
72impl fmt::Display for NodeId {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        match (self.is_me(), self.is_my_machine()) {
75            (true, true) => write!(f, "Self")?,
76            (true, false) => write!(f, "ERR(Self ID on different machine)")?,
77            (false, true) => write!(f, "[Id {}]", self.node)?,
78            (false, false) => write!(f, "[Id {} on LAN {}]", self.node, self.machine)?,
79        }
80
81        Ok(())
82    }
83}
84
85impl fmt::Debug for NodeId {
86    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87        write!(f, "NodeId(")?;
88        <Self as fmt::Display>::fmt(self, f)?;
89        write!(f, ")")
90    }
91}
92
93impl fmt::Display for Id {
94    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95        for byte in &self.0[0..2] {
96            write!(f, "{:02x}", byte)?;
97        }
98        Ok(())
99    }
100}
101
102impl fmt::Debug for Id {
103    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104        write!(f, "MachineId(")?;
105        <Self as fmt::Display>::fmt(self, f)?;
106        write!(f, ")")
107    }
108}