Skip to main content

modkit_node_info/
collector.rs

1use crate::error::NodeInfoError;
2use crate::model::{Node, NodeSysCap, NodeSysInfo};
3use crate::syscap_collector::SysCapCollector;
4use crate::sysinfo_collector::SysInfoCollector;
5use std::sync::Arc;
6
7/// Main collector for node information
8pub struct NodeInfoCollector {
9    sysinfo_collector: Arc<SysInfoCollector>,
10    syscap_collector: Arc<SysCapCollector>,
11}
12
13impl NodeInfoCollector {
14    #[must_use]
15    pub fn new() -> Self {
16        let sysinfo_collector = Arc::new(SysInfoCollector::new());
17        Self {
18            syscap_collector: Arc::new(SysCapCollector::new(Arc::clone(&sysinfo_collector))),
19            sysinfo_collector,
20        }
21    }
22
23    /// Create a Node instance for the current machine
24    /// Uses hardware UUID for node ID and collects hostname and local IP
25    #[must_use]
26    pub fn create_current_node() -> Node {
27        let id = crate::get_hardware_uuid();
28        let hostname = sysinfo::System::host_name().unwrap_or_else(|| "unknown".to_owned());
29        let ip_address = Self::detect_local_ip();
30        let now = chrono::Utc::now();
31
32        Node {
33            id,
34            hostname,
35            ip_address,
36            created_at: now,
37            updated_at: now,
38        }
39    }
40
41    /// Detect the local IP address used for the default route to the internet
42    /// This returns the IP address of the network interface that would be used
43    /// for outbound internet traffic, not the public external IP.
44    fn detect_local_ip() -> Option<String> {
45        match local_ip_address::local_ip() {
46            Ok(ip) => {
47                let ip_str = ip.to_string();
48                tracing::debug!(ip = %ip_str, "Detected local IP address");
49                Some(ip_str)
50            }
51            Err(e) => {
52                tracing::warn!(error = %e, "Failed to detect local IP address");
53                None
54            }
55        }
56    }
57
58    /// Collect system information for the current node.
59    ///
60    /// # Errors
61    /// Returns `NodeInfoError::SysInfoCollectionFailed` if system info collection fails.
62    pub fn collect_sysinfo(&self, node_id: uuid::Uuid) -> Result<NodeSysInfo, NodeInfoError> {
63        self.sysinfo_collector
64            .collect(node_id)
65            .map_err(|e| NodeInfoError::SysInfoCollectionFailed(e.to_string()))
66    }
67
68    /// Collect system capabilities for the current node.
69    ///
70    /// # Errors
71    /// Returns `NodeInfoError::SysCapCollectionFailed` if capability collection fails.
72    pub fn collect_syscap(&self, node_id: uuid::Uuid) -> Result<NodeSysCap, NodeInfoError> {
73        self.syscap_collector
74            .collect(node_id)
75            .map_err(|e| NodeInfoError::SysCapCollectionFailed(e.to_string()))
76    }
77
78    /// Collect both sysinfo and syscap.
79    ///
80    /// # Errors
81    /// Returns `NodeInfoError::SysInfoCollectionFailed` if system info collection fails.
82    /// Returns `NodeInfoError::SysCapCollectionFailed` if capability collection fails.
83    pub fn collect_all(
84        &self,
85        node_id: uuid::Uuid,
86    ) -> Result<(NodeSysInfo, NodeSysCap), NodeInfoError> {
87        let sysinfo = self.collect_sysinfo(node_id)?;
88        let syscap = self.collect_syscap(node_id)?;
89        Ok((sysinfo, syscap))
90    }
91}
92
93impl Default for NodeInfoCollector {
94    fn default() -> Self {
95        Self::new()
96    }
97}