use super::{Anonymous, Sender};
use crate::event::{PostType, RepliableEvent, Sex, UniversalMessage};
use crate::message_trait::MessageRegistrar as _;
use crate::onebot_message::{OneBotMessage, cq_to_arr_inner};
use kovi::bot::runtimebot::{CanSendApi, send_api_request_with_forget};
use kovi::bot::{BotInformation, SendApi};
use kovi::error::EventBuildError;
use kovi::event::id::ref_id::RefID;
use kovi::event::{Event, InternalEvent, MessageEventTrait};
use kovi::message::Message as KoviMessage;
use kovi::types::ApiAndOptOneshot;
use log::{debug, info};
use serde::Serialize;
use serde_json::value::Index;
use serde_json::{self, Value, json};
use tokio::sync::mpsc;
#[derive(Debug, Clone)]
pub struct MsgEvent {
pub time: i64,
pub self_id: i64,
pub post_type: PostType,
pub message_type: String,
pub sub_type: String,
pub message: KoviMessage,
pub message_id: i32,
pub group_id: Option<i64>,
pub user_id: i64,
pub anonymous: Option<Anonymous>,
pub raw_message: String,
pub font: i32,
pub sender: Sender,
pub text: Option<String>,
pub human_text: String,
pub original_json: Value,
pub api_tx: mpsc::Sender<ApiAndOptOneshot>,
}
impl MessageEventTrait for MsgEvent {
fn get_sender_name(&self) -> Option<&str> {
self.sender.nickname.as_deref()
}
fn get_message(&self) -> &KoviMessage {
&self.message
}
fn get_message_type_str(&self) -> Option<&str> {
Some(&self.message_type)
}
fn get_sender_id(&self) -> RefID<'_> {
RefID::new(&self.sender.user_id)
}
fn get_group_id(&self) -> Option<RefID<'_>> {
self.group_id.as_ref().map(RefID::new)
}
}
impl Event for MsgEvent {
fn de(
event: &InternalEvent,
_: &BotInformation,
api_tx: &mpsc::Sender<ApiAndOptOneshot>,
) -> Option<Self> {
let InternalEvent::DriverEvent(json) = event else {
return None;
};
Self::new(api_tx.clone(), json.clone()).ok()
}
}
impl MsgEvent {
pub(crate) fn new(
api_tx: mpsc::Sender<ApiAndOptOneshot>,
temp: Value,
) -> Result<MsgEvent, EventBuildError> {
let temp_object = temp.as_object().ok_or(EventBuildError::ParseError(
"Invalid JSON object".to_string(),
))?;
let temp_sender = temp_object
.get("sender")
.and_then(|v| v.as_object())
.ok_or(EventBuildError::ParseError(
"Invalid sender object".to_string(),
))?;
let sender = {
Sender {
user_id: temp_sender
.get("user_id")
.and_then(|v| v.as_i64())
.ok_or(EventBuildError::ParseError("Invalid user_id".to_string()))?,
nickname: temp_sender.get("nickname").and_then(|v| {
if let Value::String(str) = v.clone() {
Some(str)
} else {
None
}
}),
card: temp_sender.get("card").and_then(|v| {
if let Value::String(str) = v.clone() {
Some(str)
} else {
None
}
}),
sex: if let Some(v) = temp_sender.get("sex").and_then(|v| v.as_str()) {
match v {
"male" => Some(Sex::Male),
"female" => Some(Sex::Female),
_ => None,
}
} else {
None
},
age: temp_sender
.get("age")
.and_then(|v| v.as_i64())
.map(|v| v as i32),
area: temp_sender.get("area").and_then(|v| {
if let Value::String(str) = v.clone() {
Some(str)
} else {
None
}
}),
level: temp_sender.get("level").and_then(|v| {
if let Value::String(str) = v.clone() {
Some(str)
} else {
None
}
}),
role: temp_sender.get("role").and_then(|v| {
if let Value::String(str) = v.clone() {
Some(str)
} else {
None
}
}),
title: temp_sender.get("title").and_then(|v| {
if let Value::String(str) = v.clone() {
Some(str)
} else {
None
}
}),
}
};
let group_id = temp_object.get("group_id").and_then(|v| v.as_i64());
let message = if temp_object
.get("message")
.and_then(|v| v.as_array())
.is_some()
{
let v = temp_object
.get("message")
.ok_or(EventBuildError::ParseError(
"Missing 'message' field".to_string(),
))?
.as_array()
.ok_or(EventBuildError::ParseError(
"Invalid 'message' array".to_string(),
))?
.to_vec();
OneBotMessage::from_vec_segment_value(v)
.map_err(|e| EventBuildError::ParseError(format!("Parse error: {e}")))?
} else {
let str_v = temp_object["message"]
.as_str()
.ok_or(format!(
"message is not string:{:?}",
temp_object["message"]
))
.map_err(|e| EventBuildError::ParseError(format!("Parse error: {e}")))?;
let arr_v = cq_to_arr_inner(str_v);
OneBotMessage::from_vec_segment_value(arr_v)
.map_err(|e| EventBuildError::ParseError(format!("Parse error: {e}")))?
};
let anonymous: Option<Anonymous> =
if temp_object.get("anonymous").is_none_or(|v| v.is_null()) {
None
} else {
let anonymous = temp_object
.get("anonymous")
.ok_or(EventBuildError::ParseError(
"Invalid anonymous field".to_string(),
))?
.clone();
Some(
serde_json::from_value(anonymous)
.map_err(|e| EventBuildError::ParseError(e.to_string()))?,
)
};
let text = {
let mut text_vec = Vec::new();
for msg in message.iter() {
if msg.type_ == "text"
&& let Some(text_value) = msg.data.get("text").and_then(|v| v.as_str())
{
text_vec.push(text_value);
};
}
if !text_vec.is_empty() {
Some(text_vec.join("\n").trim().to_string())
} else {
None
}
};
let message = KoviMessage::from(message);
let event = MsgEvent {
human_text: message.to_human_string(),
time: temp_object
.get("time")
.and_then(|v| v.as_i64())
.ok_or(EventBuildError::ParseError("Invalid time".to_string()))?,
self_id: temp_object
.get("self_id")
.and_then(|v| v.as_i64())
.ok_or(EventBuildError::ParseError("Invalid self_id".to_string()))?,
post_type: temp_object
.get("post_type")
.and_then(|v| serde_json::from_value::<PostType>(v.clone()).ok())
.ok_or(EventBuildError::ParseError("Invalid post_type".to_string()))?,
message_type: temp_object
.get("message_type")
.and_then(|v| {
if let Value::String(str) = v.clone() {
Some(str)
} else {
None
}
})
.ok_or(EventBuildError::ParseError(
"Invalid message_type".to_string(),
))?,
sub_type: temp_object
.get("sub_type")
.and_then(|v| {
if let Value::String(str) = v.clone() {
Some(str)
} else {
None
}
})
.ok_or(EventBuildError::ParseError("Invalid sub_type".to_string()))?,
message,
message_id: temp_object
.get("message_id")
.and_then(|v| v.as_i64())
.ok_or(EventBuildError::ParseError(
"Invalid message_id".to_string(),
))? as i32,
group_id,
user_id: temp_object
.get("user_id")
.and_then(|v| v.as_i64())
.ok_or(EventBuildError::ParseError("Invalid user_id".to_string()))?,
anonymous,
raw_message: temp_object
.get("raw_message")
.and_then(|v| {
if let Value::String(str) = v.clone() {
Some(str)
} else {
None
}
})
.ok_or(EventBuildError::ParseError(
"Invalid raw_message".to_string(),
))?,
font: temp_object
.get("font")
.and_then(|v| v.as_i64())
.ok_or(EventBuildError::ParseError("Invalid font".to_string()))?
as i32,
sender,
api_tx,
text,
original_json: temp,
};
debug!("{event:?}");
Ok(event)
}
}
impl MsgEvent {
pub fn get<I: Index>(&self, index: I) -> Option<&Value> {
self.original_json.get(index)
}
}
impl<I> std::ops::Index<I> for MsgEvent
where
I: Index,
{
type Output = Value;
fn index(&self, index: I) -> &Self::Output {
&self.original_json[index]
}
}
impl MsgEvent {
fn reply_builder<M>(&self, msg: M, auto_escape: bool) -> SendApi
where
M: Into<OneBotMessage>,
{
RepliableEvent::reply_builder(self, msg, auto_escape)
}
#[cfg(not(feature = "cqstring"))]
pub fn reply<T>(&self, msg: T)
where
KoviMessage: From<T>,
T: Serialize,
{
RepliableEvent::reply(self, msg)
}
#[cfg(feature = "cqstring")]
pub fn reply<T>(&self, msg: T)
where
CQMessage: From<T>,
T: Serialize,
{
RepliableEvent::reply(self, msg)
}
#[cfg(not(feature = "cqstring"))]
pub fn reply_and_quote<T>(&self, msg: T)
where
KoviMessage: From<T>,
T: Serialize,
{
RepliableEvent::reply_and_quote(self, msg);
}
#[cfg(feature = "cqstring")]
fn reply_and_quote<T>(&self, msg: T)
where
CQMessage: From<T>,
T: Serialize,
{
RepliableEvent::reply_and_quote(self, msg);
}
#[cfg(feature = "cqstring")]
fn reply_text<T>(&self, msg: T)
where
String: From<T>,
T: Serialize,
{
RepliableEvent::reply_text(self, msg)
}
pub fn get_text(&self) -> String {
RepliableEvent::get_text(self)
}
pub fn get_sender_nickname(&self) -> String {
RepliableEvent::get_sender_nickname(self)
}
pub fn borrow_text(&self) -> Option<&str> {
RepliableEvent::borrow_text(self)
}
pub fn is_group(&self) -> bool {
UniversalMessage::is_group(self)
}
pub fn is_private(&self) -> bool {
UniversalMessage::is_private(self)
}
}
impl UniversalMessage for MsgEvent {
fn is_group(&self) -> bool {
self.group_id.is_some()
}
fn is_private(&self) -> bool {
self.group_id.is_none()
}
}
impl RepliableEvent for MsgEvent {
fn reply_builder<M>(&self, msg: M, auto_escape: bool) -> SendApi
where
M: Into<OneBotMessage>,
{
let msg = msg.into();
if self.is_private() {
SendApi::new(
"send_msg",
json!({
"message_type":"private",
"user_id":self.user_id,
"message":msg,
"auto_escape":auto_escape,
}),
)
} else {
SendApi::new(
"send_msg",
json!({
"message_type":"group",
"group_id":self.group_id.as_ref().expect("unreachable"),
"message":msg,
"auto_escape":auto_escape,
}),
)
}
}
#[cfg(not(feature = "cqstring"))]
fn reply<T>(&self, msg: T)
where
KoviMessage: From<T>,
T: Serialize,
{
let msg = KoviMessage::from(msg);
let mut nickname = self.get_sender_nickname();
nickname.insert(0, ' ');
let id = &self.sender.user_id;
let message_type = &self.message_type;
let group_id = match &self.group_id {
Some(v) => format!(" {v}"),
None => "".to_string(),
};
let human_msg = msg.to_human_string();
info!("[reply] [to {message_type}{group_id}{nickname} {id}]: {human_msg}");
let send_msg = self.reply_builder(msg, false);
send_api_request_with_forget(&self.api_tx, send_msg)
}
#[cfg(feature = "cqstring")]
fn reply<T>(&self, msg: T)
where
CQMessage: From<T>,
T: Serialize,
{
let msg = CQMessage::from(msg);
let send_msg = self.reply_builder(&msg, false);
let mut nickname = self.get_sender_nickname();
nickname.insert(0, ' ');
let id = &self.sender.user_id;
let message_type = &self.message_type;
let group_id = match &self.group_id {
Some(v) => format!(" {v}"),
None => "".to_string(),
};
let human_msg = Message::from(msg).to_human_string();
info!("[reply] [to {message_type}{group_id}{nickname} {id}]: {human_msg}");
send_api_request_with_forget(&self.api_tx, send_msg);
}
#[cfg(not(feature = "cqstring"))]
fn reply_and_quote<T>(&self, msg: T)
where
KoviMessage: From<T>,
T: Serialize,
{
let msg = KoviMessage::from(msg).add_reply(self.message_id);
let mut nickname = self.get_sender_nickname();
nickname.insert(0, ' ');
let id = &self.sender.user_id;
let message_type = &self.message_type;
let group_id = match &self.group_id {
Some(v) => format!(" {v}"),
None => "".to_string(),
};
let human_msg = msg.to_human_string();
info!("[reply] [to {message_type}{group_id}{nickname} {id}]: {human_msg}");
let send_msg = self.reply_builder(msg, false);
send_api_request_with_forget(&self.api_tx, send_msg);
}
#[cfg(feature = "cqstring")]
fn reply_and_quote<T>(&self, msg: T)
where
CQMessage: From<T>,
T: Serialize,
{
let msg = CQMessage::from(msg).add_reply(self.message_id);
let send_msg = self.reply_builder(&msg, false);
let mut nickname = self.get_sender_nickname();
nickname.insert(0, ' ');
let id = &self.sender.user_id;
let message_type = &self.message_type;
let group_id = match &self.group_id {
Some(v) => format!(" {v}"),
None => "".to_string(),
};
let human_msg = Message::from(msg).to_human_string();
info!("[reply] [to {message_type}{group_id}{nickname} {id}]: {human_msg}");
send_api_request_with_forget(&self.api_tx, send_msg);
}
#[cfg(feature = "cqstring")]
fn reply_text<T>(&self, msg: T)
where
String: From<T>,
T: Serialize,
{
let send_msg = self.reply_builder(&msg, true);
let mut nickname = self.get_sender_nickname();
nickname.insert(0, ' ');
let id = &self.sender.user_id;
let message_type = &self.message_type;
let group_id = match &self.group_id {
Some(v) => format!(" {v}"),
None => "".to_string(),
};
let msg = String::from(msg);
info!("[reply] [to {message_type}{group_id} {nickname} {id}]: {msg}");
send_api_request_with_forget(&self.api_tx, send_msg);
}
fn get_text(&self) -> String {
match self.text.clone() {
Some(v) => v,
None => "".to_string(),
}
}
fn get_sender_nickname(&self) -> String {
if let Some(v) = &self.sender.nickname {
v.clone()
} else {
"".to_string()
}
}
fn borrow_text(&self) -> Option<&str> {
self.text.as_deref()
}
}
impl CanSendApi for MsgEvent {
fn __get_api_tx(&self) -> &tokio::sync::mpsc::Sender<kovi::types::ApiAndOptOneshot> {
&self.api_tx
}
}