1use async_trait::async_trait;
4use parking_lot::RwLock;
5use serde_json::Value;
6use std::collections::HashMap;
7use std::sync::Arc;
8
9#[derive(Debug, Clone)]
11pub struct HookContext {
12 pub name: String,
14 pub data: Value,
16 pub proceed: bool,
18 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 pub fn set_result(&mut self, result: Value) {
34 self.result = Some(result);
35 }
36
37 pub fn stop(&mut self) {
39 self.proceed = false;
40 }
41}
42
43#[async_trait]
45pub trait Hook: Send + Sync {
46 fn name(&self) -> &str;
48
49 fn priority(&self) -> i32 {
51 0
52 }
53
54 async fn execute(&self, ctx: &mut HookContext);
56}
57
58pub 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 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 list.sort_by_key(|h| h.priority());
78 }
79
80 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 pub fn remove(&self, hook_name: &str) {
101 let mut hooks = self.hooks.write();
102 hooks.remove(hook_name);
103 }
104
105 pub fn clear(&self) {
107 let mut hooks = self.hooks.write();
108 hooks.clear();
109 }
110
111 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
127static GLOBAL_HOOK_MANAGER: once_cell::sync::Lazy<HookManager> =
129 once_cell::sync::Lazy::new(HookManager::new);
130
131pub fn global_hook_manager() -> &'static HookManager {
133 &GLOBAL_HOOK_MANAGER
134}
135
136pub mod hook_names {
138 pub const BEFORE_UPLOAD: &str = "beforeUpload";
140 pub const AFTER_UPLOAD: &str = "afterUpload";
142 pub const BEFORE_REQUEST: &str = "beforeRequest";
144 pub const AFTER_REQUEST: &str = "afterRequest";
146 pub const BEFORE_DB: &str = "beforeDb";
148 pub const AFTER_DB: &str = "afterDb";
150}