Skip to main content

shirabe_core/
context.rs

1pub mod filter;
2pub mod listener;
3pub mod state;
4
5// TODO: 完善上下文系统
6use std::any::Any;
7use std::sync::{Arc, Mutex, RwLock}; // Mutex 用于回调的内部可变性
8use uuid::Uuid; // Mutex 用于回调的内部可变性
9
10use crate::bot::Bot;
11use crate::command::CommandBuilder;
12use crate::context::{
13    filter::ContextFilter,
14    listener::{ListenerAction, ListenerHandle, ListenerId, RegisteredListener},
15    state::EventSystemSharedState,
16};
17use crate::session::Session;
18
19// 事件上下文
20#[derive(Clone)]
21pub struct Context {
22    /// 当前应用的全部机器人实例
23    pub bots: Arc<Mutex<Vec<Arc<Bot>>>>,
24    /// 当前上下文的过滤器设置
25    pub current_filter: ContextFilter,
26    /// 对共享状态的引用
27    pub shared_state: Arc<RwLock<EventSystemSharedState>>,
28}
29
30impl Context {
31    pub fn new_root(shared_state: Arc<RwLock<EventSystemSharedState>>) -> Self {
32        Context {
33            bots: Arc::new(Mutex::new(Vec::new())),
34            current_filter: ContextFilter::new(), // 根上下文的过滤器是空的
35            shared_state,
36        }
37    }
38
39    // --- 上下文派生方法 ---
40    pub fn user(&self, user_id: &str) -> Self {
41        // 创建只针对特定用户的子上下文
42        Context {
43            bots: self.bots.clone(),
44            current_filter: self.current_filter.clone().user(user_id),
45            shared_state: Arc::clone(&self.shared_state),
46        }
47    }
48    pub fn guild(&self, guild_id: &str) -> Self {
49        // 创建只针对特定群组的子上下文
50        Context {
51            bots: self.bots.clone(),
52            current_filter: self.current_filter.clone().guild(guild_id),
53            shared_state: Arc::clone(&self.shared_state),
54        }
55    }
56    pub fn platform(&self, platform: &str) -> Self {
57        // 创建只针对特定平台的子上下文
58        Context {
59            bots: self.bots.clone(),
60            current_filter: self.current_filter.clone().platform(platform),
61            shared_state: Arc::clone(&self.shared_state),
62        }
63    }
64    pub fn private(&self) -> Self {
65        // 创建只针对私聊的子上下文
66        Context {
67            bots: self.bots.clone(),
68            current_filter: self.current_filter.clone().private(),
69            shared_state: Arc::clone(&self.shared_state),
70        }
71    }
72    pub fn group(&self) -> Self {
73        // 创建只针对群聊的子上下文 (与 private 相对)
74        Context {
75            bots: self.bots.clone(),
76            current_filter: self.current_filter.clone().group(),
77            shared_state: Arc::clone(&self.shared_state),
78        }
79    }
80    // --- 上下文派生方法结束 ---
81
82    /// 开始定义一个新指令。
83    ///
84    /// 指令将自动关联当前上下文的过滤器。
85    ///
86    /// # 例如
87    ///
88    /// ```ignore
89    /// ctx.command("ping")
90    ///    .description("Replies with pong")
91    ///    .action(|session, _args| Box::pin(async move {
92    ///        session.bot.send_message(&session.channel_id, "pong").await?;
93    ///        Ok(())
94    ///    }))
95    ///    .register()?;
96    /// ```
97    pub fn command(&self, name: &str) -> CommandBuilder {
98        let registry_arc = {
99            let state_guard = self.shared_state.read().unwrap();
100            Arc::clone(&state_guard.command_registry)
101        };
102        CommandBuilder::new(name.to_string(), self.current_filter.clone(), registry_arc)
103    }
104
105    fn register_listener_internal(
106        &self,
107        event_name: &str,
108        action: ListenerAction,
109    ) -> ListenerHandle {
110        let id = Uuid::new_v4(); // 生成唯一ID
111        let listener = Arc::new(RegisteredListener {
112            id,
113            filter: self.current_filter.clone(), // 监听器关联到当前上下文的过滤器副本
114            action,
115        });
116        let mut state = self.shared_state.write().unwrap(); // 获取共享状态的写锁
117        state.add_listener(event_name.to_string(), Arc::clone(&listener));
118        ListenerHandle {
119            id,
120            shared_state: Arc::clone(&self.shared_state),
121        }
122    }
123
124    // 注册普通监听器
125    pub fn on<F>(&self, event_name: &str, callback: F) -> ListenerHandle
126    where
127        F: FnMut(Option<&Session>, &[Box<dyn Any + Send + Sync>]) + Send + Sync + 'static,
128    {
129        self.register_listener_internal(
130            event_name,
131            ListenerAction::On(Mutex::new(Box::new(callback))),
132        )
133    }
134
135    // 注册一次性监听器
136    pub fn once<F>(&self, event_name: &str, callback: F) -> ListenerHandle
137    where
138        F: FnMut(Option<&Session>, &[Box<dyn Any + Send + Sync>]) + Send + Sync + 'static,
139    {
140        self.register_listener_internal(
141            event_name,
142            ListenerAction::Once(Mutex::new(Some(Box::new(callback)))),
143        )
144    }
145
146    // 注册可熔断监听器
147    pub fn bail<F>(&self, event_name: &str, callback: F) -> ListenerHandle
148    where
149        F: FnMut(
150                Option<&Session>,
151                &[Box<dyn Any + Send + Sync>],
152            ) -> Option<Box<dyn Any + Send + Sync>>
153            + Send
154            + Sync
155            + 'static,
156    {
157        self.register_listener_internal(
158            event_name,
159            ListenerAction::Bail(Mutex::new(Box::new(callback))),
160        )
161    }
162
163    /// 发射事件
164    /// # Arguments
165    ///
166    /// `session_context`: 可选的会话上下文,用于过滤器匹配
167    /// `event_name`: 事件名称
168    /// `args`: 事件参数列表
169    ///
170    /// # Returns
171    /// 如果某个 bail 监听器熔断了,则返回其返回值
172    pub fn emit(
173        &self,
174        event_name: &str,
175        session_context: Option<&Session>,
176        args: &[Box<dyn Any + Send + Sync>],
177    ) -> Option<Box<dyn Any + Send + Sync>> {
178        let state_read_guard = self.shared_state.read().unwrap(); // 获取读锁
179        let listeners_for_event_arcs = match state_read_guard.listeners_by_event.get(event_name) {
180            Some(listeners) => listeners.clone(), // 克隆 Arc 列表,以便在锁外操作
181            None => return None,                  // 没有此事件的监听器
182        };
183        drop(state_read_guard); // 释放读锁,避免长时间持有
184
185        let mut ids_of_once_listeners_fired: Vec<ListenerId> = Vec::new(); // 存储已触发的 Once 监听器ID
186
187        for listener_arc in listeners_for_event_arcs {
188            //  检查上下文过滤器是否匹配
189            let should_run = match session_context {
190                Some(s_ctx) => listener_arc.filter.matches_session(s_ctx),
191                None => listener_arc.filter.matches_generic(), // 对于无会话的通用事件
192            };
193
194            if !should_run {
195                continue; // 过滤器不匹配,跳过此监听器
196            }
197
198            //  根据监听器类型执行回调
199            match &listener_arc.action {
200                ListenerAction::On(cb_mutex) => {
201                    // 对于 On 监听器,获取其回调的锁并执行
202                    // 使用 try_lock 更好,以防死锁(如果回调内部又 emit 同步事件)
203                    if let Ok(mut cb_guard) = cb_mutex.try_lock() {
204                        (*cb_guard)(session_context, args);
205                    } else {
206                        // 处理无法获取锁的情况,例如打印警告
207                        eprintln!(
208                            "[事件系统警告] 无法获取 On 监听器 {} 的锁,可能存在重入或竞争。",
209                            listener_arc.id
210                        );
211                    }
212                }
213                ListenerAction::Once(cb_mutex_opt) => {
214                    let mut opt_cb_guard = cb_mutex_opt.lock().unwrap();
215                    if let Some(mut cb) = opt_cb_guard.take() {
216                        // 尝试取出回调
217                        // 成功取出,表示这是第一次执行
218                        drop(opt_cb_guard); // 在调用回调前释放锁
219                        cb(session_context, args);
220                        ids_of_once_listeners_fired.push(listener_arc.id); // 记录此ID,稍后移除
221                    }
222                    // 如果 opt_cb_guard.take() 返回 None,说明回调已被取走,不再执行
223                }
224                ListenerAction::Bail(cb_mutex) => {
225                    if let Ok(mut cb_guard) = cb_mutex.try_lock() {
226                        let bail_result = (*cb_guard)(session_context, args);
227                        if bail_result.is_some() {
228                            // Bail 监听器返回了 Some 值,表示熔断
229                            // 在返回前,清理掉在此 Bail 之前已触发的 Once 监听器
230                            if !ids_of_once_listeners_fired.is_empty() {
231                                let mut state_write_guard = self.shared_state.write().unwrap();
232                                for id in &ids_of_once_listeners_fired {
233                                    state_write_guard.remove_listener(*id);
234                                }
235                            }
236                            return bail_result; // 立即返回熔断结果
237                        }
238                    } else {
239                        eprintln!(
240                            "[事件系统警告] 无法获取 Bail 监听器 {} 的锁,可能存在重入或竞争。",
241                            listener_arc.id
242                        );
243                    }
244                }
245            }
246        }
247
248        // 循环结束后,统一清理所有已触发的 Once 监听器
249        if !ids_of_once_listeners_fired.is_empty() {
250            let mut state_write_guard = self.shared_state.write().unwrap();
251            for id in ids_of_once_listeners_fired {
252                state_write_guard.remove_listener(id);
253            }
254        }
255
256        None // 没有监听器熔断
257    }
258}