use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use thiserror::Error;
pub(crate) mod bootstrap;
#[derive(Error, Debug, Clone)]
pub enum RegistryError {
#[error("服务 '{name}' 已存在")]
ServiceAlreadyExists {
name: String,
},
#[error("服务 '{name}' 不存在")]
ServiceNotFound {
name: String,
},
#[error("循环依赖检测: {dependency_chain}")]
CircularDependency {
dependency_chain: String,
},
#[error("缺少依赖服务: {missing_dependencies:?}")]
MissingDependencies {
missing_dependencies: Vec<String>,
},
#[error("功能标志 '{flag}' 无效")]
InvalidFeatureFlag {
flag: String,
},
}
pub type RegistryResult<T> = Result<T, RegistryError>;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServiceMetadata {
pub name: String,
pub version: String,
pub description: Option<String>,
pub dependencies: Vec<String>,
pub provides: Vec<String>,
pub status: ServiceStatus,
pub priority: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum ServiceStatus {
Uninitialized,
Initializing,
Ready,
Running,
Stopped,
Error(String),
}
#[derive(Debug)]
pub struct ServiceEntry {
pub metadata: ServiceMetadata,
pub instance: Option<Box<dyn std::any::Any + Send + Sync>>,
pub created_at: chrono::DateTime<chrono::Utc>,
pub updated_at: chrono::DateTime<chrono::Utc>,
}
pub trait ServiceRegistry: Send + Sync {
fn register_service(&mut self, metadata: ServiceMetadata) -> RegistryResult<()>;
fn unregister_service(&mut self, name: &str) -> RegistryResult<()>;
fn get_service(&self, name: &str) -> RegistryResult<&ServiceEntry>;
fn get_service_typed<T>(&self, name: &str) -> RegistryResult<&T>
where
T: 'static;
fn list_services(&self) -> Vec<&ServiceEntry>;
fn has_service(&self, name: &str) -> bool;
fn update_service_status(&mut self, name: &str, status: ServiceStatus) -> RegistryResult<()>;
fn get_dependency_graph(&self) -> HashMap<String, Vec<String>>;
}
#[derive(Debug)]
pub struct DefaultServiceRegistry {
services: HashMap<String, ServiceEntry>,
}
impl Default for DefaultServiceRegistry {
fn default() -> Self {
Self::new()
}
}
impl DefaultServiceRegistry {
pub fn new() -> Self {
Self {
services: HashMap::new(),
}
}
}
impl ServiceRegistry for DefaultServiceRegistry {
fn register_service(&mut self, metadata: ServiceMetadata) -> RegistryResult<()> {
if self.services.contains_key(&metadata.name) {
return Err(RegistryError::ServiceAlreadyExists {
name: metadata.name,
});
}
let entry = ServiceEntry {
metadata: metadata.clone(),
instance: None,
created_at: chrono::Utc::now(),
updated_at: chrono::Utc::now(),
};
self.services.insert(metadata.name.clone(), entry);
Ok(())
}
fn unregister_service(&mut self, name: &str) -> RegistryResult<()> {
if !self.services.contains_key(name) {
return Err(RegistryError::ServiceNotFound {
name: name.to_string(),
});
}
self.services.remove(name);
Ok(())
}
fn get_service(&self, name: &str) -> RegistryResult<&ServiceEntry> {
self.services
.get(name)
.ok_or_else(|| RegistryError::ServiceNotFound {
name: name.to_string(),
})
}
fn get_service_typed<T>(&self, name: &str) -> RegistryResult<&T>
where
T: 'static,
{
let entry = self.get_service(name)?;
entry
.instance
.as_ref()
.and_then(|instance| instance.downcast_ref::<T>())
.ok_or_else(|| RegistryError::ServiceNotFound {
name: format!("类型转换失败: {}", name),
})
}
fn list_services(&self) -> Vec<&ServiceEntry> {
self.services.values().collect()
}
fn has_service(&self, name: &str) -> bool {
self.services.contains_key(name)
}
fn update_service_status(&mut self, name: &str, status: ServiceStatus) -> RegistryResult<()> {
let entry = self
.services
.get_mut(name)
.ok_or_else(|| RegistryError::ServiceNotFound {
name: name.to_string(),
})?;
entry.metadata.status = status.clone();
entry.updated_at = chrono::Utc::now();
Ok(())
}
fn get_dependency_graph(&self) -> HashMap<String, Vec<String>> {
self.services
.iter()
.map(|(name, entry)| (name.clone(), entry.metadata.dependencies.clone()))
.collect()
}
}
#[cfg(test)]
#[allow(unused_imports)]
mod tests {
use super::*;
#[test]
fn test_service_registration() {
let mut registry = DefaultServiceRegistry::new();
let metadata = ServiceMetadata {
name: "test-service".to_string(),
version: "1.0.0".to_string(),
description: Some("测试服务".to_string()),
dependencies: vec![],
provides: vec!["test-feature".to_string()],
status: ServiceStatus::Uninitialized,
priority: 1,
};
assert!(registry.register_service(metadata).is_ok());
assert!(registry.has_service("test-service"));
}
#[test]
fn test_duplicate_registration() {
let mut registry = DefaultServiceRegistry::new();
let metadata = ServiceMetadata {
name: "test-service".to_string(),
version: "1.0.0".to_string(),
description: None,
dependencies: vec![],
provides: vec![],
status: ServiceStatus::Uninitialized,
priority: 1,
};
registry.register_service(metadata.clone()).unwrap();
let result = registry.register_service(metadata);
assert!(matches!(
result,
Err(RegistryError::ServiceAlreadyExists { .. })
));
}
}