use async_trait::async_trait;
use revoke_core::{HealthStatus, Result, ServiceInfo, ServiceRegistry, Status};
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use tracing::info;
use uuid::Uuid;
pub struct MemoryRegistry {
services: Arc<RwLock<HashMap<String, Vec<ServiceInfo>>>>,
health_status: Arc<RwLock<HashMap<Uuid, HealthStatus>>>,
}
impl MemoryRegistry {
pub fn new() -> Self {
Self {
services: Arc::new(RwLock::new(HashMap::new())),
health_status: Arc::new(RwLock::new(HashMap::new())),
}
}
}
impl Default for MemoryRegistry {
fn default() -> Self {
Self::new()
}
}
#[async_trait]
impl ServiceRegistry for MemoryRegistry {
async fn register(&self, service: ServiceInfo) -> Result<()> {
let mut services = self.services.write().await;
services
.entry(service.name.clone())
.or_insert_with(Vec::new)
.push(service.clone());
info!("Service {} registered with ID {}", service.name, service.id);
Ok(())
}
async fn deregister(&self, service_id: Uuid) -> Result<()> {
let mut services = self.services.write().await;
for (_, service_list) in services.iter_mut() {
service_list.retain(|s| s.id != service_id);
}
let mut health = self.health_status.write().await;
health.remove(&service_id);
info!("Service {} deregistered", service_id);
Ok(())
}
async fn get_service(&self, name: &str) -> Result<Vec<ServiceInfo>> {
let services = self.services.read().await;
let health = self.health_status.read().await;
Ok(services
.get(name)
.map(|list| {
list.iter()
.filter(|s| {
health
.get(&s.id)
.map(|h| h.status == Status::Healthy)
.unwrap_or(true)
})
.cloned()
.collect()
})
.unwrap_or_default())
}
async fn update_health(&self, status: HealthStatus) -> Result<()> {
let mut health = self.health_status.write().await;
health.insert(status.service_id, status);
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use revoke_core::Protocol;
#[tokio::test]
async fn test_memory_registry() {
let registry = MemoryRegistry::new();
let service = ServiceInfo {
id: Uuid::new_v4(),
name: "test-service".to_string(),
version: "1.0.0".to_string(),
address: "127.0.0.1".to_string(),
port: 8080,
protocol: Protocol::Http,
metadata: HashMap::new(),
};
registry.register(service.clone()).await.unwrap();
let services = registry.get_service("test-service").await.unwrap();
assert_eq!(services.len(), 1);
assert_eq!(services[0].id, service.id);
registry.deregister(service.id).await.unwrap();
let services = registry.get_service("test-service").await.unwrap();
assert_eq!(services.len(), 0);
}
}