Skip to content

Commit

Permalink
refactor post msg type
Browse files Browse the repository at this point in the history
  • Loading branch information
EluvK committed Mar 13, 2023
1 parent 84a40db commit 972d9d5
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 27 deletions.
2 changes: 2 additions & 0 deletions src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ pub(super) static COMMAND_HELP_INFO: &str = r#"
- `#help` for this menu
"#;

pub(super) static GREETING_MESSAGE: &str = "Hi! I'm a chatbot developed by EluvK and open-sourced at https://github.com/EluvK/qbot. Type `#help` to get the list of commands.";

pub(super) enum Opcode {
Invalid,
Role(BotRole),
Expand Down
52 changes: 43 additions & 9 deletions src/cqbot/bot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ use tokio::net::TcpStream;
use tokio_tungstenite::{connect_async, tungstenite::Message, MaybeTlsStream, WebSocketStream};

use crate::{
command::GREETING_MESSAGE,
config::Config,
cqbot::msg::{MessageType, RecvMsg, SendMsg},
cqbot::msg::{MessageType, PostMessageMsg, PostMessageType, PostMsg, SendMsg},
gpt::{GPTPostMessage, GPTRecvMessage},
private_manager::ChatManager,
};

use super::msg::{NoticeType, PostNoticeMsg, PostRequestMsg};

pub struct Bot {
web_socket_stream: Box<WebSocketStream<MaybeTlsStream<TcpStream>>>,

Expand Down Expand Up @@ -49,13 +52,27 @@ impl Bot {
async fn handle_cqhttp_message(&mut self, message: Message) -> Option<SendMsg> {
if let Message::Text(text) = message {
// println!("Handle Text:{}", &text);
let msg = serde_json::from_str::<RecvMsg>(&text).ok()?;
let (is_at, msg) = msg.pre_parse_msg(self.config.bot_qq());
println!("is_at:{:?}, RecvMessage:{:?}", is_at, &msg);
if &MessageType::Group == msg.message_type() && !is_at {
None
} else {
self.handle_message(msg).await
let post_msg = serde_json::from_str::<PostMsg>(&text).ok()?;
match post_msg.post_type {
PostMessageType::Message => {
let msg = serde_json::from_str::<PostMessageMsg>(&text).ok()?;
let (is_at, msg) = msg.pre_parse_msg(self.config.bot_qq());
println!("[Message] is_at:{:?}, RecvMessage:{:?}", is_at, &msg);
if &MessageType::Group == msg.message_type() && !is_at {
None
} else {
self.handle_message(msg).await
}
}
PostMessageType::MetaEvent => None, // don't care for now
PostMessageType::Request => {
let req = serde_json::from_str::<PostRequestMsg>(&text).ok()?;
self.handle_request(req)
}
PostMessageType::Notice => {
let notice = serde_json::from_str::<PostNoticeMsg>(&text).ok()?;
self.handle_notice(notice)
}
}
} else {
None
Expand All @@ -67,7 +84,8 @@ impl Bot {
self.web_socket_stream.send(reply).await.expect("Send_fail");
}

async fn handle_message(&mut self, message: RecvMsg) -> Option<SendMsg> {
/// for PostMessageType::Message
async fn handle_message(&mut self, message: PostMessageMsg) -> Option<SendMsg> {
let group_id = if message.message_type() == &MessageType::Group {
Some(message.group_id())
} else {
Expand Down Expand Up @@ -148,6 +166,22 @@ impl Bot {

Ok(gpt_recv_msg)
}

/// for PostMessageType::Request
fn handle_request(&mut self, req: PostRequestMsg) -> Option<SendMsg> {
Some(SendMsg::new_message(
None,
self.config.root_qq(),
format!("Bot receive request: {}", req),
))
}
/// for PostMessageType::Notice
fn handle_notice(&mut self, notice: PostNoticeMsg) -> Option<SendMsg> {
match notice.notice_type {
NoticeType::FriendAdd => Some(SendMsg::new_message(None, notice.user_id, GREETING_MESSAGE.into())),
_ => None,
}
}
}

mod error {
Expand Down
129 changes: 113 additions & 16 deletions src/cqbot/msg.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::{fmt::Display, marker::PhantomData};

use lazy_static::lazy_static;
use regex::Regex;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -55,9 +57,11 @@ impl SendMsg {

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
enum PostMessageType {
pub enum PostMessageType {
Message,
MetaEvent,
Request,
Notice,
}

#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
Expand All @@ -75,15 +79,26 @@ struct Sender {
user_id: u64,
}

/// Used to check PostType.
#[derive(Debug, Serialize, Deserialize)]
pub struct PostMsg {
pub post_type: PostMessageType,
#[serde(skip)]
_others: PhantomData<PostMsg>,
}

/// Type: Message,
#[derive(Debug, Serialize, Deserialize)]
pub struct RecvMsg {
post_type: PostMessageType,
pub struct PostMessageMsg {
post_type: PostMessageType, // PostMessageType::Message

message_type: MessageType, // group message or private message
time: u64, // timestamp
self_id: u64, // self qq number
sub_type: String, // normal ? friend ?

time: u64, // timestamp
self_id: u64, // self qq number
user_id: u64, // sender qq number

sub_type: String, // normal ? friend ?
sender: Sender,
message: String,
raw_message: String,
Expand All @@ -97,7 +112,83 @@ pub struct RecvMsg {
target_id: Option<u64>, // self qq number the same
}

impl RecvMsg {
#[derive(Debug, Serialize, Deserialize)]
pub struct PostMetaEventMsg {
// todo, now really not need these
}

#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum RequestType {
Friend,
Group,
}

impl Display for RequestType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let str = match self {
RequestType::Friend => "friend",
RequestType::Group => "group",
};
write!(f, "{}", str)
}
}

#[derive(Debug, Serialize, Deserialize)]
pub struct PostRequestMsg {
post_type: PostMessageType, // PostMessageType::Request

request_type: RequestType, // friend or group request

time: u64, // timestamp
self_id: u64, // self qq number
user_id: u64, // sender qq number

comment: String,
flag: String,
}

impl Display for PostRequestMsg {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"type: {}, user_id: {}, comment:{}",
self.request_type, self.user_id, self.comment
)
}
}

/// https://docs.go-cqhttp.org/reference/data_struct.html#post-notice-type
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum NoticeType {
GroupUpload,
GroupAdmin,
GroupDecrease,
GroupIncrease,
GroupBan,
FriendAdd, // only one needed for now
GroupRecall,
FriendRecall,
GroupCard,
OfflineFile,
ClientStatus,
Essence,
Notify,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct PostNoticeMsg {
post_type: PostMessageType, // PostMessageType::Notice

pub notice_type: NoticeType,

time: u64, // timestamp
self_id: u64, // self qq number
pub user_id: u64, // sender qq number
}

impl PostMessageMsg {
// pub fn is_group_message(&self) -> bool {
// self.message_type == MessageType::Group
// }
Expand Down Expand Up @@ -133,10 +224,6 @@ impl RecvMsg {
pub fn user_id(&self) -> u64 {
self.user_id
}
#[allow(dead_code)]
pub fn message_id(&self) -> i64 {
self.message_id
}
pub fn message(&self) -> &String {
&self.message
}
Expand All @@ -153,11 +240,11 @@ mod tests {
#[test]
fn test_recvmsg_serde() {
let msg_str = r#"{"post_type":"message","message_type":"private","time":1678331835,"self_id":222,"sub_type":"friend","sender":{"age":0,"nickname":"Mr.Eucalypt","sex":"unknown","user_id":999},"message_id":1996520388,"user_id":999,"target_id":222,"message":"test","raw_message":"test","font":0}"#;
let recv_msg = serde_json::from_str::<RecvMsg>(msg_str).unwrap();
let recv_msg = serde_json::from_str::<PostMessageMsg>(msg_str).unwrap();
println!("{:?}", recv_msg);

let msg_str_2 = r#"{"post_type":"message","message_type":"group","time":1678331780,"self_id":222,"sub_type":"normal","group_id":777,"message":"test","raw_message":"test","sender":{"age":0,"area":"","card":"","level":"","nickname":"Mr.Eucalypt","role":"member","sex":"unknown","title":"","user_id":999},"user_id":999,"message_id":-645121622,"anonymous":null,"font":0,"message_seq":133}"#;
let recv_msg_2 = serde_json::from_str::<RecvMsg>(msg_str_2).unwrap();
let recv_msg_2 = serde_json::from_str::<PostMessageMsg>(msg_str_2).unwrap();
println!("{:?}", recv_msg_2);

// let _msg_str_3 = r#"{"post_type":"meta_event","meta_event_type":"heartbeat","time":1678331981,"self_id":222,"status":{"app_enabled":true,"app_good":true,"app_initialized":true,"good":true,"online":true,"plugins_good":null,"stat":{"packet_received":201,"packet_sent":188,"packet_lost":0,"message_received":3,"message_sent":0,"disconnect_times":0,"lost_times":0,"last_message_time":1678331835}},"interval":5000}"#;
Expand All @@ -168,18 +255,28 @@ mod tests {
#[test]
fn test_recv_at() {
let msg_str = r#"{"post_type":"message","message_type":"group","time":1678336087,"self_id":222,"sub_type":"normal","anonymous":null,"group_id":777,"raw_message":"[CQ:at,qq=222] 1","sender":{"age":0,"area":"","card":"","level":"","nickname":"Mr.Eucalypt","role":"member","sex":"unknown","title":"","user_id":999},"user_id":999,"message_id":1206430729,"font":0,"message":"[CQ:at,qq=222] 1","message_seq":134}"#;
let recv_msg = serde_json::from_str::<RecvMsg>(msg_str).unwrap();
let recv_msg = serde_json::from_str::<PostMessageMsg>(msg_str).unwrap();
println!("{:?}", recv_msg);
println!("{:?}", recv_msg.pre_parse_msg(222));

let msg_str_2 = r#"{"post_type":"message","message_type":"private","time":1678336074,"self_id":222,"sub_type":"friend","target_id":222,"message":"柠檬茶 1","raw_message":"柠檬茶 1","font":0,"sender":{"age":0,"nickname":"Mr.Eucalypt","sex":"unknown","user_id":999},"message_id":-111094286,"user_id":999}"#;
let recv_msg_2 = serde_json::from_str::<RecvMsg>(msg_str_2).unwrap();
let recv_msg_2 = serde_json::from_str::<PostMessageMsg>(msg_str_2).unwrap();
println!("{:?}", recv_msg_2);
println!("{:?}", recv_msg_2.pre_parse_msg(222));

let msg_str_3 = r#"{"post_type":"message","message_type":"private","time":1678334227,"self_id":222,"sub_type":"friend","sender":{"age":0,"nickname":"Mr.Eucalypt","sex":"unknown","user_id":999},"message_id":67453260,"user_id":999,"target_id":222,"message":"[CQ:image,file=7ecb49dcfcdcca29feb728cf8811bb37.image,url=https://c2cpicdw.qpic.cn/offpic_new/999//999-3676750358-7ECB49DCFCDCCA29FEB728CF8811BB37/0?term=2\u0026amp;is_origin=0]","raw_message":"[CQ:image,file=7ecb49dcfcdcca29feb728cf8811bb37.image,url=https://c2cpicdw.qpic.cn/offpic_new/999//999-3676750358-7ECB49DCFCDCCA29FEB728CF8811BB37/0?term=2\u0026amp;is_origin=0]","font":0}"#;
let recv_msg_3 = serde_json::from_str::<RecvMsg>(msg_str_3).unwrap();
let recv_msg_3 = serde_json::from_str::<PostMessageMsg>(msg_str_3).unwrap();
println!("{:?}", recv_msg_3);
println!("{:?}", recv_msg_3.pre_parse_msg(222));
}

#[test]
fn test_notice_request_msg() {
let msg_str = r#"{"post_type":"notice","notice_type":"friend_add","time":1678697481,"self_id":2221488475,"user_id":948211941}"#;
let recv_msg = serde_json::from_str::<PostNoticeMsg>(msg_str).unwrap();
println!("{:?}", recv_msg);
let msg_str_2 = r#"{"post_type":"request","request_type":"friend","time":1678697473,"self_id":2221488475,"user_id":948211941,"comment":"","flag":"1678697473000000"}"#;
let recv_msg_2 = serde_json::from_str::<PostRequestMsg>(msg_str_2).unwrap();
println!("{:?}", recv_msg_2);
}
}
4 changes: 2 additions & 2 deletions src/role.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ pub enum BotRole {

impl BotRole {
pub fn new_from_str(ins: &str) -> Self {
match ins {
"assistant" | "Assistant" | "default" | "Default" => Self::Assistant,
match ins.to_ascii_lowercase().as_str() {
"assistant" | "default" => Self::Assistant,
"clippy" => Self::Clippy,
"taler" => Self::Taler,
"storyteller" => Self::StoryTeller,
Expand Down

0 comments on commit 972d9d5

Please sign in to comment.