nonebot_rs/matcher/matchers/
mod.rs

1use crate::event::{Event, MessageEvent, MetaEvent, NoticeEvent, RequestEvent, SelfId};
2use crate::matcher::Matcher;
3use async_trait::async_trait;
4use colored::*;
5use std::collections::{BTreeMap, HashMap};
6use tokio::sync::broadcast;
7use tracing::{event, Level};
8
9mod action;
10
11/// 按 `priority` 依序存储 `MatchersHashMap`
12pub type MatchersBTreeMap<E> = BTreeMap<i8, MatchersHashMap<E>>;
13/// 使用唯一名字存储 `Matcher`
14pub type MatchersHashMap<E> = HashMap<String, Matcher<E>>;
15/// Matchers Action Sender
16pub type ActionSender = broadcast::Sender<super::action::MatchersAction>;
17
18pub const PLUGIN_NAME: &'static str = "Matcher";
19
20/// 根据 `Event` 类型分类存储对应的 `Matcher`
21#[derive(Clone, Debug)]
22pub struct Matchers {
23    /// MessageEvent 对应 MatcherBTreeMap
24    pub message: MatchersBTreeMap<MessageEvent>,
25    /// NoticeEvent 对应 MatcherBTreeMap
26    pub notice: MatchersBTreeMap<NoticeEvent>,
27    /// RequestEvent 对应 MatcherBTreeMap
28    pub request: MatchersBTreeMap<RequestEvent>,
29    /// MetaEvent 对应 MatcherBTreeMap
30    pub meta: MatchersBTreeMap<MetaEvent>,
31    /// Bot Watch channel Receiver
32    bot_getter: Option<crate::BotGetter>,
33    /// Matchers Action Sender
34    action_sender: ActionSender,
35    /// Config
36    config: HashMap<String, HashMap<String, toml::Value>>,
37}
38
39impl Matchers {
40    async fn handle_events(&mut self, event: Event, bot: &crate::bot::Bot) {
41        match event {
42            Event::Message(e) => {
43                self.handle_event(self.message.clone(), e, bot.clone())
44                    .await;
45            }
46            Event::Notice(e) => {
47                self.handle_event(self.notice.clone(), e, bot.clone()).await;
48            }
49            Event::Request(e) => {
50                self.handle_event(self.request.clone(), e, bot.clone())
51                    .await;
52            }
53            Event::Meta(e) => {
54                self.handle_event(self.meta.clone(), e, bot.clone()).await;
55            }
56            Event::Nonebot(e) => match e {
57                crate::event::NbEvent::BotConnect { bot } => {
58                    log_load_matchers(&self);
59                    self.run_on_connect(bot, false).await;
60                }
61                crate::event::NbEvent::BotDisconnect { bot } => {
62                    self.run_on_connect(bot, true).await;
63                }
64            },
65        }
66    }
67
68    /// 接收按类型分发后的 Event 逐级匹配 Matcher
69    async fn handle_event<E>(
70        &mut self,
71        mut matcherb: MatchersBTreeMap<E>,
72        event: E,
73        bot: crate::bot::Bot,
74    ) where
75        E: Clone + Send + 'static + std::fmt::Debug + SelfId,
76    {
77        event!(Level::TRACE, "handling event {:?}", event);
78        // 根据不同 Event 类型,逐级匹配,判定是否 Block
79        for (_, matcherh) in matcherb.iter_mut() {
80            if self
81                ._handler_event(matcherh, event.clone(), bot.clone())
82                .await
83            {
84                break;
85            };
86        }
87    }
88
89    #[doc(hidden)]
90    async fn _handler_event<E>(
91        &mut self,
92        matcherh: &mut MatchersHashMap<E>,
93        e: E,
94        bot: crate::bot::Bot,
95    ) -> bool
96    where
97        E: Clone + Send + 'static + std::fmt::Debug + SelfId,
98    {
99        event!(Level::TRACE, "handling event_ {:?}", e);
100        // 每级 Matcher 匹配,返回是否 block
101        let mut get_block = false;
102        let config = bot.config.clone();
103        for (name, matcher) in matcherh.iter_mut() {
104            let matched = matcher
105                .build(bot.clone())
106                .match_(e.clone(), config.clone(), self)
107                .await;
108            if matched {
109                event!(Level::INFO, "Matched {}", name.blue());
110                if matcher.is_block() {
111                    get_block = true;
112                }
113                if matcher.is_temp() {
114                    event!(Level::INFO, "Remove matched temp matcher {}", name.blue());
115                    self.remove_matcher(name);
116                }
117            }
118        }
119        get_block
120    }
121
122    async fn event_recv(mut self, mut event_receiver: crate::EventReceiver) {
123        let mut receiver = self.action_sender.subscribe();
124        while let Ok(event) = event_receiver.recv().await {
125
126            match receiver.try_recv() {
127                Ok(action) => self.handle_action(action),
128                Err(_) => {}
129            }
130
131            let bots = self.bot_getter.clone().unwrap().borrow().clone();
132            if let Some(bot) = bots.get(&event.get_self_id()) {
133                self.handle_events(event, bot).await;
134            }
135        }
136    }
137}
138
139#[async_trait]
140impl crate::Plugin for Matchers {
141    fn run(&self, event_receiver: crate::EventReceiver, bot_getter: crate::BotGetter) {
142        let mut m = self.clone();
143        m.bot_getter = Some(bot_getter.clone());
144        tokio::spawn(m.event_recv(event_receiver));
145    }
146
147    fn plugin_name(&self) -> &'static str {
148        PLUGIN_NAME
149    }
150
151    async fn load_config(&mut self, config: toml::Value) {
152        let config: HashMap<String, HashMap<String, toml::Value>> =
153            config.try_into().expect("Matchers get error config");
154        self.config = config;
155        self.load_all_matcher_config().await;
156        event!(Level::INFO, "Loaded Matchers config: {:?}", self.config);
157    }
158}
159
160fn log_load_matchers(matchers: &crate::Matchers) {
161    log_matcherb(&matchers.message);
162    log_matcherb(&matchers.notice);
163    log_matcherb(&matchers.request);
164    log_matcherb(&matchers.meta);
165}
166
167fn log_matcherb<E>(matcherb: &MatchersBTreeMap<E>)
168where
169    E: Clone,
170{
171    if matcherb.is_empty() {
172        return;
173    }
174    for (_, matcherh) in matcherb {
175        for (name, _) in matcherh {
176            event!(Level::INFO, "Matcher {} is Loaded", name.blue());
177        }
178    }
179}