use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use tracing::{debug, error, info, warn};
use crate::module::inter_module::api::ModuleAPI;
use crate::module::traits::ModuleError;
pub struct ModuleApiRegistry {
apis: Arc<RwLock<HashMap<String, Arc<dyn ModuleAPI>>>>,
method_routing: Arc<RwLock<HashMap<String, (String, String)>>>,
}
impl ModuleApiRegistry {
pub fn new() -> Self {
Self {
apis: Arc::new(RwLock::new(HashMap::new())),
method_routing: Arc::new(RwLock::new(HashMap::new())),
}
}
pub async fn register_api(
&self,
module_id: String,
api: Arc<dyn ModuleAPI>,
) -> Result<(), ModuleError> {
info!("Registering API for module: {}", module_id);
let methods = api.list_methods();
let api_version = api.api_version();
debug!(
"Module {} API v{} exposes {} methods: {:?}",
module_id,
api_version,
methods.len(),
methods
);
{
let mut apis = self.apis.write().await;
apis.insert(module_id.clone(), api);
}
{
let mut routing = self.method_routing.write().await;
for method in methods {
let full_method_name = format!("{module_id}::{method}");
routing.insert(
full_method_name.clone(),
(module_id.clone(), method.clone()),
);
routing
.entry(method)
.or_insert_with(|| (module_id.clone(), full_method_name));
}
}
Ok(())
}
pub async fn unregister_api(&self, module_id: &str) -> Result<(), ModuleError> {
info!("Unregistering API for module: {}", module_id);
{
let mut apis = self.apis.write().await;
apis.remove(module_id);
}
{
let mut routing = self.method_routing.write().await;
routing.retain(|_, (mid, _)| mid != module_id);
}
Ok(())
}
pub async fn get_api(&self, module_id: &str) -> Option<Arc<dyn ModuleAPI>> {
let apis = self.apis.read().await;
apis.get(module_id).cloned()
}
pub async fn resolve_module_id(&self, target: &str) -> Option<String> {
let apis = self.apis.read().await;
if apis.contains_key(target) {
return Some(target.to_string());
}
let prefix = format!("{target}_");
apis.keys().find(|k| k.starts_with(&prefix)).cloned()
}
pub async fn route_method(&self, method_name: &str) -> Option<(String, String)> {
let routing = self.method_routing.read().await;
routing.get(method_name).cloned()
}
pub async fn list_modules(&self) -> Vec<String> {
let apis = self.apis.read().await;
apis.keys().cloned().collect()
}
pub async fn get_module_methods(&self, module_id: &str) -> Option<Vec<String>> {
let apis = self.apis.read().await;
apis.get(module_id).map(|api| api.list_methods())
}
}
impl Default for ModuleApiRegistry {
fn default() -> Self {
Self::new()
}
}