1use super::{Anonymous, Sender};
2use crate::event::{PostType, RepliableEvent, Sex, UniversalMessage};
3use crate::message_trait::MessageRegistrar as _;
4use crate::onebot_message::{OneBotMessage, cq_to_arr_inner};
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::{debug, 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 MsgEvent {
20 pub time: i64,
22 pub self_id: i64,
24 pub post_type: PostType,
26 pub message_type: String,
28 pub sub_type: String,
30 pub message: KoviMessage,
32 pub message_id: i32,
34 pub group_id: Option<i64>,
36 pub user_id: i64,
38 pub anonymous: Option<Anonymous>,
40 pub raw_message: String,
42 pub font: i32,
44 pub sender: Sender,
46
47 pub text: Option<String>,
49 pub human_text: String,
51 pub original_json: Value,
53
54 pub api_tx: mpsc::Sender<ApiAndOptOneshot>,
56}
57
58impl MessageEventTrait for MsgEvent {
59 fn get_sender_name(&self) -> Option<&str> {
60 self.sender.nickname.as_deref()
61 }
62
63 fn get_message(&self) -> &KoviMessage {
64 &self.message
65 }
66
67 fn get_message_type_str(&self) -> Option<&str> {
68 Some(&self.message_type)
69 }
70
71 fn get_sender_id(&self) -> RefID<'_> {
72 RefID::new(&self.sender.user_id)
73 }
74
75 fn get_group_id(&self) -> Option<RefID<'_>> {
76 self.group_id.as_ref().map(RefID::new)
77 }
78}
79
80impl Event for MsgEvent {
81 fn de(
82 event: &InternalEvent,
83 _: &BotInformation,
84 api_tx: &mpsc::Sender<ApiAndOptOneshot>,
85 ) -> Option<Self> {
86 let InternalEvent::DriverEvent(json) = event else {
87 return None;
88 };
89
90 Self::new(api_tx.clone(), json.clone()).ok()
91 }
92}
93
94impl MsgEvent {
95 pub(crate) fn new(
96 api_tx: mpsc::Sender<ApiAndOptOneshot>,
97 temp: Value,
98 ) -> Result<MsgEvent, EventBuildError> {
99 let temp_object = temp.as_object().ok_or(EventBuildError::ParseError(
100 "Invalid JSON object".to_string(),
101 ))?;
102
103 let temp_sender = temp_object
104 .get("sender")
105 .and_then(|v| v.as_object())
106 .ok_or(EventBuildError::ParseError(
107 "Invalid sender object".to_string(),
108 ))?;
109
110 let sender = {
111 Sender {
112 user_id: temp_sender
113 .get("user_id")
114 .and_then(|v| v.as_i64())
115 .ok_or(EventBuildError::ParseError("Invalid user_id".to_string()))?,
116 nickname: temp_sender.get("nickname").and_then(|v| {
117 if let Value::String(str) = v.clone() {
118 Some(str)
119 } else {
120 None
121 }
122 }),
123 card: temp_sender.get("card").and_then(|v| {
124 if let Value::String(str) = v.clone() {
125 Some(str)
126 } else {
127 None
128 }
129 }),
130 sex: if let Some(v) = temp_sender.get("sex").and_then(|v| v.as_str()) {
131 match v {
132 "male" => Some(Sex::Male),
133 "female" => Some(Sex::Female),
134 _ => None,
135 }
136 } else {
137 None
138 },
139 age: temp_sender
140 .get("age")
141 .and_then(|v| v.as_i64())
142 .map(|v| v as i32),
143 area: temp_sender.get("area").and_then(|v| {
144 if let Value::String(str) = v.clone() {
145 Some(str)
146 } else {
147 None
148 }
149 }),
150 level: temp_sender.get("level").and_then(|v| {
151 if let Value::String(str) = v.clone() {
152 Some(str)
153 } else {
154 None
155 }
156 }),
157 role: temp_sender.get("role").and_then(|v| {
158 if let Value::String(str) = v.clone() {
159 Some(str)
160 } else {
161 None
162 }
163 }),
164 title: temp_sender.get("title").and_then(|v| {
165 if let Value::String(str) = v.clone() {
166 Some(str)
167 } else {
168 None
169 }
170 }),
171 }
172 };
173
174 let group_id = temp_object.get("group_id").and_then(|v| v.as_i64());
175
176 let message = if temp_object
177 .get("message")
178 .and_then(|v| v.as_array())
179 .is_some()
180 {
181 let v = temp_object
182 .get("message")
183 .ok_or(EventBuildError::ParseError(
184 "Missing 'message' field".to_string(),
185 ))?
186 .as_array()
187 .ok_or(EventBuildError::ParseError(
188 "Invalid 'message' array".to_string(),
189 ))?
190 .to_vec();
191 OneBotMessage::from_vec_segment_value(v)
192 .map_err(|e| EventBuildError::ParseError(format!("Parse error: {e}")))?
193 } else {
194 let str_v = temp_object["message"]
195 .as_str()
196 .ok_or(format!(
197 "message is not string:{:?}",
198 temp_object["message"]
199 ))
200 .map_err(|e| EventBuildError::ParseError(format!("Parse error: {e}")))?;
201 let arr_v = cq_to_arr_inner(str_v);
202 OneBotMessage::from_vec_segment_value(arr_v)
203 .map_err(|e| EventBuildError::ParseError(format!("Parse error: {e}")))?
204 };
205
206 let anonymous: Option<Anonymous> =
207 if temp_object.get("anonymous").is_none_or(|v| v.is_null()) {
208 None
209 } else {
210 let anonymous = temp_object
211 .get("anonymous")
212 .ok_or(EventBuildError::ParseError(
213 "Invalid anonymous field".to_string(),
214 ))?
215 .clone();
216 Some(
217 serde_json::from_value(anonymous)
218 .map_err(|e| EventBuildError::ParseError(e.to_string()))?,
219 )
220 };
221
222 let text = {
223 let mut text_vec = Vec::new();
224 for msg in message.iter() {
225 if msg.type_ == "text"
226 && let Some(text_value) = msg.data.get("text").and_then(|v| v.as_str())
227 {
228 text_vec.push(text_value);
229 };
230 }
231 if !text_vec.is_empty() {
232 Some(text_vec.join("\n").trim().to_string())
233 } else {
234 None
235 }
236 };
237
238 let message = KoviMessage::from(message);
239 let event = MsgEvent {
240 human_text: message.to_human_string(),
241 time: temp_object
242 .get("time")
243 .and_then(|v| v.as_i64())
244 .ok_or(EventBuildError::ParseError("Invalid time".to_string()))?,
245 self_id: temp_object
246 .get("self_id")
247 .and_then(|v| v.as_i64())
248 .ok_or(EventBuildError::ParseError("Invalid self_id".to_string()))?,
249 post_type: temp_object
250 .get("post_type")
251 .and_then(|v| serde_json::from_value::<PostType>(v.clone()).ok())
252 .ok_or(EventBuildError::ParseError("Invalid post_type".to_string()))?,
253 message_type: temp_object
254 .get("message_type")
255 .and_then(|v| {
256 if let Value::String(str) = v.clone() {
257 Some(str)
258 } else {
259 None
260 }
261 })
262 .ok_or(EventBuildError::ParseError(
263 "Invalid message_type".to_string(),
264 ))?,
265 sub_type: temp_object
266 .get("sub_type")
267 .and_then(|v| {
268 if let Value::String(str) = v.clone() {
269 Some(str)
270 } else {
271 None
272 }
273 })
274 .ok_or(EventBuildError::ParseError("Invalid sub_type".to_string()))?,
275 message,
276 message_id: temp_object
277 .get("message_id")
278 .and_then(|v| v.as_i64())
279 .ok_or(EventBuildError::ParseError(
280 "Invalid message_id".to_string(),
281 ))? as i32,
282 group_id,
283 user_id: temp_object
284 .get("user_id")
285 .and_then(|v| v.as_i64())
286 .ok_or(EventBuildError::ParseError("Invalid user_id".to_string()))?,
287 anonymous,
288 raw_message: temp_object
289 .get("raw_message")
290 .and_then(|v| {
291 if let Value::String(str) = v.clone() {
292 Some(str)
293 } else {
294 None
295 }
296 })
297 .ok_or(EventBuildError::ParseError(
298 "Invalid raw_message".to_string(),
299 ))?,
300 font: temp_object
301 .get("font")
302 .and_then(|v| v.as_i64())
303 .ok_or(EventBuildError::ParseError("Invalid font".to_string()))?
304 as i32,
305 sender,
306 api_tx,
307 text,
308 original_json: temp,
309 };
310 debug!("{event:?}");
311 Ok(event)
312 }
313}
314
315impl MsgEvent {
316 pub fn get<I: Index>(&self, index: I) -> Option<&Value> {
330 self.original_json.get(index)
331 }
332}
333
334impl<I> std::ops::Index<I> for MsgEvent
335where
336 I: Index,
337{
338 type Output = Value;
339
340 fn index(&self, index: I) -> &Self::Output {
341 &self.original_json[index]
342 }
343}
344
345impl MsgEvent {
346 fn reply_builder<M>(&self, msg: M, auto_escape: bool) -> SendApi
347 where
348 M: Into<OneBotMessage>,
349 {
350 RepliableEvent::reply_builder(self, msg, auto_escape)
351 }
352
353 #[cfg(not(feature = "cqstring"))]
354 pub fn reply<T>(&self, msg: T)
355 where
356 KoviMessage: From<T>,
357 T: Serialize,
358 {
359 RepliableEvent::reply(self, msg)
360 }
361
362 #[cfg(feature = "cqstring")]
363 pub fn reply<T>(&self, msg: T)
364 where
365 CQMessage: From<T>,
366 T: Serialize,
367 {
368 RepliableEvent::reply(self, msg)
369 }
370
371 #[cfg(not(feature = "cqstring"))]
372 pub fn reply_and_quote<T>(&self, msg: T)
373 where
374 KoviMessage: From<T>,
375 T: Serialize,
376 {
377 RepliableEvent::reply_and_quote(self, msg);
378 }
379
380 #[cfg(feature = "cqstring")]
381 fn reply_and_quote<T>(&self, msg: T)
382 where
383 CQMessage: From<T>,
384 T: Serialize,
385 {
386 RepliableEvent::reply_and_quote(self, msg);
387 }
388
389 #[cfg(feature = "cqstring")]
390 fn reply_text<T>(&self, msg: T)
391 where
392 String: From<T>,
393 T: Serialize,
394 {
395 RepliableEvent::reply_text(self, msg)
396 }
397
398 pub fn get_text(&self) -> String {
399 RepliableEvent::get_text(self)
400 }
401
402 pub fn get_sender_nickname(&self) -> String {
403 RepliableEvent::get_sender_nickname(self)
404 }
405
406 pub fn borrow_text(&self) -> Option<&str> {
407 RepliableEvent::borrow_text(self)
408 }
409
410 pub fn is_group(&self) -> bool {
411 UniversalMessage::is_group(self)
412 }
413
414 pub fn is_private(&self) -> bool {
415 UniversalMessage::is_private(self)
416 }
417}
418
419impl UniversalMessage for MsgEvent {
420 fn is_group(&self) -> bool {
421 self.group_id.is_some()
422 }
423
424 fn is_private(&self) -> bool {
425 self.group_id.is_none()
426 }
427}
428
429impl RepliableEvent for MsgEvent {
430 fn reply_builder<M>(&self, msg: M, auto_escape: bool) -> SendApi
431 where
432 M: Into<OneBotMessage>,
433 {
434 let msg = msg.into();
435 if self.is_private() {
436 SendApi::new(
437 "send_msg",
438 json!({
439 "message_type":"private",
440 "user_id":self.user_id,
441 "message":msg,
442 "auto_escape":auto_escape,
443 }),
444 )
445 } else {
446 SendApi::new(
447 "send_msg",
448 json!({
449 "message_type":"group",
450 "group_id":self.group_id.as_ref().expect("unreachable"),
451 "message":msg,
452 "auto_escape":auto_escape,
453 }),
454 )
455 }
456 }
457
458 #[cfg(not(feature = "cqstring"))]
459 fn reply<T>(&self, msg: T)
461 where
462 KoviMessage: From<T>,
463 T: Serialize,
464 {
465 let msg = KoviMessage::from(msg);
466 let mut nickname = self.get_sender_nickname();
467 nickname.insert(0, ' ');
468 let id = &self.sender.user_id;
469 let message_type = &self.message_type;
470 let group_id = match &self.group_id {
471 Some(v) => format!(" {v}"),
472 None => "".to_string(),
473 };
474 let human_msg = msg.to_human_string();
475 info!("[reply] [to {message_type}{group_id}{nickname} {id}]: {human_msg}");
476
477 let send_msg = self.reply_builder(msg, false);
478 send_api_request_with_forget(&self.api_tx, send_msg)
479 }
480
481 #[cfg(feature = "cqstring")]
482 fn reply<T>(&self, msg: T)
484 where
485 CQMessage: From<T>,
486 T: Serialize,
487 {
488 let msg = CQMessage::from(msg);
489 let send_msg = self.reply_builder(&msg, false);
490 let mut nickname = self.get_sender_nickname();
491 nickname.insert(0, ' ');
492 let id = &self.sender.user_id;
493 let message_type = &self.message_type;
494 let group_id = match &self.group_id {
495 Some(v) => format!(" {v}"),
496 None => "".to_string(),
497 };
498 let human_msg = Message::from(msg).to_human_string();
499 info!("[reply] [to {message_type}{group_id}{nickname} {id}]: {human_msg}");
500 send_api_request_with_forget(&self.api_tx, send_msg);
501 }
502
503 #[cfg(not(feature = "cqstring"))]
504 fn reply_and_quote<T>(&self, msg: T)
506 where
507 KoviMessage: From<T>,
508 T: Serialize,
509 {
510 let msg = KoviMessage::from(msg).add_reply(self.message_id);
511 let mut nickname = self.get_sender_nickname();
512 nickname.insert(0, ' ');
513 let id = &self.sender.user_id;
514 let message_type = &self.message_type;
515 let group_id = match &self.group_id {
516 Some(v) => format!(" {v}"),
517 None => "".to_string(),
518 };
519 let human_msg = msg.to_human_string();
520 info!("[reply] [to {message_type}{group_id}{nickname} {id}]: {human_msg}");
521
522 let send_msg = self.reply_builder(msg, false);
523 send_api_request_with_forget(&self.api_tx, send_msg);
524 }
525
526 #[cfg(feature = "cqstring")]
527 fn reply_and_quote<T>(&self, msg: T)
529 where
530 CQMessage: From<T>,
531 T: Serialize,
532 {
533 let msg = CQMessage::from(msg).add_reply(self.message_id);
534 let send_msg = self.reply_builder(&msg, false);
535
536 let mut nickname = self.get_sender_nickname();
537 nickname.insert(0, ' ');
538 let id = &self.sender.user_id;
539 let message_type = &self.message_type;
540 let group_id = match &self.group_id {
541 Some(v) => format!(" {v}"),
542 None => "".to_string(),
543 };
544 let human_msg = Message::from(msg).to_human_string();
545 info!("[reply] [to {message_type}{group_id}{nickname} {id}]: {human_msg}");
546 send_api_request_with_forget(&self.api_tx, send_msg);
547 }
548
549 #[cfg(feature = "cqstring")]
550 fn reply_text<T>(&self, msg: T)
552 where
553 String: From<T>,
554 T: Serialize,
555 {
556 let send_msg = self.reply_builder(&msg, true);
557 let mut nickname = self.get_sender_nickname();
558 nickname.insert(0, ' ');
559 let id = &self.sender.user_id;
560 let message_type = &self.message_type;
561 let group_id = match &self.group_id {
562 Some(v) => format!(" {v}"),
563 None => "".to_string(),
564 };
565 let msg = String::from(msg);
566 info!("[reply] [to {message_type}{group_id} {nickname} {id}]: {msg}");
567 send_api_request_with_forget(&self.api_tx, send_msg);
568 }
569
570 fn get_text(&self) -> String {
572 match self.text.clone() {
573 Some(v) => v,
574 None => "".to_string(),
575 }
576 }
577
578 fn get_sender_nickname(&self) -> String {
580 if let Some(v) = &self.sender.nickname {
581 v.clone()
582 } else {
583 "".to_string()
584 }
585 }
586
587 fn borrow_text(&self) -> Option<&str> {
589 self.text.as_deref()
590 }
591}
592
593impl CanSendApi for MsgEvent {
594 fn __get_api_tx(&self) -> &tokio::sync::mpsc::Sender<kovi::types::ApiAndOptOneshot> {
595 &self.api_tx
596 }
597}