mecha10-dev 0.6.2

Mecha10 dev services — node discovery, topology analysis, and dev mode support
Documentation
//! Redis connection and service port extraction

use anyhow::Result;
use regex::Regex;

use crate::types::ProjectConfig;

use super::{RedisInfo, ServiceInfo, TopologyService};

impl TopologyService {
    /// Parse Redis URL into components
    ///
    /// Note: This method is public primarily for testing purposes.
    pub fn parse_redis_url(&self, url: &str) -> Result<RedisInfo> {
        // Handle redis://host:port format
        let url_pattern = Regex::new(r"redis://([^:]+):(\d+)")?;

        if let Some(caps) = url_pattern.captures(url) {
            let host = caps.get(1).map(|m| m.as_str()).unwrap_or("localhost");
            let port = caps.get(2).and_then(|m| m.as_str().parse::<u16>().ok()).unwrap_or(6379);

            Ok(RedisInfo {
                url: url.to_string(),
                host: host.to_string(),
                port,
            })
        } else {
            // Default fallback
            Ok(RedisInfo {
                url: url.to_string(),
                host: "localhost".to_string(),
                port: 6379,
            })
        }
    }

    /// Extract service port information from config
    pub(super) fn extract_services(&self, config: &ProjectConfig) -> Vec<ServiceInfo> {
        let mut services = Vec::new();

        // HTTP API service
        if let Some(http_api) = &config.services.http_api {
            services.push(ServiceInfo {
                name: "HTTP API".to_string(),
                host: http_api.host.clone(),
                port: http_api.port,
            });
        }

        // Database service
        if let Some(db) = &config.services.database {
            // Try to parse postgres://host:port or similar
            if let Some(port) = self.extract_port_from_url(&db.url) {
                services.push(ServiceInfo {
                    name: "Database".to_string(),
                    host: self
                        .extract_host_from_url(&db.url)
                        .unwrap_or_else(|| "localhost".to_string()),
                    port,
                });
            }
        }

        services
    }

    /// Extract host from a URL string
    fn extract_host_from_url(&self, url: &str) -> Option<String> {
        let re = Regex::new(r"://([^:/@]+)").ok()?;
        re.captures(url)
            .and_then(|caps| caps.get(1).map(|m| m.as_str().to_string()))
    }

    /// Extract port from a URL string
    fn extract_port_from_url(&self, url: &str) -> Option<u16> {
        let re = Regex::new(r":(\d+)").ok()?;
        re.captures(url)
            .and_then(|caps| caps.get(1))
            .and_then(|m| m.as_str().parse().ok())
    }
}