进度是真tm快啊

This commit is contained in:
shenjack 2024-06-04 23:48:01 +08:00
parent 5a07286d2d
commit ff255426f6
Signed by: shenjack
GPG Key ID: 7B1134A979775551
12 changed files with 273 additions and 70 deletions

2
Cargo.lock generated
View File

@ -659,7 +659,7 @@ dependencies = [
[[package]]
name = "ica-rs"
version = "0.6.5"
version = "0.6.6"
dependencies = [
"anyhow",
"base64 0.22.1",

View File

@ -1,6 +1,6 @@
[package]
name = "ica-rs"
version = "0.6.5"
version = "0.6.6"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -188,9 +188,9 @@ class TailchatReciveMessage:
@property
def sender_id(self) -> TailchatType.UserId:
...
@property
def is_from_self(self) -> bool:
...
# @property
# def is_from_self(self) -> bool:
# ...
@property
def is_reply(self) -> bool:
...
@ -202,11 +202,41 @@ class TailchatReciveMessage:
...
class TailchatSendingMessage:
"""
Tailchat 将要发送的信息
"""
@property
def content(self) -> str:
...
@content.setter
def content(self, value: str) -> None:
...
def with_content(self, content: str) -> "TailchatSendingMessage":
"""
为了链式调用, 返回自身
"""
self.content = content
return self
# def set_img(self, file: bytes, file_type: str, as_sticker: bool):
# """
# 设置消息的图片
# @param file: 图片文件 (实际上是 vec<u8>)
# @param file_type: 图片类型 (MIME) (image/png; image/jpeg)
# @param as_sticker: 是否作为贴纸发送
# """
class TailchatClient:
"""
Tailchat 的客户端
"""
def send_message(self, message: TailchatSendingMessage) -> bool:
...
def send_and_warn(self, message: TailchatSendingMessage) -> bool:
"""发送消息, 并在日志中输出警告信息"""
self.warn(message.content)
return self.send_message(message)
def debug(self, message: str) -> None:
"""向日志中输出调试信息"""
@ -235,8 +265,9 @@ on_ica_delete_message = Callable[[IcaType.MessageId, IcaClient], None]
# def on_delete_message(msg_id: MessageId, client: IcaClient) -> None:
# ...
# TODO: Tailchat adapter
on_tailchat_message = Callable[[], None]
on_tailchat_message = Callable[[TailchatClient, TailchatReciveMessage], None]
# def on_tailchat_message(client: TailchatClient, msg: TailchatReciveMessage) -> None:
# ...
on_config = Callable[[None], Tuple[str, str]]

View File

@ -11,3 +11,5 @@ def on_ica_message(msg: IcaNewMessage, client: IcaClient) -> None:
if msg.content == "/bot":
reply = msg.reply_with(f"ica-async-rs({client.version})-sync-py {client.ica_version}")
client.send_message(reply)

View File

@ -3,18 +3,6 @@ use serde_json::{json, Value as JsonValue};
use crate::data_struct::tailchat::{ConverseId, GroupId, MessageId, UserId};
/*{'_id': '6606b3075163504389a6fc47',
'content': '(',
'author': '6602e20d7b8d10675758e36b',
'groupId': '6602e331d31fd31b04aa0693',
'converseId': '6602f785928c4254f17726b2',
'hasRecall': False,
'meta': {'mentions': []},
'reactions': [],
'createdAt': ExtType(code=0, data=b'\x00\x00\x01\x8e\x8a+TJ'),
'updatedAt': ExtType(code=0, data=b'\x00\x00\x01\x8e\x8a+TJ'),
'__v': 0} */
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ReciveMessage {
/// 消息ID
@ -35,6 +23,7 @@ pub struct ReciveMessage {
#[serde(rename = "hasRecall")]
pub has_recall: bool,
/// 暂时懒得解析这玩意
/// 准确来说是不确定内容, 毕竟没细看 API
pub meta: JsonValue,
/// 也懒得解析这玩意
pub reactions: Vec<JsonValue>,
@ -50,19 +39,46 @@ pub struct ReciveMessage {
}
impl ReciveMessage {
pub fn as_reply(&self) -> ReplyMessage {
ReplyMessage {
content: self.content.clone(),
converse_id: self.converse_id.clone(),
group_id: self.group_id.clone(),
reply_id: self.msg_id.clone(),
}
pub fn is_reply(&self) -> bool { self.meta.get("reply").is_some() }
/// 创建一个对这条消息的回复
pub fn as_reply(&self) -> SendingMessage {
SendingMessage::new(
"".to_string(),
self.converse_id.clone(),
self.group_id.clone(),
Some(ReplyMeta::from_recive_message(self)),
)
}
/// 回复这条消息
pub fn reply_with(&self, content: String) -> SendingMessage {
SendingMessage::new(
content,
self.converse_id.clone(),
self.group_id.clone(),
Some(ReplyMeta::from_recive_message(self)),
)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize)]
/// 将要发送的消息
///
/// 发送时:
/// - `content`: 回复的消息内容
/// - `converseId`: 会话ID
/// - `groupId`: 服务器ID
/// - `meta`: 回复的消息的元数据 可能为空
/// - `mentions`: 被回复的人的ID (可以是多个)
/// - `reply`: 被回复的消息
/// - `_id`: 被回复的消息ID
/// - `author`: 被回复的消息的发送者ID
/// - `content`: 被回复的消息内容
pub struct SendingMessage {
/// 消息内容
///
/// 其实还有个 plain, 就是不知道干啥的
pub content: String,
/// 会话ID
#[serde(rename = "converseId")]
@ -70,11 +86,38 @@ pub struct SendingMessage {
/// 服务器ID
#[serde(rename = "groupId")]
pub group_id: GroupId,
/// 消息的元数据
pub meta: Option<ReplyMeta>,
}
impl SendingMessage {
pub fn new(
content: String,
converse_id: ConverseId,
group_id: GroupId,
meta: Option<ReplyMeta>,
) -> Self {
Self {
content,
converse_id,
group_id,
meta,
}
}
pub fn new_without_meta(content: String, converse_id: ConverseId, group_id: GroupId) -> Self {
Self {
content,
converse_id,
group_id,
meta: None,
}
}
pub fn as_value(&self) -> JsonValue { serde_json::to_value(self).unwrap() }
}
#[derive(Debug, Clone)]
pub struct ReplyMeta {
/// 被回复的人的ID (可以是多个?)
/// 被回复的人的ID (可以是多个)
pub mentions: Vec<UserId>,
/// 被回复的消息ID
pub reply_id: MessageId,
@ -84,6 +127,19 @@ pub struct ReplyMeta {
pub reply_content: String,
}
impl ReplyMeta {
pub fn from_recive_message(msg: &ReciveMessage) -> Self {
Self {
mentions: vec![msg.sender_id.clone()],
reply_id: msg.msg_id.clone(),
reply_author: msg.sender_id.clone(),
reply_content: msg.content.clone(),
}
}
pub fn add_mention(&mut self, user_id: UserId) { self.mentions.push(user_id); }
pub fn replace_content(&mut self, content: String) { self.reply_content = content; }
}
impl Serialize for ReplyMeta {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@ -91,9 +147,9 @@ impl Serialize for ReplyMeta {
{
let reply = json! {
{
"replyId": self.reply_id,
"replyAuthor": self.reply_author,
"replyContent": self.reply_content,
"_id": self.reply_id,
"author": self.reply_author,
"content": self.reply_content,
}
};
let mut map = serde_json::Map::new();
@ -102,18 +158,3 @@ impl Serialize for ReplyMeta {
map.serialize(serializer)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReplyMessage {
/// 消息内容
pub content: String,
/// 会话ID
#[serde(rename = "converseId")]
pub converse_id: ConverseId,
/// 服务器ID
#[serde(rename = "groupId")]
pub group_id: GroupId,
/// 回复的消息ID
#[serde(rename = "replyId")]
pub reply_id: MessageId,
}

View File

@ -25,8 +25,8 @@ pub type MainStatus = status::BotStatus;
pub type StopGetter = tokio::sync::oneshot::Receiver<()>;
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub const ICA_VERSION: &str = "1.4.1";
pub const TAILCHAT_VERSION: &str = "0.1.0";
pub const ICA_VERSION: &str = "1.5.0";
pub const TAILCHAT_VERSION: &str = "0.2.0";
#[macro_export]
macro_rules! wrap_callback {

View File

@ -174,8 +174,9 @@ pub async fn tailchat_new_message_py(message: &tailchat::messages::ReciveMessage
let plugins = PyStatus::get_files();
for (path, plugin) in plugins.iter() {
// let msg = class::tailchat::
let args = ();
let msg = class::tailchat::TailchatReciveMessagePy::from_recive_message(&message);
let client = class::tailchat::TailchatClientPy::new(client);
let args = (msg, client);
call_py_func!(args, plugin, path, TAILCHAT_NEW_MESSAGE_FUNC, client);
}
}

View File

@ -1,4 +1,5 @@
pub mod ica;
pub mod tailchat;
use pyo3::prelude::*;
use toml::Value as TomlValue;

View File

@ -185,10 +185,7 @@ impl IcaClientPy {
pub fn send_and_warn(&self, message: SendMessagePy) -> bool {
warn!(message.msg.content);
tokio::task::block_in_place(|| {
let rt = Runtime::new().unwrap();
rt.block_on(send_message(&self.client, &message.msg))
})
self.send_message(message)
}
pub fn delete_message(&self, message: DeleteMessagePy) -> bool {
@ -222,11 +219,9 @@ impl IcaClientPy {
pub fn debug(&self, content: String) {
debug!("{}", content);
}
pub fn info(&self, content: String) {
info!("{}", content);
}
pub fn warn(&self, content: String) {
warn!("{}", content);
}

View File

@ -0,0 +1,116 @@
use pyo3::prelude::*;
use rust_socketio::asynchronous::Client;
use tracing::{debug, info, warn};
use crate::data_struct::tailchat::messages::{ReciveMessage, ReplyMeta, SendingMessage};
use crate::data_struct::tailchat::{ConverseId, GroupId, MessageId, UserId};
use crate::tailchat::client::send_message;
#[pyclass]
#[pyo3(name = "TailchatClient")]
pub struct TailchatClientPy {
pub client: Client,
}
impl TailchatClientPy {
pub fn new(client: &Client) -> Self {
Self {
client: client.clone(),
}
}
}
#[pyclass]
#[pyo3(name = "TailchatStatus")]
/// 预留?
pub struct TailchatStatusPy {}
#[pyclass]
#[pyo3(name = "TailchatReciveMessage")]
pub struct TailchatReciveMessagePy {
pub message: ReciveMessage,
}
impl TailchatReciveMessagePy {
pub fn from_recive_message(msg: &ReciveMessage) -> Self {
Self {
message: msg.clone(),
}
}
}
#[derive(Clone)]
#[pyclass]
#[pyo3(name = "TailchatSendingMessage")]
pub struct TailchatSendingMessagePy {
pub message: SendingMessage,
}
#[pymethods]
impl TailchatClientPy {
pub fn send_message(&self, message: TailchatSendingMessagePy) -> bool {
tokio::task::block_in_place(|| {
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(send_message(&self.client, &message.message))
})
}
pub fn send_and_warn(&self, message: TailchatSendingMessagePy) -> bool {
warn!("{}", message.message.content);
self.send_message(message)
}
pub fn debug(&self, content: String) {
debug!("{}", content);
}
pub fn info(&self, content: String) {
info!("{}", content);
}
pub fn warn(&self, content: String) {
warn!("{}", content);
}
}
#[pymethods]
impl TailchatReciveMessagePy {
#[getter]
pub fn get_is_reply(&self) -> bool { self.message.is_reply() }
#[getter]
pub fn get_msg_id(&self) -> MessageId { self.message.msg_id.clone() }
#[getter]
pub fn get_content(&self) -> String { self.message.content.clone() }
#[getter]
pub fn get_sender_id(&self) -> UserId { self.message.sender_id.clone() }
#[getter]
pub fn get_group_id(&self) -> GroupId { self.message.group_id.clone() }
#[getter]
pub fn get_converse_id(&self) -> ConverseId { self.message.converse_id.clone() }
/// 作为回复
pub fn as_reply(&self) -> TailchatSendingMessagePy {
TailchatSendingMessagePy {
message: self.message.as_reply(),
}
}
pub fn reply_with(&self, content: String) -> TailchatSendingMessagePy {
TailchatSendingMessagePy {
message: self.message.reply_with(content),
}
}
}
#[pymethods]
impl TailchatSendingMessagePy {
#[getter]
pub fn get_content(&self) -> String { self.message.content.clone() }
#[setter]
pub fn set_content(&mut self, content: String) { self.message.content = content; }
#[getter]
pub fn get_converse_id(&self) -> ConverseId { self.message.converse_id.clone() }
#[getter]
pub fn get_group_id(&self) -> GroupId { self.message.group_id.clone() }
pub fn with_content(&mut self, content: String) -> Self {
self.message.content = content;
self.clone()
}
}

View File

@ -1 +1,22 @@
use crate::data_struct::tailchat::messages::SendingMessage;
// use crate::data_struct::tailchat::{ConverseId, GroupId, MessageId, UserId};
use rust_socketio::asynchronous::Client;
use colored::Colorize;
use serde_json::Value;
use tracing::{debug, info, span, warn, Level};
pub async fn send_message(client: &Client, message: &SendingMessage) -> bool {
let value: Value = message.as_value();
match client.emit("chat.message.sendMessage", value).await {
Ok(_) => {
debug!("send_message {}", format!("{:#?}", message).cyan());
true
}
Err(e) => {
warn!("send_message faild:{}", format!("{:#?}", e).red());
false
}
}
}

View File

@ -56,24 +56,19 @@ pub async fn any_event(event: Event, payload: Payload, _client: Client) {
}
}
pub async fn on_message(payload: Payload, _client: Client) {
match payload {
Payload::Text(values) => {
if let Some(value) = values.first() {
let message: ReciveMessage = serde_json::from_value(value.clone()).unwrap();
info!("收到消息 {:?}", message);
}
pub async fn on_message(payload: Payload, client: Client) {
if let Payload::Text(values) = payload {
if let Some(value) = values.first() {
let message: ReciveMessage = serde_json::from_value(value.clone()).unwrap();
info!("收到消息 {:?}", message);
crate::py::call::tailchat_new_message_py(&message, &client).await;
}
_ => (),
}
}
pub async fn on_msg_delete(payload: Payload, _client: Client) {
match payload {
Payload::Text(values) => {
if let Some(value) = values.first() {
info!("删除消息 {}", value.to_string().red());
}
if let Payload::Text(values) = payload {
if let Some(value) = values.first() {
info!("删除消息 {}", value.to_string().red());
}
_ => (),
}
}