mecha10-cli 0.1.47

Mecha10 CLI tool
Documentation
#![allow(dead_code)]

//! Discovery service for finding Mecha10 nodes on the network
//!
//! This service provides operations for discovering and monitoring Mecha10
//! nodes through Redis pub/sub and network scanning.

mod node_manager;
mod parser;
mod redis_ops;

use anyhow::Result;
use std::collections::HashMap;
use std::time::{Duration, SystemTime};

/// Information about a discovered node
#[derive(Debug, Clone)]
pub struct NodeInfo {
    pub node_id: String,
    pub node_type: String,
    pub host: String,
    pub port: u16,
    pub last_seen: SystemTime,
    pub metadata: HashMap<String, String>,
}

/// Discovery configuration
#[derive(Debug, Clone)]
pub struct DiscoveryConfig {
    pub redis_url: String,
    pub discovery_topic: String,
    pub heartbeat_interval: Duration,
    pub node_timeout: Duration,
    pub scan_subnet: Option<String>,
}

impl Default for DiscoveryConfig {
    fn default() -> Self {
        Self {
            redis_url: "redis://localhost:6379".to_string(),
            discovery_topic: "mecha10/discovery".to_string(),
            heartbeat_interval: Duration::from_secs(5),
            node_timeout: Duration::from_secs(30),
            scan_subnet: None,
        }
    }
}

/// Discovery service for finding Mecha10 nodes
///
/// # Examples
///
/// ```rust,ignore
/// use mecha10_cli::services::{DiscoveryService, DiscoveryConfig};
///
/// # async fn example() -> anyhow::Result<()> {
/// let service = DiscoveryService::new();
///
/// // Configure discovery
/// let config = DiscoveryConfig::default();
///
/// // Discover nodes
/// let nodes = service.discover(&config).await?;
/// for node in nodes {
///     println!("Found node: {} at {}:{}", node.node_id, node.host, node.port);
/// }
///
/// // Monitor for new nodes
/// service.monitor(&config, |node| {
///     println!("New node discovered: {}", node.node_id);
/// }).await?;
/// # Ok(())
/// # }
/// ```
pub struct DiscoveryService {
    discovered_nodes: HashMap<String, NodeInfo>,
}

impl DiscoveryService {
    /// Create a new discovery service
    pub fn new() -> Self {
        Self {
            discovered_nodes: HashMap::new(),
        }
    }

    /// Discover active nodes on the network
    ///
    /// # Arguments
    ///
    /// * `config` - Discovery configuration
    pub async fn discover(&mut self, config: &DiscoveryConfig) -> Result<Vec<NodeInfo>> {
        redis_ops::discover(config, &mut self.discovered_nodes).await
    }

    /// Monitor for new nodes
    ///
    /// # Arguments
    ///
    /// * `config` - Discovery configuration
    /// * `callback` - Function to call when a new node is discovered
    pub async fn monitor<F>(&mut self, config: &DiscoveryConfig, callback: F) -> Result<()>
    where
        F: FnMut(&NodeInfo),
    {
        redis_ops::monitor(config, &mut self.discovered_nodes, callback).await
    }

    /// Get list of currently known nodes
    pub fn get_nodes(&self) -> Vec<&NodeInfo> {
        node_manager::get_nodes(&self.discovered_nodes)
    }

    /// Get a specific node by ID
    ///
    /// # Arguments
    ///
    /// * `node_id` - Node identifier
    pub fn get_node(&self, node_id: &str) -> Option<&NodeInfo> {
        node_manager::get_node(&self.discovered_nodes, node_id)
    }

    /// Remove stale nodes that haven't sent heartbeats
    ///
    /// # Arguments
    ///
    /// * `timeout` - Maximum time since last heartbeat
    pub fn cleanup_stale_nodes(&mut self, timeout: Duration) -> usize {
        node_manager::cleanup_stale_nodes(&mut self.discovered_nodes, timeout)
    }

    /// Broadcast presence announcement
    ///
    /// # Arguments
    ///
    /// * `config` - Discovery configuration
    /// * `node_info` - Information about this node
    pub async fn announce(&self, config: &DiscoveryConfig, node_info: &NodeInfo) -> Result<()> {
        redis_ops::announce(config, node_info).await
    }

    /// Send heartbeat for a node
    ///
    /// # Arguments
    ///
    /// * `config` - Discovery configuration
    /// * `node_id` - Node identifier
    pub async fn heartbeat(&self, config: &DiscoveryConfig, node_id: &str) -> Result<()> {
        redis_ops::heartbeat(config, node_id).await
    }

    /// Get node count
    pub fn node_count(&self) -> usize {
        node_manager::node_count(&self.discovered_nodes)
    }

    /// Get nodes by type
    ///
    /// # Arguments
    ///
    /// * `node_type` - Type of nodes to filter
    pub fn get_nodes_by_type(&self, node_type: &str) -> Vec<&NodeInfo> {
        node_manager::get_nodes_by_type(&self.discovered_nodes, node_type)
    }

    /// Clear all discovered nodes
    pub fn clear(&mut self) {
        node_manager::clear(&mut self.discovered_nodes);
    }
}

impl Default for DiscoveryService {
    fn default() -> Self {
        Self::new()
    }
}