rsclaw 0.0.1-alpha.1

rsclaw: High-performance AI agent (BETA). Optimized for M4 Max and 2GB VPS. 100% compatible with openclaw
Documentation
use super::types::{Hook, HookEvent};
use crate::store::Store;
use anyhow::Result;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;

/// Hook registry for managing hooks.
pub struct HookRegistry {
    hooks: Arc<RwLock<HashMap<Arc<str>, Hook>>>,
    event_hooks: Arc<RwLock<HashMap<HookEvent, Vec<Arc<str>>>>>,
    store: Option<Arc<Store>>,
}

impl HookRegistry {
    /// Create a new hook registry.
    pub fn new() -> Self {
        Self {
            hooks: Arc::new(RwLock::new(HashMap::new())),
            event_hooks: Arc::new(RwLock::new(HashMap::new())),
            store: None,
        }
    }

    /// Create with persistence.
    pub fn with_store(store: Arc<Store>) -> Self {
        Self {
            hooks: Arc::new(RwLock::new(HashMap::new())),
            event_hooks: Arc::new(RwLock::new(HashMap::new())),
            store: Some(store),
        }
    }

    /// Register a hook.
    pub async fn register(&self, hook: Hook) -> Result<Arc<str>> {
        let id = hook.id.clone();
        let event = hook.event.clone();
        let event_name = event.to_string();

        {
            let mut hooks = self.hooks.write().await;
            hooks.insert(id.clone(), hook);
        }

        {
            let mut event_hooks = self.event_hooks.write().await;
            let hooks_for_event = event_hooks.entry(event).or_insert_with(Vec::new);
            if !hooks_for_event.contains(&id) {
                hooks_for_event.push(id.clone());
            }
        }

        tracing::info!("Hook '{}' registered for event '{}'", id, event_name);
        Ok(id)
    }

    /// Unregister a hook.
    pub async fn unregister(&self, id: &str) -> Result<bool> {
        let mut hooks = self.hooks.write().await;
        
        if let Some(hook) = hooks.remove(id) {
            let mut event_hooks = self.event_hooks.write().await;
            if let Some(hooks_for_event) = event_hooks.get_mut(&hook.event) {
                hooks_for_event.retain(|h| h.as_ref() != id);
            }
            tracing::info!("Hook '{}' unregistered", id);
            Ok(true)
        } else {
            Ok(false)
        }
    }

    /// Get a hook by ID.
    pub async fn get(&self, id: &str) -> Option<Hook> {
        let hooks = self.hooks.read().await;
        hooks.get(id).cloned()
    }

    /// List all hooks.
    pub async fn list(&self) -> Vec<Hook> {
        let hooks = self.hooks.read().await;
        hooks.values().cloned().collect()
    }

    /// Get hooks for an event, sorted by priority.
    pub async fn get_hooks_for_event(&self, event: &HookEvent) -> Vec<Hook> {
        let event_hooks = self.event_hooks.read().await;
        let hooks = self.hooks.read().await;

        let mut result = Vec::new();

        if let Some(hook_ids) = event_hooks.get(event) {
            for id in hook_ids {
                if let Some(hook) = hooks.get(id) {
                    if hook.enabled {
                        result.push(hook.clone());
                    }
                }
            }
        }

        // Sort by priority (lower = higher priority)
        result.sort_by_key(|h| h.priority);
        result
    }

    /// List all registered events.
    pub async fn list_events(&self) -> Vec<HookEvent> {
        let event_hooks = self.event_hooks.read().await;
        event_hooks.keys().cloned().collect()
    }

    /// Enable/disable a hook.
    pub async fn set_enabled(&self, id: &str, enabled: bool) -> Result<bool> {
        let mut hooks = self.hooks.write().await;
        
        if let Some(hook) = hooks.get_mut(id) {
            hook.enabled = enabled;
            Ok(true)
        } else {
            Ok(false)
        }
    }
}

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