Skip to content

Commit

Permalink
feat: message dispatch & impl some ManiaEvents
Browse files Browse the repository at this point in the history
- `bot_online`, `bot_offline`, `group_sys_poke`, `friend_message`, `temp_message`, `group_join_request (WIP)`
  • Loading branch information
pk5ls20 committed Feb 10, 2025
1 parent 7f9f4cc commit 3dafd72
Show file tree
Hide file tree
Showing 20 changed files with 251 additions and 57 deletions.
10 changes: 5 additions & 5 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@

| Protocol | Support | Login | Support | Messages | Support | Operations | Support | Events | Support |
|----------|:-------:|----------------------------|:-------:|:--------------|:-------:|:------------------|:-------:|:--------------------|:-------:|
| Windows | 🔴 | QrCode | 🟢 | BounceFace | 🔴 | Poke | 🔴 | Captcha | 🔴 |
| macOS | 🔴 | ~~Password~~ | 🔴 | Face | 🟡 [^1] | Recall | 🔴 | BotOnline | 🔴 |
| Linux | 🟢 | EasyLogin | 🟡 | File | 🟡[^1] | Leave Group | 🔴 | BotOffline | 🔴 |
| | | UnusualDevice<br/>Password | 🔴 | Forward | 🟡[^1] | Set Special Title | 🔴 | Message | 🟡 |
| | | UnusualDevice<br/>Easy | 🔴 | ~~GreyTip~~ | 🔴 | Kick Member | 🔴 | Poke | 🔴 |
| Windows | 🔴 | QrCode | 🟢 | BounceFace | 🔴 | Poke | 🔴 | ~~Captcha~~ | 🔴 |
| macOS | 🔴 | ~~Password~~ | 🔴 | Face | 🟡 [^1] | Recall | 🔴 | BotOnline | 🟢 |
| Linux | 🟢 | EasyLogin | 🟡 | File | 🟡[^1] | Leave Group | 🔴 | BotOffline | 🟢 |
| | | UnusualDevice<br/>Password | 🔴 | Forward | 🟡[^1] | Set Special Title | 🔴 | Message | 🟢 |
| | | UnusualDevice<br/>Easy | 🔴 | ~~GreyTip~~ | 🔴 | Kick Member | 🔴 | Poke | 🟢 |
| | | ~~NewDeviceVerify~~ | 🔴 | GroupReaction | 🔴 | Mute Member | 🔴 | MessageRecall | 🔴 |
| | | | | Image | 🟡[^1] | Set Admin | 🔴 | GroupMemberDecrease | 🔴 |
| | | | | Json | 🟢 | Friend Request | 🔴 | GroupMemberIncrease | 🔴 |
Expand Down
42 changes: 21 additions & 21 deletions examples/multi_login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,27 @@ async fn main() {
let mut client = Client::new(config, device, key_store).await.unwrap();
let operator = client.handle().operator();
let mut event_listener = operator.event_listener.clone();
tokio::spawn(async move {
loop {
tokio::select! {
_ = event_listener.system.changed() => {
if let Some(ref be) = *event_listener.system.borrow() {
tracing::info!("[SystemEvent] {:?}", be);
}
}
_ = event_listener.friend.changed() => {
if let Some(ref fe) = *event_listener.friend.borrow() {
tracing::info!("[FriendEvent] {:?}", fe);
}
}
_ = event_listener.group.changed() => {
if let Some(ref ge) = *event_listener.group.borrow() {
tracing::info!("[GroupEvent] {:?}", ge);
}
}
}
}
});
tokio::spawn(async move {
client.spawn().await;
});
Expand Down Expand Up @@ -77,26 +98,5 @@ async fn main() {
.update_key_store()
.save("keystore.json")
.unwrap_or_else(|e| tracing::error!("Failed to save key store: {:?}", e));
tokio::spawn(async move {
loop {
tokio::select! {
_ = event_listener.bot.changed() => {
if let Some(ref be) = *event_listener.bot.borrow() {
tracing::info!("[BotEvent] {:?}", be);
}
}
_ = event_listener.friend.changed() => {
if let Some(ref fe) = *event_listener.friend.borrow() {
tracing::info!("[FriendEvent] {:?}", fe);
}
}
_ = event_listener.group.changed() => {
if let Some(ref ge) = *event_listener.group.borrow() {
tracing::info!("[GroupEvent] {:?}", ge);
}
}
}
}
});
tokio::signal::ctrl_c().await.unwrap();
}
4 changes: 2 additions & 2 deletions mania-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,11 @@ pub fn derive_dummy_event(input: TokenStream) -> TokenStream {

impl crate::core::event::ClientEvent for #struct_name {
fn build(&self, _: &crate::core::context::Context) -> crate::core::event::CEBuildResult {
unreachable!("DummyEvent should not be built");
unreachable!("DummyEvent {} should not be parsed", stringify!(#struct_name));
}

fn parse(_: bytes::Bytes, _: &crate::core::context::Context) -> crate::core::event::CEParseResult {
unreachable!("DummyEvent should not be parsed");
unreachable!("DummyEvent {} should not be parsed", stringify!(#struct_name));
}
}
};
Expand Down
39 changes: 36 additions & 3 deletions mania/src/core/business/messaging_logic.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
use crate::core::business::LogicRegistry;
use crate::core::business::{BusinessHandle, LogicFlow};
use crate::core::event::message::push_msg::PushMessageEvent;
use crate::core::event::notify::group_sys_poke::GroupSysPokeEvent;
use crate::core::event::notify::group_sys_request_join::GroupSysRequestJoinEvent;
use crate::core::event::prelude::*;
use crate::event::friend::{FriendEvent, friend_message};
use crate::event::group::group_poke::GroupPokeEvent;
use crate::event::group::{GroupEvent, group_message};
use crate::event::system::{SystemEvent, temp_message};
use crate::message::chain::{MessageChain, MessageType};
use crate::message::entity::Entity;
use crate::message::entity::file::FileUnique;
use mania_macros::handle_event;
use std::sync::Arc;

#[handle_event(PushMessageEvent, GroupSysRequestJoinEvent)]
#[handle_event(PushMessageEvent, GroupSysRequestJoinEvent, GroupSysPokeEvent)]
async fn messaging_logic(
event: &mut dyn ServerEvent,
handle: Arc<BusinessHandle>,
Expand Down Expand Up @@ -42,9 +46,26 @@ async fn messaging_logic_incoming(
.send(Some(GroupEvent::GroupMessage(
group_message::GroupMessageEvent { chain },
)))
.expect("Failed to send group event");
.expect("Failed to send group_message event");
}
MessageType::Friend(_) => {
handle
.event_dispatcher
.friend
.send(Some(FriendEvent::FriendMessageEvent(
friend_message::FriendMessageEvent { chain },
)))
.expect("Failed to send friend_message event");
}
MessageType::Temp => {
handle
.event_dispatcher
.system
.send(Some(SystemEvent::TempMessageEvent(
temp_message::TempMessageEvent { chain },
)))
.expect("Failed to send temp_message event");
}
// TODO: friend message & temp message
_ => {}
}
} else {
Expand All @@ -57,6 +78,18 @@ async fn messaging_logic_incoming(
{
tracing::debug!("Handling GroupSysRequestJoinEvent: {:?}", event); // TODO: dispatch
}
_ if let Some(event) = event.as_any_mut().downcast_mut::<GroupSysPokeEvent>() => handle
.event_dispatcher
.group
.send(Some(GroupEvent::GroupPoke(GroupPokeEvent {
group_uin: event.group_uin,
operator_uin: event.operator_uin,
target_uin: event.target_uin,
action: event.action.to_owned(),
suffix: event.suffix.to_owned(),
action_img_url: event.action_img_url.to_owned(),
})))
.expect("Failed to send group event"),
_ => {}
}
event
Expand Down
12 changes: 10 additions & 2 deletions mania/src/core/business/wt_logic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use crate::core::business::LogicRegistry;
use crate::core::business::{BusinessHandle, LogicFlow};
use crate::core::event::prelude::*;
use crate::core::event::system::kick_nt::KickNTEvent;
use crate::event::system::SystemEvent;
use crate::event::system::bot_offline::BotOfflineEvent;
use mania_macros::handle_event;
use std::sync::Arc;

Expand All @@ -20,13 +22,19 @@ async fn messaging_logic(

async fn messaging_logic_incoming(
event: &mut dyn ServerEvent,
_: Arc<BusinessHandle>,
handle: Arc<BusinessHandle>,
) -> &dyn ServerEvent {
match event {
_ if let Some(kick) = event.as_any_mut().downcast_mut::<KickNTEvent>() => {
tracing::error!("KickNTEvent: {:?}", kick);
tracing::error!("Bot will be offline in 5 seconds...");
todo!("Dispatch this event")
handle
.event_dispatcher
.system
.send(Some(SystemEvent::BotOfflineEvent(BotOfflineEvent {
reason: Some(format!("{}: {}", kick.title, kick.tips)),
})))
.expect("send BotOnlineEvent failed");
}
_ => {}
}
Expand Down
3 changes: 0 additions & 3 deletions mania/src/core/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,6 @@ pub enum EventError {
#[error("failed to parse mania internal packet: {0}")]
PacketParseError(#[from] crate::core::packet::PacketError),

#[error("Unknown olpush message type {0}")]
UnknownOlpushMessageTypeError(u32),

#[error("An mania internal event error occurred: {0}")]
OtherError(String),

Expand Down
110 changes: 107 additions & 3 deletions mania/src/core/event/message/push_msg.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use crate::core::event::notify::group_sys_poke::GroupSysPokeEvent;
use crate::core::event::notify::group_sys_request_join::GroupSysRequestJoinEvent;
use crate::core::event::prelude::*;
use crate::core::protos::message::{GroupJoin, PushMsg};
use crate::core::protos::message::{GroupJoin, NotifyMessageBody, PushMsg};
use crate::message::chain::MessageChain;
use crate::message::packer::MessagePacker;
use std::collections::HashMap;

#[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
#[repr(u32)]
Expand Down Expand Up @@ -73,8 +75,13 @@ impl ClientEvent for PushMessageEvent {
.and_then(|msg| msg.content_head.as_ref())
.map(|content_head| content_head.r#type)
.ok_or_else(|| EventError::OtherError("Cannot get typ in PushMsg".to_string()))?;
let packet_type =
PkgType::try_from(typ).map_err(|_| EventError::UnknownOlpushMessageTypeError(typ))?;
let packet_type = match PkgType::try_from(typ) {
Ok(packet_type) => packet_type,
Err(_) => {
tracing::warn!("receive unknown olpush message type: {:?}", typ);
return Ok(ClientResult::single(Box::new(Self { chain: None })));
}
};
let mut chain: Option<MessageChain> = None;
let mut extra: Option<Vec<Box<dyn ServerEvent>>> = match packet_type {
PkgType::PrivateMessage
Expand Down Expand Up @@ -121,6 +128,9 @@ impl ClientEvent for PushMessageEvent {
}));
}
}
PkgType::Event0x2DC => {
extra = process_event_0x2dc(&packet, &mut extra)?.take();
}
// TODO: handle other message types
_ => {
tracing::warn!("receive unknown message type: {:?}", packet_type);
Expand All @@ -129,3 +139,97 @@ impl ClientEvent for PushMessageEvent {
Ok(ClientResult::with_extra(Box::new(Self { chain }), extra))
}
}

fn process_event_0x2dc<'a>(
packet: &'a PushMsg,
extra: &'a mut Option<Vec<Box<dyn ServerEvent>>>,
) -> Result<&'a mut Option<Vec<Box<dyn ServerEvent>>>, EventError> {
let sub_type = Event0x2DCSubType::try_from(
packet
.message
.as_ref()
.ok_or(EventError::OtherError(
"Cannot get message in PushMsg".to_string(),
))?
.content_head
.as_ref()
.ok_or(EventError::OtherError(
"Cannot get content_head in PushMsg".to_string(),
))?
.sub_type
.ok_or(EventError::OtherError(
"Cannot get sub_type in PushMsgContentHead".to_string(),
))?,
);
let sub_type = match sub_type {
Ok(sub_type) => sub_type,
Err(_) => {
tracing::warn!(
"receive unknown olpush message 0x2dc sub type: {:?}",
sub_type
);
return Ok(extra);
}
};
match sub_type {
Event0x2DCSubType::GroupGreyTipNotice => {
let msg_content = match packet
.message
.as_ref()
.and_then(|m| m.body.as_ref())
.and_then(|b| b.msg_content.as_ref())
{
Some(content) => content,
None => return Ok(extra),
};
let mut packet_reader = PacketReader::new(Bytes::from(msg_content.to_owned()));
let group_uin = packet_reader.u32();
packet_reader.u8();
let proto = packet_reader
.read_with_length::<_, { PREFIX_U16 | PREFIX_LENGTH_ONLY }>(|p| p.bytes());
let grey_tip = NotifyMessageBody::decode(proto)?;
let gray_tip_info = match grey_tip.gray_tip_info.as_ref() {
Some(info) if info.busi_type == 12 => info,
_ => return Ok(extra),
};
let templates: HashMap<String, String> = gray_tip_info
.msg_templ_param
.iter()
.map(|param| (param.key.to_owned(), param.value.to_owned()))
.collect();
let action = templates
.get("action_str")
.or_else(|| templates.get("alt_str1"))
.cloned()
.unwrap_or_default();
let operator_uin = templates
.get("uin_str1")
.ok_or_else(|| EventError::OtherError("Missing uin_str1 in grey tip event".into()))?
.parse::<u32>()
.map_err(|e| {
EventError::OtherError(format!("Failed to parse uin_str1 in poke event: {}", e))
})?;
let target_uin = templates
.get("uin_str2")
.ok_or_else(|| EventError::OtherError("Missing uin_str2 in grey tip event".into()))?
.parse::<u32>()
.map_err(|e| {
EventError::OtherError(format!("Failed to parse uin_str2 in poke event: {}", e))
})?;
let suffix = templates.get("suffix").cloned().unwrap_or_default();
let action_img_url = templates.get("action_img_url").cloned().unwrap_or_default();
extra.as_mut().unwrap().push(Box::new(GroupSysPokeEvent {
group_uin,
operator_uin,
target_uin,
action,
suffix,
action_img_url,
}));
}
_ => {
tracing::warn!("receive unknown message 0x2dc sub type: {:?}", sub_type);
}
}
Ok(extra)
}
11 changes: 11 additions & 0 deletions mania/src/core/event/notify/group_sys_poke.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use crate::core::event::prelude::*;

#[derive(Debug, DummyEvent, Default)]
pub struct GroupSysPokeEvent {
pub group_uin: u32,
pub operator_uin: u32,
pub target_uin: u32,
pub action: String,
pub suffix: String,
pub action_img_url: String,
}
1 change: 1 addition & 0 deletions mania/src/core/event/notify/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod group_sys_poke;
pub mod group_sys_request_join;
4 changes: 2 additions & 2 deletions mania/src/core/event/system/kick_nt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use crate::core::protos::system::ServiceKickNtResponse;
#[command("trpc.qq_new_tech.status_svc.StatusService.KickNT")]
#[derive(Debug, ServerEvent)]
pub struct KickNTEvent {
tips: String,
title: String,
pub tips: String,
pub title: String,
}

impl ClientEvent for KickNTEvent {
Expand Down
8 changes: 8 additions & 0 deletions mania/src/core/operation/wt_op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ use crate::core::event::system::info_sync::InfoSyncEvent;
use crate::core::event::system::nt_sso_alive::NtSsoAliveEvent;
use crate::core::http;
use crate::core::session::QrSign;
use crate::event::system::SystemEvent;
use crate::event::system::bot_online::BotOnlineEvent;
use crate::{KeyStore, ManiaError, ManiaResult};
use bytes::Bytes;
use std::borrow::Cow;
Expand Down Expand Up @@ -192,6 +194,12 @@ impl BusinessHandle {
"d2key: {:?}",
hex::encode(**self.context.key_store.session.d2_key.load())
);
self.event_dispatcher
.system
.send(Some(SystemEvent::BotOnlineEvent(BotOnlineEvent {
reason: None,
})))
.expect("send BotOnlineEvent failed");
let handle = self.clone();
let heartbeat = async move {
let mut hb_interval = tokio::time::interval(Duration::from_secs(10));
Expand Down
6 changes: 0 additions & 6 deletions mania/src/event/bot.rs

This file was deleted.

5 changes: 4 additions & 1 deletion mania/src/event/friend.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
pub mod friend_message;
pub mod friend_poke;

#[derive(Debug)]
#[allow(clippy::large_enum_variant)] // FIXME: do we need spilt or refactoring?
pub enum FriendEvent {
FriendPokeEvent(friend_poke::FriendPokeEvent),
FriendPokeEvent(friend_poke::FriendPokeEvent), // FIXME: clippy warn: at least 80 bytes
FriendMessageEvent(friend_message::FriendMessageEvent), // FIXME: clippy warn: at least 320 bytes
}
Loading

0 comments on commit 3dafd72

Please sign in to comment.