use std::sync::Arc;
#[derive(Debug, Clone)]
pub enum ModuleEvent {
Loading { path: String },
Loaded { name: String, duration_ms: u64 },
LoadFailed { path: String, error: String },
Unloading { name: String },
Unloaded { name: String },
CallStarted { module: String, method: String },
CallCompleted { module: String, method: String, duration_us: u64, success: bool },
HealthCheck { module: String, healthy: bool },
ConfigChanged { module: String },
}
pub trait EventListener: Send + Sync {
fn on_event(&self, event: &ModuleEvent);
}
pub struct EventRegistry {
listeners: dashmap::DashMap<String, Arc<dyn EventListener>>,
}
impl EventRegistry {
pub fn new() -> Self {
Self {
listeners: dashmap::DashMap::new(),
}
}
pub fn register(&self, id: &str, listener: Arc<dyn EventListener>) {
self.listeners.insert(id.to_string(), listener);
}
pub fn unregister(&self, id: &str) -> Option<Arc<dyn EventListener>> {
self.listeners.remove(id).map(|(_, v)| v)
}
pub fn emit(&self, event: &ModuleEvent) {
for entry in self.listeners.iter() {
entry.value().on_event(event);
}
}
pub fn listener_count(&self) -> usize {
self.listeners.len()
}
}
impl Default for EventRegistry {
fn default() -> Self {
Self::new()
}
}
pub trait CallMiddleware: Send + Sync {
fn before_call(&self, module: &str, method: &str, args: &[u8]) -> Result<(), String>;
fn after_call(&self, module: &str, method: &str, result: &Result<Vec<u8>, String>);
}
pub struct MiddlewareChain {
middleware: Vec<Arc<dyn CallMiddleware>>,
}
impl MiddlewareChain {
pub fn new() -> Self {
Self {
middleware: Vec::new(),
}
}
pub fn add(&mut self, mw: Arc<dyn CallMiddleware>) {
self.middleware.push(mw);
}
pub fn before_call(&self, module: &str, method: &str, args: &[u8]) -> Result<(), String> {
for mw in &self.middleware {
mw.before_call(module, method, args)?;
}
Ok(())
}
pub fn after_call(&self, module: &str, method: &str, result: &Result<Vec<u8>, String>) {
for mw in &self.middleware {
mw.after_call(module, method, result);
}
}
}
impl Default for MiddlewareChain {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
struct TestListener {
events: std::sync::Mutex<Vec<ModuleEvent>>,
}
impl EventListener for TestListener {
fn on_event(&self, event: &ModuleEvent) {
self.events.lock().unwrap().push(event.clone());
}
}
#[test]
fn test_event_registry() {
let registry = EventRegistry::new();
let listener = Arc::new(TestListener {
events: std::sync::Mutex::new(Vec::new()),
});
registry.register("test", listener.clone());
let event = ModuleEvent::Loaded { name: "module".to_string(), duration_ms: 100 };
registry.emit(&event);
let events = listener.events.lock().unwrap();
assert_eq!(events.len(), 1);
}
}