memlink-runtime 0.2.0

Dynamic module loading framework with circuit breaker, caching, pooling, health checks, versioning, and auto-discovery
Documentation
//! Module events and lifecycle hooks.
//!
//! Provides event emission and middleware for module operations.

use std::sync::Arc;

/// Module lifecycle event.
#[derive(Debug, Clone)]
pub enum ModuleEvent {
    /// Module is being loaded.
    Loading { path: String },
    /// Module was loaded successfully.
    Loaded { name: String, duration_ms: u64 },
    /// Module load failed.
    LoadFailed { path: String, error: String },
    /// Module is being unloaded.
    Unloading { name: String },
    /// Module was unloaded.
    Unloaded { name: String },
    /// Module call started.
    CallStarted { module: String, method: String },
    /// Module call completed.
    CallCompleted { module: String, method: String, duration_us: u64, success: bool },
    /// Module health check.
    HealthCheck { module: String, healthy: bool },
    /// Module configuration changed.
    ConfigChanged { module: String },
}

/// Event listener trait.
pub trait EventListener: Send + Sync {
    /// Called when an event is emitted.
    fn on_event(&self, event: &ModuleEvent);
}

/// Event registry for module events.
pub struct EventRegistry {
    /// Registered listeners.
    listeners: dashmap::DashMap<String, Arc<dyn EventListener>>,
}

impl EventRegistry {
    /// Creates a new event registry.
    pub fn new() -> Self {
        Self {
            listeners: dashmap::DashMap::new(),
        }
    }

    /// Registers an event listener.
    pub fn register(&self, id: &str, listener: Arc<dyn EventListener>) {
        self.listeners.insert(id.to_string(), listener);
    }

    /// Unregisters an event listener.
    pub fn unregister(&self, id: &str) -> Option<Arc<dyn EventListener>> {
        self.listeners.remove(id).map(|(_, v)| v)
    }

    /// Emits an event to all listeners.
    pub fn emit(&self, event: &ModuleEvent) {
        for entry in self.listeners.iter() {
            entry.value().on_event(event);
        }
    }

    /// Returns the number of registered listeners.
    pub fn listener_count(&self) -> usize {
        self.listeners.len()
    }
}

impl Default for EventRegistry {
    fn default() -> Self {
        Self::new()
    }
}

/// Middleware for intercepting module calls.
pub trait CallMiddleware: Send + Sync {
    /// Called before a module call.
    fn before_call(&self, module: &str, method: &str, args: &[u8]) -> Result<(), String>;

    /// Called after a module call.
    fn after_call(&self, module: &str, method: &str, result: &Result<Vec<u8>, String>);
}

/// Middleware chain for module calls.
pub struct MiddlewareChain {
    /// Registered middleware.
    middleware: Vec<Arc<dyn CallMiddleware>>,
}

impl MiddlewareChain {
    /// Creates a new middleware chain.
    pub fn new() -> Self {
        Self {
            middleware: Vec::new(),
        }
    }

    /// Adds middleware to the chain.
    pub fn add(&mut self, mw: Arc<dyn CallMiddleware>) {
        self.middleware.push(mw);
    }

    /// Executes before-call hooks.
    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(())
    }

    /// Executes after-call hooks.
    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);
    }
}