mecha10_core/discovery/
metadata.rs

1//! Node metadata types and builders for service discovery
2
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6/// Node status
7#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
8#[serde(rename_all = "lowercase")]
9pub enum NodeStatus {
10    /// Node is starting up
11    Starting,
12    /// Node is running and healthy
13    Running,
14    /// Node is stopping
15    Stopping,
16    /// Node has stopped
17    Stopped,
18    /// Node is unhealthy
19    Unhealthy,
20}
21
22/// Node metadata for service discovery
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct NodeMetadata {
25    /// Unique node identifier
26    pub node_id: String,
27
28    /// Node type (e.g., "camera_driver", "perception", "planning")
29    #[serde(default)]
30    pub node_type: String,
31
32    /// Current status
33    #[serde(default = "default_status")]
34    pub status: NodeStatus,
35
36    /// When the node started (Unix timestamp in seconds)
37    #[serde(default)]
38    pub started_at: u64,
39
40    /// Last heartbeat timestamp (Unix timestamp in seconds)
41    #[serde(default)]
42    pub last_heartbeat: u64,
43
44    /// Topics this node publishes to
45    #[serde(default)]
46    pub publishes: Vec<String>,
47
48    /// Topics this node subscribes to
49    #[serde(default)]
50    pub subscribes: Vec<String>,
51
52    /// Node capabilities/features
53    #[serde(default)]
54    pub capabilities: Vec<String>,
55
56    /// Additional metadata (version, config, etc.)
57    #[serde(default)]
58    pub metadata: HashMap<String, String>,
59}
60
61fn default_status() -> NodeStatus {
62    NodeStatus::Running
63}
64
65impl Default for NodeMetadata {
66    fn default() -> Self {
67        Self {
68            node_id: String::new(),
69            node_type: String::new(),
70            status: NodeStatus::Running,
71            started_at: current_timestamp(),
72            last_heartbeat: current_timestamp(),
73            publishes: Vec::new(),
74            subscribes: Vec::new(),
75            capabilities: Vec::new(),
76            metadata: HashMap::new(),
77        }
78    }
79}
80
81impl NodeMetadata {
82    /// Create new metadata for a node
83    pub fn new(node_id: impl Into<String>) -> Self {
84        Self {
85            node_id: node_id.into(),
86            ..Default::default()
87        }
88    }
89
90    /// Set node type
91    pub fn with_type(mut self, node_type: impl Into<String>) -> Self {
92        self.node_type = node_type.into();
93        self
94    }
95
96    /// Add a published topic
97    pub fn publishes(mut self, topic: impl Into<String>) -> Self {
98        self.publishes.push(topic.into());
99        self
100    }
101
102    /// Add a subscribed topic
103    pub fn subscribes(mut self, topic: impl Into<String>) -> Self {
104        self.subscribes.push(topic.into());
105        self
106    }
107
108    /// Add a capability
109    pub fn capability(mut self, cap: impl Into<String>) -> Self {
110        self.capabilities.push(cap.into());
111        self
112    }
113
114    /// Add metadata
115    pub fn metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
116        self.metadata.insert(key.into(), value.into());
117        self
118    }
119}
120
121/// Get current Unix timestamp in seconds
122pub(crate) fn current_timestamp() -> u64 {
123    std::time::SystemTime::now()
124        .duration_since(std::time::UNIX_EPOCH)
125        .unwrap()
126        .as_secs()
127}