Skip to content
This repository has been archived by the owner on Oct 21, 2023. It is now read-only.

Commit

Permalink
feat: support recall event
Browse files Browse the repository at this point in the history
Resolve #22
See #17
  • Loading branch information
BlueGlassBlock committed Mar 16, 2023
1 parent a2171e1 commit d81a5cb
Show file tree
Hide file tree
Showing 10 changed files with 208 additions and 78 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,4 @@

### 其他

- 使用 [`towncrier`](https://towncrier.readthedocs.io) 和 GitHub Release 来管理项目。 [#18](https://github.com/BlueGlassBlock/ichika/issues/18)
- 使用 [`towncrier`](https://towncrier.readthedocs.io) 和 GitHub Release 来管理项目。 ([#18](https://github.com/BlueGlassBlock/ichika/issues/18))
1 change: 1 addition & 0 deletions news/22.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
支持处理群聊和好友撤回消息事件
31 changes: 30 additions & 1 deletion python/ichika/core/events/__init__.pyi
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from dataclasses import dataclass
from datetime import datetime

from graia.amnesia.message import MessageChain

from . import structs as structs
from .structs import MemberInfo, MessageSource
from .structs import FriendInfo, MemberInfo, MessageSource

internal_repr = dataclass(frozen=True, init=False)

Expand All @@ -16,3 +17,31 @@ class GroupMessage:
source: MessageSource
content: MessageChain
sender: MemberInfo

@internal_repr
class GroupRecallMessage:
time: datetime
author: MemberInfo
operator: MemberInfo
seq: int

@internal_repr
class FriendMessage:
source: MessageSource
content: MessageChain
sender: FriendInfo

@internal_repr
class FriendRecallMessage:
time: datetime
author: FriendInfo
seq: int

@internal_repr
class TempMessage:
source: MessageSource
content: MessageChain
sender: MemberInfo

@internal_repr
class UnknownEvent: ...
5 changes: 5 additions & 0 deletions python/ichika/core/events/structs.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,8 @@ class MemberInfo:
uin: int
name: str
group: Group

@internal_repr
class FriendInfo:
uin: int
nickname: str
24 changes: 12 additions & 12 deletions src/client/friend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ use ricq_core::command::friendlist::FriendListResponse;
#[pyclass(get_all)]
#[derive(PyRepr, Clone)]
pub struct Friend {
uin: i64,
nick: String,
remark: String,
face_id: i16,
group_id: u8,
pub uin: i64,
pub nick: String,
pub remark: String,
pub face_id: i16,
pub group_id: u8,
}

impl From<FriendInfo> for Friend {
Expand All @@ -31,11 +31,11 @@ impl From<FriendInfo> for Friend {
#[pyclass(get_all)]
#[derive(PyRepr, Clone)]
pub struct FriendGroup {
group_id: u8,
name: String,
total_count: i32,
online_count: i32,
seq_id: u8,
pub group_id: u8,
pub name: String,
pub total_count: i32,
pub online_count: i32,
pub seq_id: u8,
}

impl From<FriendGroupInfo> for FriendGroup {
Expand Down Expand Up @@ -64,9 +64,9 @@ pub struct FriendList {
entries: Vec<Friend>,
friend_groups: HashMap<u8, FriendGroup>,
#[pyo3(get)]
total_count: i16,
pub total_count: i16,
#[pyo3(get)]
online_count: i16,
pub online_count: i16,
}

#[pymethods]
Expand Down
177 changes: 120 additions & 57 deletions src/events/converter.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
use ricq::client::event as rce;
use ricq::handler::QEvent;

use super::structs::{FriendInfo, MemberInfo, MessageSource};
use super::{FriendMessage, GroupMessage, LoginEvent, TempMessage, UnknownEvent};
use super::{
FriendMessage,
FriendRecallMessage,
GroupMessage,
GroupRecallMessage,
LoginEvent,
TempMessage,
UnknownEvent,
};
use crate::client::cache;
use crate::exc::MapPyErr;
use crate::message::convert::{serialize_as_py_chain, serialize_audio};
use crate::utils::{py_try, py_use};
use crate::PyRet;
use crate::utils::{datetime_from_ts, py_try, AsPython};
use crate::{call_static_py, PyRet};

pub async fn convert(event: QEvent) -> PyRet {
match event {
Expand All @@ -18,20 +27,14 @@ pub async fn convert(event: QEvent) -> PyRet {
QEvent::FriendMessage(event) => handle_friend_message(event).await,
QEvent::FriendAudioMessage(event) => handle_friend_audio(event).await,
QEvent::GroupTempMessage(event) => handle_temp_message(event).await,
unknown => obj(|_| UnknownEvent { inner: unknown }),
QEvent::GroupMessageRecall(event) => handle_group_recall(event).await,
QEvent::FriendMessageRecall(event) => handle_friend_recall(event).await,
unknown => Ok(UnknownEvent { inner: unknown }.obj()),
}
}

fn obj<F, R, T>(f: F) -> PyResult<T>
where
F: for<'py> FnOnce(Python<'py>) -> R,
R: IntoPy<T>,
{
py_use(|py| Ok(f(py).into_py(py)))
}

async fn handle_login(uin: i64) -> PyRet {
obj(|py| LoginEvent { uin }.into_py(py))
Ok(LoginEvent { uin }.obj())
}

async fn handle_group_message(event: rce::GroupMessageEvent) -> PyRet {
Expand All @@ -45,19 +48,44 @@ async fn handle_group_message(event: rce::GroupMessageEvent) -> PyRet {
.py_res()?;

let content = py_try(|py| serialize_as_py_chain(py, msg.elements))?;
obj(|py| GroupMessage {
source: MessageSource::new(py, &msg.seqs, &msg.rands, msg.time),
content,
sender: MemberInfo {
uin: msg.from_uin,
name: sender_info.card_name.clone(),
nickname: sender_info.nickname.clone(),
group: (*group_info).clone(),
permission: sender_info.permission,
},
py_try(|py| {
Ok(GroupMessage {
source: MessageSource::new(py, &msg.seqs, &msg.rands, msg.time)?,
content,
sender: MemberInfo {
uin: msg.from_uin,
name: sender_info.card_name.clone(),
nickname: sender_info.nickname.clone(),
group: (*group_info).clone(),
permission: sender_info.permission,
},
}
.obj())
})
}

async fn handle_group_recall(event: rce::GroupMessageRecallEvent) -> PyRet {
let msg = event.inner;
let mut cache = cache(event.client).await;
let group_info = cache.fetch_group(msg.group_code).await.py_res()?;
let author = cache
.fetch_member(msg.group_code, msg.author_uin)
.await
.py_res()?;
let operator = cache
.fetch_member(msg.group_code, msg.operator_uin)
.await
.py_res()?;
let time = py_try(|py| Ok(call_static_py!(datetime_from_ts, py, (msg.time))?.into_py(py)))?;
Ok(GroupRecallMessage {
time,
author: MemberInfo::new(&author, (*group_info).clone()),
operator: MemberInfo::new(&operator, (*group_info).clone()),
seq: msg.msg_seq,
}
.obj())
}

async fn handle_group_audio(event: rce::GroupAudioMessageEvent) -> PyRet {
let url = event.url().await.py_res()?;
let msg = event.inner;
Expand All @@ -69,43 +97,75 @@ async fn handle_group_audio(event: rce::GroupAudioMessageEvent) -> PyRet {
.await
.py_res()?;

obj(|py| GroupMessage {
source: MessageSource::new(py, &msg.seqs, &msg.rands, msg.time),
content,
sender: MemberInfo {
uin: msg.from_uin,
name: sender_info.card_name.clone(),
nickname: sender_info.nickname.clone(),
group: (*group_info).clone(),
permission: sender_info.permission,
},
py_try(|py| {
Ok(GroupMessage {
source: MessageSource::new(py, &msg.seqs, &msg.rands, msg.time)?,
content,
sender: MemberInfo {
uin: msg.from_uin,
name: sender_info.card_name.clone(),
nickname: sender_info.nickname.clone(),
group: (*group_info).clone(),
permission: sender_info.permission,
},
}
.obj())
})
}

async fn handle_friend_message(event: rce::FriendMessageEvent) -> PyRet {
let msg = event.inner;
let content = py_try(|py| serialize_as_py_chain(py, msg.elements))?;
obj(|py| FriendMessage {
source: MessageSource::new(py, &msg.seqs, &msg.rands, msg.time),
content,
sender: FriendInfo {
uin: msg.from_uin,
nickname: msg.from_nick,
},
py_try(|py| {
Ok(FriendMessage {
source: MessageSource::new(py, &msg.seqs, &msg.rands, msg.time)?,
content,
sender: FriendInfo {
uin: msg.from_uin,
nickname: msg.from_nick,
},
}
.obj())
})
}

async fn handle_friend_recall(event: rce::FriendMessageRecallEvent) -> PyRet {
let msg = event.inner;
let mut cache = cache(event.client).await;
let friend = cache
.fetch_friend_list()
.await
.py_res()?
.find_friend(msg.friend_uin)
.ok_or_else(|| {
PyValueError::new_err(format!("Unable to find friend {}", msg.friend_uin))
})?;
let time = py_try(|py| Ok(call_static_py!(datetime_from_ts, py, (msg.time))?.into_py(py)))?;
Ok(FriendRecallMessage {
time,
author: FriendInfo {
uin: friend.uin,
nickname: friend.nick,
},
seq: msg.msg_seq,
}
.obj())
}

async fn handle_friend_audio(event: rce::FriendAudioMessageEvent) -> PyRet {
let url = event.url().await.py_res()?;
let msg = event.inner;
let content = py_try(|py| serialize_audio(py, url, &msg.audio.0))?;
obj(|py| FriendMessage {
source: MessageSource::new(py, &msg.seqs, &msg.rands, msg.time),
content,
sender: FriendInfo {
uin: msg.from_uin,
nickname: msg.from_nick,
},
py_try(|py| {
Ok(FriendMessage {
source: MessageSource::new(py, &msg.seqs, &msg.rands, msg.time)?,
content,
sender: FriendInfo {
uin: msg.from_uin,
nickname: msg.from_nick,
},
}
.obj())
})
}

Expand All @@ -120,15 +180,18 @@ async fn handle_temp_message(event: rce::GroupTempMessageEvent) -> PyRet {
.await
.py_res()?;

obj(|py| TempMessage {
source: MessageSource::new(py, &msg.seqs, &msg.rands, msg.time),
content,
sender: MemberInfo {
uin: msg.from_uin,
name: sender_info.card_name.clone(),
nickname: sender_info.nickname.clone(),
group: (*group_info).clone(),
permission: sender_info.permission,
},
py_try(|py| {
Ok(TempMessage {
source: MessageSource::new(py, &msg.seqs, &msg.rands, msg.time)?,
content,
sender: MemberInfo {
uin: msg.from_uin,
name: sender_info.card_name.clone(),
nickname: sender_info.nickname.clone(),
group: (*group_info).clone(),
permission: sender_info.permission,
},
}
.obj())
})
}
17 changes: 17 additions & 0 deletions src/events/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ pub struct GroupMessage {
sender: MemberInfo,
}

#[pyclass(get_all)]
#[derive(PyRepr, Clone)]
pub struct GroupRecallMessage {
time: PyObject, // PyDatetime
author: MemberInfo,
operator: MemberInfo,
seq: i32,
}

#[pyclass(get_all)]
#[derive(PyRepr, Clone)]
pub struct FriendMessage {
Expand All @@ -32,6 +41,14 @@ pub struct FriendMessage {
sender: FriendInfo,
}

#[pyclass(get_all)]
#[derive(PyRepr, Clone)]
pub struct FriendRecallMessage {
time: PyObject, // PyDatetime
author: FriendInfo,
seq: i32,
}

#[pyclass(get_all)]
#[derive(PyRepr, Clone)]
pub struct TempMessage {
Expand Down
Loading

0 comments on commit d81a5cb

Please sign in to comment.