use async_trait::async_trait;
use crate::event::{ServiceKind, ServiceMetric};
use crate::ssh::probe::ProbeOutput;
pub mod docker;
pub mod nginx;
pub mod nodejs;
pub mod postgresql;
pub mod redis;
#[async_trait]
pub trait ServiceProvider: Send + Sync {
fn kind(&self) -> ServiceKind;
fn detect(&self, probe_output: &ProbeOutput) -> bool;
fn quick_metrics(&self, _probe_output: &ProbeOutput) -> Vec<ServiceMetric> {
Vec::new()
}
}
pub struct ServiceRegistry {
providers: Vec<Box<dyn ServiceProvider>>,
}
impl ServiceRegistry {
pub fn new() -> Self {
let providers: Vec<Box<dyn ServiceProvider>> = vec![
Box::new(docker::DockerProvider),
Box::new(nginx::NginxProvider),
Box::new(postgresql::PostgreSQLProvider),
Box::new(redis::RedisProvider),
Box::new(nodejs::NodeJSProvider),
];
Self { providers }
}
pub fn detect_services(&self, probe_output: &ProbeOutput) -> Vec<ServiceKind> {
self.providers
.iter()
.filter(|p| p.detect(probe_output))
.map(|p| p.kind())
.collect()
}
pub fn get_provider(&self, kind: &ServiceKind) -> Option<&dyn ServiceProvider> {
self.providers
.iter()
.find(|p| &p.kind() == kind)
.map(|boxed| &**boxed)
}
}
impl Default for ServiceRegistry {
fn default() -> Self {
Self::new()
}
}
pub fn metric_int(name: impl Into<String>, value: i64) -> ServiceMetric {
ServiceMetric {
name: name.into(),
value: crate::event::MetricValue::Integer(value),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_registry_creation() {
let registry = ServiceRegistry::new();
assert_eq!(registry.providers.len(), 5); }
#[test]
fn test_registry_get_provider() {
let registry = ServiceRegistry::new();
assert!(registry.get_provider(&ServiceKind::Docker).is_some());
assert!(registry.get_provider(&ServiceKind::Nginx).is_some());
assert!(registry.get_provider(&ServiceKind::PostgreSQL).is_some());
assert!(registry.get_provider(&ServiceKind::Redis).is_some());
assert!(registry.get_provider(&ServiceKind::NodeJS).is_some());
}
}