mecha10-core 0.6.2

Mecha10 core runtime and foundational types
Documentation
//! Node metadata types and builders for service discovery

use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// Node status
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum NodeStatus {
    /// Node is starting up
    Starting,
    /// Node is running and healthy
    Running,
    /// Node is stopping
    Stopping,
    /// Node has stopped
    Stopped,
    /// Node is unhealthy
    Unhealthy,
}

/// Node metadata for service discovery
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NodeMetadata {
    /// Unique node identifier
    pub node_id: String,

    /// Node type (e.g., "camera_driver", "perception", "planning")
    #[serde(default)]
    pub node_type: String,

    /// Current status
    #[serde(default = "default_status")]
    pub status: NodeStatus,

    /// When the node started (Unix timestamp in seconds)
    #[serde(default)]
    pub started_at: u64,

    /// Last heartbeat timestamp (Unix timestamp in seconds)
    #[serde(default)]
    pub last_heartbeat: u64,

    /// Topics this node publishes to
    #[serde(default)]
    pub publishes: Vec<String>,

    /// Topics this node subscribes to
    #[serde(default)]
    pub subscribes: Vec<String>,

    /// Node capabilities/features
    #[serde(default)]
    pub capabilities: Vec<String>,

    /// Additional metadata (version, config, etc.)
    #[serde(default)]
    pub metadata: HashMap<String, String>,
}

fn default_status() -> NodeStatus {
    NodeStatus::Running
}

impl Default for NodeMetadata {
    fn default() -> Self {
        Self {
            node_id: String::new(),
            node_type: String::new(),
            status: NodeStatus::Running,
            started_at: current_timestamp(),
            last_heartbeat: current_timestamp(),
            publishes: Vec::new(),
            subscribes: Vec::new(),
            capabilities: Vec::new(),
            metadata: HashMap::new(),
        }
    }
}

impl NodeMetadata {
    /// Create new metadata for a node
    pub fn new(node_id: impl Into<String>) -> Self {
        Self {
            node_id: node_id.into(),
            ..Default::default()
        }
    }

    crate::builder_setter!(
        /// Set node type
        into, with_type, node_type, impl Into<String>
    );

    /// Add a published topic
    pub fn publishes(mut self, topic: impl Into<String>) -> Self {
        self.publishes.push(topic.into());
        self
    }

    /// Add a subscribed topic
    pub fn subscribes(mut self, topic: impl Into<String>) -> Self {
        self.subscribes.push(topic.into());
        self
    }

    /// Add a capability
    pub fn capability(mut self, cap: impl Into<String>) -> Self {
        self.capabilities.push(cap.into());
        self
    }

    crate::builder_setter!(
        /// Add metadata
        insert, metadata, metadata, impl Into<String>, impl Into<String>
    );
}

/// Get current Unix timestamp in seconds
pub(crate) fn current_timestamp() -> u64 {
    crate::prelude::now_secs()
}