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::models::{CacheType, DatabaseType, SearchType, ServiceRole, ServiceType};

pub struct ServiceSignature {
    pub port: u16,
    pub process_pattern: &'static str,
    pub service_type: ServiceType,
    pub name: &'static str,
    pub systemd_unit: Option<&'static str>,
    pub role: ServiceRole,
}

pub struct ServiceSignatures;

impl ServiceSignatures {
    pub fn all() -> Vec<ServiceSignature> {
        vec![
            // Databases
            ServiceSignature {
                port: 5432,
                process_pattern: "postgres",
                service_type: ServiceType::Database { database: DatabaseType::Postgres },
                name: "PostgreSQL",
                systemd_unit: Some("postgresql.service"),
                role: ServiceRole::Database,
            },
            ServiceSignature {
                port: 3306,
                process_pattern: "mysqld",
                service_type: ServiceType::Database { database: DatabaseType::MySQL },
                name: "MySQL",
                systemd_unit: Some("mysql.service"),
                role: ServiceRole::Database,
            },
            ServiceSignature {
                port: 27017,
                process_pattern: "mongod",
                service_type: ServiceType::Database { database: DatabaseType::MongoDB },
                name: "MongoDB",
                systemd_unit: Some("mongod.service"),
                role: ServiceRole::Database,
            },
            // Cache/Queue
            ServiceSignature {
                port: 6379,
                process_pattern: "redis-server",
                service_type: ServiceType::Cache { cache: CacheType::Redis },
                name: "Redis",
                systemd_unit: Some("redis-server.service"),
                role: ServiceRole::Cache,
            },
            ServiceSignature {
                port: 11211,
                process_pattern: "memcached",
                service_type: ServiceType::Cache { cache: CacheType::Memcached },
                name: "Memcached",
                systemd_unit: Some("memcached.service"),
                role: ServiceRole::Cache,
            },
            // Search
            ServiceSignature {
                port: 9200,
                process_pattern: "elasticsearch",
                service_type: ServiceType::Search { search: SearchType::Elasticsearch },
                name: "Elasticsearch",
                systemd_unit: Some("elasticsearch.service"),
                role: ServiceRole::Unknown, // Search engines are typically backend
            },
            ServiceSignature {
                port: 7700,
                process_pattern: "meilisearch",
                service_type: ServiceType::Search { search: SearchType::Meilisearch },
                name: "Meilisearch",
                systemd_unit: Some("meilisearch.service"),
                role: ServiceRole::Unknown,
            },
            // Development servers - Frontend
            ServiceSignature {
                port: 3000,
                process_pattern: "node",
                service_type: ServiceType::HttpServer,
                name: "Node.js Dev Server",
                systemd_unit: None,
                role: ServiceRole::Frontend, // Common React/Next.js port
            },
            ServiceSignature {
                port: 4200,
                process_pattern: "node",
                service_type: ServiceType::HttpServer,
                name: "Angular Dev Server",
                systemd_unit: None,
                role: ServiceRole::Frontend,
            },
            ServiceSignature {
                port: 5173,
                process_pattern: "node",
                service_type: ServiceType::HttpServer,
                name: "Vite Dev Server",
                systemd_unit: None,
                role: ServiceRole::Frontend,
            },
            // Development servers - Backend
            ServiceSignature {
                port: 8000,
                process_pattern: "python",
                service_type: ServiceType::HttpServer,
                name: "Python Dev Server",
                systemd_unit: None,
                role: ServiceRole::Backend,
            },
            ServiceSignature {
                port: 8080,
                process_pattern: "java",
                service_type: ServiceType::HttpServer,
                name: "Java Server",
                systemd_unit: None,
                role: ServiceRole::Backend,
            },
        ]
    }

    pub fn find_by_port(port: u16) -> Option<ServiceSignature> {
        Self::all().into_iter().find(|sig| sig.port == port)
    }

    pub fn find_by_process(process_name: &str) -> Option<ServiceSignature> {
        Self::all()
            .into_iter()
            .find(|sig| process_name.contains(sig.process_pattern))
    }

    /// Infer service role from port and process name
    pub fn infer_role(port: u16, process_name: Option<&str>, service_type: &ServiceType) -> ServiceRole {
        // Check if we have a signature match
        if let Some(sig) = Self::find_by_port(port) {
            return sig.role;
        }
        
        if let Some(process_name) = process_name {
            if let Some(sig) = Self::find_by_process(process_name) {
                return sig.role;
            }
            
            // Heuristic: Check process name for frontend indicators
            let process_lower = process_name.to_lowercase();
            if process_lower.contains("vite") || process_lower.contains("webpack") 
                || process_lower.contains("next") || process_lower.contains("react")
                || process_lower.contains("angular") || process_lower.contains("vue") {
                return ServiceRole::Frontend;
            }
            
            // Heuristic: Check process name for backend indicators
            if process_lower.contains("python") || process_lower.contains("java")
                || process_lower.contains("go") || process_lower.contains("rust")
                || process_lower.contains("node") && !process_lower.contains("vite")
                && !process_lower.contains("webpack") && !process_lower.contains("next") {
                return ServiceRole::Backend;
            }
        }
        
        // Port-based heuristics
        if (3000..=4000).contains(&port) || port == 5173 || port == 4200 {
            return ServiceRole::Frontend;
        }
        
        if (8000..=9000).contains(&port) || port == 5000 {
            return ServiceRole::Backend;
        }
        
        // Type-based inference
        match service_type {
            ServiceType::Database { .. } => ServiceRole::Database,
            ServiceType::Cache { .. } => ServiceRole::Cache,
            _ => ServiceRole::Unknown,
        }
    }
}