darpan 0.2.4

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::{ConfigLoader, ProjectConfig, UserConfig};
use crate::core::registry::ServiceRegistry;
use crate::detectors::{ConfigDetector, DetectorTrait, DockerDetector, PortDetector, ProcessDetector};
use crate::health::HealthChecker;
use anyhow::Result;
use std::path::PathBuf;
use tracing::{debug, info};

pub struct CoreEngine {
    project_path: PathBuf,
    registry: ServiceRegistry,
    user_config: UserConfig,
    project_config: Option<ProjectConfig>,
    detectors: Vec<Box<dyn DetectorTrait>>,
    health_checker: HealthChecker,
}

impl CoreEngine {
    pub fn new(project_path: PathBuf) -> Result<Self> {
        info!("Initializing Darpan for project: {:?}", project_path);
        
        let user_config = ConfigLoader::load_user_config()?;
        let project_config = ConfigLoader::load_project_config(&project_path)?;
        
        let mut detectors: Vec<Box<dyn DetectorTrait>> = Vec::new();
        
        // Initialize detectors based on user config
        if user_config.detection.enabled_detectors.contains(&"config".to_string()) {
            detectors.push(Box::new(ConfigDetector::new()));
        }
        if user_config.detection.enabled_detectors.contains(&"port".to_string()) {
            detectors.push(Box::new(PortDetector::new(
                user_config.detection.port_range.0,
                user_config.detection.port_range.1,
            )));
        }
        if user_config.detection.enabled_detectors.contains(&"process".to_string()) {
            detectors.push(Box::new(ProcessDetector::new()));
        }
        if user_config.detection.enabled_detectors.contains(&"docker".to_string()) {
            detectors.push(Box::new(DockerDetector::new()));
        }
        
        let health_checker = HealthChecker::new(
            std::time::Duration::from_secs(user_config.health_checks.timeout),
            user_config.health_checks.retry_count,
        );
        
        Ok(Self {
            project_path,
            registry: ServiceRegistry::new(),
            user_config,
            project_config,
            detectors,
            health_checker,
        })
    }

    pub async fn detect_services(&mut self) -> Result<()> {
        info!("Starting service detection");
        self.registry.clear();
        
        for detector in &self.detectors {
            debug!("Running detector: {}", detector.name());
            let services = detector.detect(&self.project_path, self.project_config.as_ref()).await?;
            debug!("Detector {} found {} services", detector.name(), services.len());
            
            for service in services {
                self.registry.merge_or_update(service);
            }
        }
        
        info!("Detection complete. Found {} services", self.registry.count());
        Ok(())
    }

    pub async fn check_health(&mut self) -> Result<()> {
        info!("Starting health checks");
        
        for service in self.registry.all_services_mut() {
            let health_result = self.health_checker.check(service).await;
            service.health_status = Some(health_result);
        }
        
        info!("Health checks complete");
        Ok(())
    }

    pub async fn refresh(&mut self) -> Result<()> {
        self.detect_services().await?;
        self.check_health().await?;
        Ok(())
    }

    pub fn get_registry(&self) -> &ServiceRegistry {
        &self.registry
    }

    pub fn get_registry_mut(&mut self) -> &mut ServiceRegistry {
        &mut self.registry
    }

    pub fn project_path(&self) -> &PathBuf {
        &self.project_path
    }

    pub fn user_config(&self) -> &UserConfig {
        &self.user_config
    }

    pub fn project_config(&self) -> Option<&ProjectConfig> {
        self.project_config.as_ref()
    }
}