use std::sync::Arc;
use tokio::sync::Mutex;
use tracing::{debug, error, info, warn};
use crate::module::inter_module::registry::ModuleApiRegistry;
use crate::module::ipc::server::ModuleIpcServer;
use crate::module::manager::ModuleManager;
use crate::module::traits::ModuleError;
pub struct ModuleRouter {
registry: Arc<ModuleApiRegistry>,
ipc_server: Option<Arc<tokio::sync::Mutex<ModuleIpcServer>>>,
module_manager: Option<Arc<tokio::sync::Mutex<ModuleManager>>>,
}
impl ModuleRouter {
pub fn new(registry: Arc<ModuleApiRegistry>) -> Self {
Self {
registry,
ipc_server: None,
module_manager: None,
}
}
pub fn with_ipc_server(mut self, ipc_server: Arc<tokio::sync::Mutex<ModuleIpcServer>>) -> Self {
self.ipc_server = Some(ipc_server);
self
}
pub fn with_module_manager(
mut self,
module_manager: Arc<tokio::sync::Mutex<ModuleManager>>,
) -> Self {
self.module_manager = Some(module_manager);
self
}
pub async fn route_call(
&self,
caller_module_id: &str,
target_module_id: Option<&str>,
method: &str,
params: &[u8],
) -> Result<Vec<u8>, ModuleError> {
let (target_id, actual_method) = if let Some(target_id) = target_module_id {
(target_id.to_string(), method.to_string())
} else {
match self.registry.route_method(method).await {
Some((mid, mname)) => (mid, mname),
None => {
return Err(ModuleError::OperationError(format!(
"Method '{method}' not found in any module"
)));
}
}
};
debug!(
"Routing call: {} -> {}::{}",
caller_module_id, target_id, actual_method
);
if let Some(module_manager) = &self.module_manager {
let manager = module_manager.lock().await;
let target_module_name = target_id.split('_').next().unwrap_or(&target_id);
if let Err(e) = manager
.validate_module_dependencies(target_module_name)
.await
{
return Err(ModuleError::op_err(
&format!("Dependency validation failed for module '{target_id}'"),
e,
));
}
use crate::module::process::monitor::ModuleHealth;
if let Some(state) = manager.get_module_state(target_module_name).await {
let health = match state {
crate::module::traits::ModuleState::Running => ModuleHealth::Healthy,
crate::module::traits::ModuleState::Initializing => ModuleHealth::Healthy,
crate::module::traits::ModuleState::Stopped => ModuleHealth::Unresponsive,
crate::module::traits::ModuleState::Error(err) => ModuleHealth::Crashed(err),
crate::module::traits::ModuleState::Stopping => ModuleHealth::Unresponsive,
};
match health {
ModuleHealth::Healthy => {
}
ModuleHealth::Unresponsive | ModuleHealth::Crashed(_) => {
return Err(ModuleError::OperationError(format!(
"Target module '{target_id}' is not healthy (health: {health:?})"
)));
}
}
}
}
let resolved_id = self
.registry
.resolve_module_id(&target_id)
.await
.unwrap_or_else(|| target_id.clone());
let api = self.registry.get_api(&resolved_id).await.ok_or_else(|| {
ModuleError::OperationError(format!(
"Module '{target_id}' not found or has no API registered"
))
})?;
api.handle_request(&actual_method, params, caller_module_id)
.await
}
}