darpan 0.2.5

Linux developer service monitoring utility with auto-detection, real-time health checks, and interactive TUI for databases, APIs, Docker containers, and more
Documentation
use crate::config::ProjectConfig;
use crate::detectors::DetectorTrait;
use crate::models::{DetectionSource, HealthCheckConfig, Service};
use crate::utils::ServiceSignatures;
use anyhow::Result;
use async_trait::async_trait;
use std::path::Path;
use tracing::debug;

pub struct ConfigDetector;

impl ConfigDetector {
    pub fn new() -> Self {
        Self
    }
}

#[async_trait]
impl DetectorTrait for ConfigDetector {
    fn name(&self) -> &str {
        "ConfigDetector"
    }

    fn priority(&self) -> i32 {
        100  // Highest priority - explicit config should override auto-detection
    }

    async fn detect(&self, project_path: &Path, config: Option<&ProjectConfig>) -> Result<Vec<Service>> {
        let mut services = Vec::new();
        
        if let Some(project_config) = config {
            debug!("Loading services from .darpan.yml");
            
            for service_config in &project_config.services {
                // Use role from config if provided, otherwise infer it
                let role = service_config.role.unwrap_or_else(|| {
                    ServiceSignatures::infer_role(
                        service_config.port,
                        service_config.process.as_deref(),
                        &service_config.service_type,
                    )
                });
                
                let mut service = Service::new_with_role(
                    service_config.name.clone(),
                    service_config.service_type.clone(),
                    service_config.host.clone().unwrap_or_else(|| "localhost".to_string()),
                    service_config.port,
                    DetectionSource::ExplicitConfig,
                    project_path.to_string_lossy().to_string(),
                    role,
                );
                
                if let Some(process) = &service_config.process {
                    service.command_line = Some(process.clone());
                }
                
                if let Some(health_check) = &service_config.health_check {
                    service.health_check = health_check.clone();
                } else {
                    service.health_check = HealthCheckConfig::default();
                }
                
                service.tags = service_config.tags.clone();
                
                if let Some(additional_ports) = &service_config.additional_ports {
                    service.additional_ports = additional_ports.clone();
                }
                
                services.push(service);
                debug!("Loaded service '{}' from config", service_config.name);
            }
            
            // Handle dependencies
            if let Some(deps) = &project_config.dependencies {
                for dep_config in deps {
                    if let Some(service) = services.iter_mut().find(|s| s.name == dep_config.service) {
                        service.dependencies = dep_config.depends_on.clone();
                    }
                }
            }
        }
        
        Ok(services)
    }
}