Skip to main content

kovi_onebot/event/
group_msg_event.rs

1use super::{Anonymous, Sender};
2use crate::event::{MsgEvent, PostType, RepliableEvent};
3use crate::message_trait::MessageRegistrar as _;
4use crate::onebot_message::OneBotMessage;
5use kovi::bot::runtimebot::{CanSendApi, send_api_request_with_forget};
6use kovi::bot::{BotInformation, SendApi};
7use kovi::error::EventBuildError;
8use kovi::event::id::ref_id::RefID;
9use kovi::event::{Event, InternalEvent, MessageEventTrait};
10use kovi::message::Message as KoviMessage;
11use kovi::types::ApiAndOptOneshot;
12use log::info;
13use serde::Serialize;
14use serde_json::value::Index;
15use serde_json::{self, Value, json};
16use tokio::sync::mpsc;
17
18#[derive(Debug, Clone)]
19pub struct GroupMsgEvent {
20    /// 事件发生的时间戳
21    pub time: i64,
22    /// 收到事件的机器人 登陆号
23    pub self_id: i64,
24    /// 上报类型
25    pub post_type: PostType,
26    /// 消息类型
27    pub message_type: String,
28    /// 消息子类型,如果是好友则是 friend,如果是群临时会话则是 group
29    pub sub_type: String,
30    /// 消息内容
31    pub message: KoviMessage,
32    /// 消息 ID
33    pub message_id: i32,
34    /// 群号
35    pub group_id: i64,
36    /// 发送者号
37    pub user_id: i64,
38    /// 匿名信息,如果不是匿名消息则为 null
39    pub anonymous: Option<Anonymous>,
40    /// 原始消息内容
41    pub raw_message: String,
42    /// 字体
43    pub font: i32,
44    /// 发送人信息
45    pub sender: Sender,
46
47    /// 处理过的纯文本,如果是纯图片或无文本,此处为None
48    pub text: Option<String>,
49    /// 处理过的文本,会解析成人类易读形式,里面会包含\[image\]\[face\]等解析后字符串
50    pub human_text: String,
51    /// 原始的onebot消息,已处理成json格式
52    pub original_json: Value,
53
54    /// 不推荐的消息发送方式
55    pub api_tx: mpsc::Sender<ApiAndOptOneshot>,
56}
57
58impl Event for GroupMsgEvent {
59    fn de(
60        event: &InternalEvent,
61        _: &BotInformation,
62        api_tx: &mpsc::Sender<ApiAndOptOneshot>,
63    ) -> Option<Self> {
64        let InternalEvent::DriverEvent(json) = event else {
65            return None;
66        };
67        let event = Self::new(api_tx.clone(), json.clone()).ok()?;
68
69        Some(event)
70    }
71}
72
73impl GroupMsgEvent {
74    fn new(
75        api_tx: mpsc::Sender<ApiAndOptOneshot>,
76        json: Value,
77    ) -> Result<GroupMsgEvent, EventBuildError> {
78        let msg_event = MsgEvent::new(api_tx, json)?;
79
80        Ok(GroupMsgEvent {
81            time: msg_event.time,
82            self_id: msg_event.self_id,
83            post_type: msg_event.post_type,
84            message_type: msg_event.message_type,
85            sub_type: msg_event.sub_type,
86            message: msg_event.message,
87            message_id: msg_event.message_id,
88            group_id: match msg_event.group_id {
89                Some(id) => id,
90                None => {
91                    return Err(EventBuildError::ParseError(
92                        "group_id unreachable".to_string(),
93                    ));
94                }
95            },
96            user_id: msg_event.user_id,
97            anonymous: msg_event.anonymous,
98            raw_message: msg_event.raw_message,
99            font: msg_event.font,
100            sender: msg_event.sender,
101            text: msg_event.text,
102            human_text: msg_event.human_text,
103            original_json: msg_event.original_json,
104            api_tx: msg_event.api_tx,
105        })
106    }
107}
108
109impl GroupMsgEvent {
110    /// 直接从原始的 Json Value 获取某值
111    ///
112    /// # example
113    ///
114    /// ```ignore
115    /// use kovi::PluginBuilder;
116    ///
117    /// PluginBuilder::on_msg(|event| async move {
118    ///     let time = event.get("time").and_then(|v| v.as_i64()).unwrap();
119    ///
120    ///     assert_eq!(time, event.time);
121    /// });
122    /// ```
123    pub fn get<I: Index>(&self, index: I) -> Option<&Value> {
124        self.original_json.get(index)
125    }
126}
127
128impl<I> std::ops::Index<I> for GroupMsgEvent
129where
130    I: Index,
131{
132    type Output = Value;
133
134    fn index(&self, index: I) -> &Self::Output {
135        &self.original_json[index]
136    }
137}
138
139impl GroupMsgEvent {
140    fn reply_builder<M>(&self, msg: M, auto_escape: bool) -> SendApi
141    where
142        M: Into<OneBotMessage>,
143    {
144        RepliableEvent::reply_builder(self, msg, auto_escape)
145    }
146
147    #[cfg(not(feature = "cqstring"))]
148    pub fn reply<T>(&self, msg: T)
149    where
150        KoviMessage: From<T>,
151        T: Serialize,
152    {
153        RepliableEvent::reply(self, msg)
154    }
155
156    #[cfg(feature = "cqstring")]
157    pub fn reply<T>(&self, msg: T)
158    where
159        CQMessage: From<T>,
160        T: Serialize,
161    {
162        RepliableEvent::reply(self, msg)
163    }
164
165    #[cfg(not(feature = "cqstring"))]
166    pub fn reply_and_quote<T>(&self, msg: T)
167    where
168        KoviMessage: From<T>,
169        T: Serialize,
170    {
171        RepliableEvent::reply_and_quote(self, msg);
172    }
173
174    #[cfg(feature = "cqstring")]
175    fn reply_and_quote<T>(&self, msg: T)
176    where
177        CQMessage: From<T>,
178        T: Serialize,
179    {
180        RepliableEvent::reply_and_quote(self, msg);
181    }
182
183    #[cfg(feature = "cqstring")]
184    fn reply_text<T>(&self, msg: T)
185    where
186        String: From<T>,
187        T: Serialize,
188    {
189        RepliableEvent::reply_text(self, msg)
190    }
191
192    pub fn get_text(&self) -> String {
193        RepliableEvent::get_text(self)
194    }
195
196    pub fn get_sender_nickname(&self) -> String {
197        RepliableEvent::get_sender_nickname(self)
198    }
199
200    pub fn borrow_text(&self) -> Option<&str> {
201        RepliableEvent::borrow_text(self)
202    }
203}
204
205impl RepliableEvent for GroupMsgEvent {
206    fn reply_builder<M>(&self, msg: M, auto_escape: bool) -> SendApi
207    where
208        M: Into<OneBotMessage>,
209    {
210        let msg = msg.into();
211        SendApi::new(
212            "send_msg",
213            json!({
214                "message_type":"group",
215                "group_id":self.group_id,
216                "message":msg,
217                "auto_escape":auto_escape,
218            }),
219        )
220    }
221
222    #[cfg(not(feature = "cqstring"))]
223    /// 快速回复消息
224    fn reply<T>(&self, msg: T)
225    where
226        KoviMessage: From<T>,
227        T: Serialize,
228    {
229        let msg = KoviMessage::from(msg);
230        let nickname = self.get_sender_nickname();
231        let id = &self.sender.user_id;
232        let message_type = &self.message_type;
233        let group_id = &self.group_id;
234        let human_msg = msg.to_human_string();
235        info!("[reply] [to {message_type} {group_id} {nickname} {id}]: {human_msg}");
236
237        let send_msg = self.reply_builder(msg, false);
238        send_api_request_with_forget(&self.api_tx, send_msg)
239    }
240
241    #[cfg(feature = "cqstring")]
242    /// 快速回复消息
243    fn reply<T>(&self, msg: T)
244    where
245        CQMessage: From<T>,
246        T: Serialize,
247    {
248        let msg = CQMessage::from(msg);
249        let send_msg = self.reply_builder(&msg, false);
250        let nickname = self.get_sender_nickname();
251        let id = &self.sender.user_id;
252        let message_type = &self.message_type;
253        let group_id = &self.group_id;
254        let human_msg = Message::from(msg).to_human_string();
255        info!("[reply] [to {message_type} {group_id} {nickname} {id}]: {human_msg}");
256        send_api_request_with_forget(&self.api_tx, send_msg);
257    }
258
259    #[cfg(not(feature = "cqstring"))]
260    /// 快速回复消息并且**引用**
261    fn reply_and_quote<T>(&self, msg: T)
262    where
263        KoviMessage: From<T>,
264        T: Serialize,
265    {
266        let msg = KoviMessage::from(msg).add_reply(self.message_id);
267        let nickname = self.get_sender_nickname();
268        let id = &self.sender.user_id;
269        let message_type = &self.message_type;
270        let group_id = &self.group_id;
271        let human_msg = msg.to_human_string();
272        info!("[reply] [to {message_type} {group_id} {nickname} {id}]: {human_msg}");
273
274        let send_msg = self.reply_builder(msg, false);
275        send_api_request_with_forget(&self.api_tx, send_msg);
276    }
277
278    #[cfg(feature = "cqstring")]
279    /// 快速回复消息并且**引用**
280    fn reply_and_quote<T>(&self, msg: T)
281    where
282        CQMessage: From<T>,
283        T: Serialize,
284    {
285        let msg = CQMessage::from(msg).add_reply(self.message_id);
286        let send_msg = self.reply_builder(&msg, false);
287        let nickname = self.get_sender_nickname();
288        let id = &self.sender.user_id;
289        let message_type = &self.message_type;
290        let group_id = &self.group_id;
291        let human_msg = Message::from(msg).to_human_string();
292        info!("[reply] [to {message_type} {group_id} {nickname} {id}]: {human_msg}");
293        send_api_request_with_forget(&self.api_tx, send_msg);
294    }
295
296    #[cfg(feature = "cqstring")]
297    /// 快速回复消息,并且**kovi不进行解析,直接发送此字符串**
298    fn reply_text<T>(&self, msg: T)
299    where
300        String: From<T>,
301        T: Serialize,
302    {
303        let send_msg = self.reply_builder(&msg, true);
304        let nickname = self.get_sender_nickname();
305        let id = &self.sender.user_id;
306        let message_type = &self.message_type;
307        let group_id = &self.group_id;
308        let msg = String::from(msg);
309        info!("[reply] [to {message_type} {group_id} {nickname} {id}]: {msg}");
310        send_api_request_with_forget(&self.api_tx, send_msg);
311    }
312
313    /// 便捷获取文本,如果没有文本则会返回空字符串,如果只需要借用,请使用 `borrow_text()`
314    fn get_text(&self) -> String {
315        match self.text.clone() {
316            Some(v) => v,
317            None => "".to_string(),
318        }
319    }
320
321    /// 便捷获取发送者昵称,如果无名字,此处为空字符串
322    fn get_sender_nickname(&self) -> String {
323        if let Some(v) = &self.sender.nickname {
324            v.clone()
325        } else {
326            "".to_string()
327        }
328    }
329
330    /// 借用 event 的 text,只是做了一下self.text.as_deref()的包装
331    fn borrow_text(&self) -> Option<&str> {
332        self.text.as_deref()
333    }
334}
335
336impl CanSendApi for GroupMsgEvent {
337    fn __get_api_tx(&self) -> &tokio::sync::mpsc::Sender<kovi::types::ApiAndOptOneshot> {
338        &self.api_tx
339    }
340}
341
342impl MessageEventTrait for GroupMsgEvent {
343    fn get_sender_name(&self) -> Option<&str> {
344        self.sender.nickname.as_deref()
345    }
346
347    fn get_message(&self) -> &KoviMessage {
348        &self.message
349    }
350
351    fn get_message_type_str(&self) -> Option<&str> {
352        Some(&self.message_type)
353    }
354
355    fn get_sender_id(&self) -> RefID<'_> {
356        RefID::new(&self.sender.user_id)
357    }
358
359    fn get_group_id(&self) -> Option<RefID<'_>> {
360        Some(RefID::new(&self.group_id))
361    }
362}