Skip to main content

cool_plugin/
hook.rs

1//! 钩子系统
2
3use async_trait::async_trait;
4use parking_lot::RwLock;
5use serde_json::Value;
6use std::collections::HashMap;
7use std::sync::Arc;
8
9/// 钩子上下文
10#[derive(Debug, Clone)]
11pub struct HookContext {
12    /// 钩子名称
13    pub name: String,
14    /// 钩子数据
15    pub data: Value,
16    /// 是否继续执行
17    pub proceed: bool,
18    /// 返回结果
19    pub result: Option<Value>,
20}
21
22impl HookContext {
23    pub fn new(name: &str, data: Value) -> Self {
24        Self {
25            name: name.to_string(),
26            data,
27            proceed: true,
28            result: None,
29        }
30    }
31
32    /// 设置结果
33    pub fn set_result(&mut self, result: Value) {
34        self.result = Some(result);
35    }
36
37    /// 停止执行后续钩子
38    pub fn stop(&mut self) {
39        self.proceed = false;
40    }
41}
42
43/// 钩子 trait
44#[async_trait]
45pub trait Hook: Send + Sync {
46    /// 获取钩子名称
47    fn name(&self) -> &str;
48
49    /// 获取优先级(数字越小优先级越高)
50    fn priority(&self) -> i32 {
51        0
52    }
53
54    /// 执行钩子
55    async fn execute(&self, ctx: &mut HookContext);
56}
57
58/// 钩子管理器
59pub struct HookManager {
60    hooks: RwLock<HashMap<String, Vec<Arc<dyn Hook>>>>,
61}
62
63impl HookManager {
64    pub fn new() -> Self {
65        Self {
66            hooks: RwLock::new(HashMap::new()),
67        }
68    }
69
70    /// 注册钩子
71    pub fn register<H: Hook + 'static>(&self, hook_name: &str, hook: H) {
72        let mut hooks = self.hooks.write();
73        let list = hooks.entry(hook_name.to_string()).or_default();
74        list.push(Arc::new(hook));
75
76        // 按优先级排序
77        list.sort_by_key(|h| h.priority());
78    }
79
80    /// 执行钩子
81    pub async fn execute(&self, hook_name: &str, data: Value) -> HookContext {
82        let mut ctx = HookContext::new(hook_name, data);
83
84        let hooks = {
85            let hooks = self.hooks.read();
86            hooks.get(hook_name).cloned().unwrap_or_default()
87        };
88
89        for hook in hooks {
90            if !ctx.proceed {
91                break;
92            }
93            hook.execute(&mut ctx).await;
94        }
95
96        ctx
97    }
98
99    /// 移除钩子
100    pub fn remove(&self, hook_name: &str) {
101        let mut hooks = self.hooks.write();
102        hooks.remove(hook_name);
103    }
104
105    /// 清空所有钩子
106    pub fn clear(&self) {
107        let mut hooks = self.hooks.write();
108        hooks.clear();
109    }
110
111    /// 获取钩子列表
112    pub fn list(&self, hook_name: &str) -> Vec<String> {
113        let hooks = self.hooks.read();
114        hooks
115            .get(hook_name)
116            .map(|list| list.iter().map(|h| h.name().to_string()).collect())
117            .unwrap_or_default()
118    }
119}
120
121impl Default for HookManager {
122    fn default() -> Self {
123        Self::new()
124    }
125}
126
127/// 全局钩子管理器
128static GLOBAL_HOOK_MANAGER: once_cell::sync::Lazy<HookManager> =
129    once_cell::sync::Lazy::new(HookManager::new);
130
131/// 获取全局钩子管理器
132pub fn global_hook_manager() -> &'static HookManager {
133    &GLOBAL_HOOK_MANAGER
134}
135
136/// 预定义的钩子名称
137pub mod hook_names {
138    /// 上传前
139    pub const BEFORE_UPLOAD: &str = "beforeUpload";
140    /// 上传后
141    pub const AFTER_UPLOAD: &str = "afterUpload";
142    /// 请求前
143    pub const BEFORE_REQUEST: &str = "beforeRequest";
144    /// 请求后
145    pub const AFTER_REQUEST: &str = "afterRequest";
146    /// 数据库操作前
147    pub const BEFORE_DB: &str = "beforeDb";
148    /// 数据库操作后
149    pub const AFTER_DB: &str = "afterDb";
150}