From e6df56b04da1d43f400961880770aa1f411092c6 Mon Sep 17 00:00:00 2001 From: shenjack <3695888@qq.com> Date: Tue, 20 Feb 2024 14:47:53 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=A7=E7=BB=AD=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ica-rs/src/client.rs | 30 +++ ica-rs/src/data_struct/all_rooms.rs | 36 ++++ ica-rs/src/data_struct/files.rs | 28 +++ ica-rs/src/data_struct/messages.rs | 272 ++++++++++++++++++++++++++ ica-rs/src/data_struct/mod.rs | 9 +- ica-rs/src/data_struct/new_message.rs | 85 -------- ica-rs/src/events.rs | 6 +- ica-rs/src/main.rs | 25 +-- 8 files changed, 393 insertions(+), 98 deletions(-) create mode 100644 ica-rs/src/data_struct/all_rooms.rs create mode 100644 ica-rs/src/data_struct/files.rs create mode 100644 ica-rs/src/data_struct/messages.rs delete mode 100644 ica-rs/src/data_struct/new_message.rs diff --git a/ica-rs/src/client.rs b/ica-rs/src/client.rs index b46fe10..c8d2908 100644 --- a/ica-rs/src/client.rs +++ b/ica-rs/src/client.rs @@ -1,10 +1,40 @@ use crate::config::IcaConfig; +use crate::data_struct::{all_rooms::Room, online_data::OnlineData}; use ed25519_dalek::{Signature, Signer, SigningKey}; use rust_socketio::{Payload, RawClient}; use serde_json::Value; use tracing::debug; +#[derive(Debug, Clone)] +pub struct IcalinguaStatus { + pub login: bool, + pub online_data: Option, + pub rooms: Option>, +} + +impl IcalinguaStatus { + pub fn new() -> Self { + Self { + login: false, + online_data: None, + rooms: None, + } + } + + pub fn update_online_data(&mut self, online_data: OnlineData) { + self.online_data = Some(online_data); + } + + pub fn update_rooms(&mut self, rooms: Vec) { + self.rooms = Some(rooms); + } + + pub fn update_login_status(&mut self, login: bool) { + self.login = login; + } +} + pub struct IcalinguaSinger { pub host: String, pub private_key: SigningKey, diff --git a/ica-rs/src/data_struct/all_rooms.rs b/ica-rs/src/data_struct/all_rooms.rs new file mode 100644 index 0000000..90a00c5 --- /dev/null +++ b/ica-rs/src/data_struct/all_rooms.rs @@ -0,0 +1,36 @@ +use crate::data_struct::messages::{At, LastMessage}; +use crate::data_struct::RoomId; + +use serde_json::Value as JsonValue; + +/// export default interface Room { +/// roomId: number +/// roomName: string +/// index: number +/// unreadCount: number +/// priority: 1 | 2 | 3 | 4 | 5 +/// utime: number +/// users: +/// | [{ _id: 1; username: '1' }, { _id: 2; username: '2' }] +/// | [{ _id: 1; username: '1' }, { _id: 2; username: '2' }, { _id: 3; username: '3' }] +/// at?: boolean | 'all' +/// lastMessage: LastMessage +/// autoDownload?: boolean +/// downloadPath?: string +/// } +#[derive(Debug, Clone)] +pub struct Room { + pub room_id: RoomId, + pub room_name: String, + pub index: i64, + pub unread_count: u64, + pub priority: u8, + pub utime: i64, + /// 我严重怀疑是脱裤子放屁 + /// 历史遗留啊,那没事了() + pub users: JsonValue, + pub at: At, + pub last_message: LastMessage, + pub auto_donwload: String, + pub download_path: String, +} diff --git a/ica-rs/src/data_struct/files.rs b/ica-rs/src/data_struct/files.rs new file mode 100644 index 0000000..97a807e --- /dev/null +++ b/ica-rs/src/data_struct/files.rs @@ -0,0 +1,28 @@ +use serde::{Deserialize, Serialize}; + +/*interface MessageFile { + type: string + url: string + size?: number + name?: string + fid?: string +} + */ +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct MessageFile { + #[serde(rename = "type")] + pub file_type: String, + pub url: String, + pub size: Option, + pub name: Option, + pub fid: Option, +} + +impl MessageFile { + pub fn get_name(&self) -> Option<&String> { + self.name.as_ref() + } + pub fn get_fid(&self) -> Option<&String> { + self.fid.as_ref() + } +} diff --git a/ica-rs/src/data_struct/messages.rs b/ica-rs/src/data_struct/messages.rs new file mode 100644 index 0000000..bb1c168 --- /dev/null +++ b/ica-rs/src/data_struct/messages.rs @@ -0,0 +1,272 @@ +use crate::data_struct::files::MessageFile; +use crate::data_struct::{MessageId, RoomId, UserId}; + +use chrono::NaiveDateTime; +use serde::{Deserialize, Serialize}; +use serde_json::Value as JsonValue; +use tracing::warn; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum At { + All, + Bool(bool), + None, +} + +impl At { + /// new_from_json(&message["at"]) + pub fn new_from_json(json: &JsonValue) -> Self { + match json { + JsonValue::Bool(b) => Self::Bool(*b), + #[allow(non_snake_case)] + JsonValue::String(_I_dont_Care) => Self::All, + _ => Self::None, + } + } +} + +/*export default interface LastMessage { + content?: string + timestamp?: string + username?: string + userId?: number +} + */ +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct LastMessage { + pub content: Option, + pub timestamp: Option, + pub username: Option, + #[serde(rename = "userId")] + pub user_id: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct ReplyedMessage { + #[serde(rename = "_id")] + pub msg_id: String, + pub content: String, + pub files: JsonValue, + #[serde(rename = "username")] + pub sender_name: String, +} + +/// {"message": {"_id":"idddddd","anonymousId":null,"anonymousflag":null,"bubble_id":0,"content":"test","date":"2024/02/18","files":[],"role":"admin","senderId":123456,"subid":1,"time":1708267062000_i64,"timestamp":"22:37:42","title":"索引管理员","username":"shenjack"},"roomId":-123456} +#[derive(Debug, Clone)] +pub struct NewMessage { + /// 房间 id + pub room_id: RoomId, + /// 消息 id + pub msg_id: MessageId, + /// 发送者 id + pub sender_id: UserId, + /// 发送者名字 + pub sender_name: String, + /// 消息内容 + pub content: String, + /// xml / json 内容 + pub code: JsonValue, + /// 消息时间 + pub time: NaiveDateTime, + /// 身份 + pub role: String, + /// 文件 + pub files: Vec, + /// 回复的消息 + pub reply: Option, + /// At + pub at: At, + /// 是否已撤回 + pub deleted: bool, + /// 是否是系统消息 + pub system: bool, + /// mirai? + pub mirai: JsonValue, + /// reveal ? + pub reveal: bool, + /// flash + pub flash: bool, + /// "群主授予的头衔" + pub title: String, + /// anonymous id + pub anonymous_id: Option, + /// 是否已被隐藏 + pub hide: bool, + /// 气泡 id + pub bubble_id: i64, + /// 子? id + pub subid: i64, + /// 头像 img? + pub head_img: JsonValue, + /// 原始消息 (准确来说是 json["message"]) + pub raw_msg: JsonValue, +} + +impl NewMessage { + /// export default interface Message { + /// _id: string | number + /// senderId?: number + /// username: string + /// content: string + /// code?: string + /// timestamp?: string + /// date?: string + /// role?: string + /// file?: MessageFile + /// files: MessageFile[] + /// time?: number + /// replyMessage?: Message + /// at?: boolean | 'all' + /// deleted?: boolean + /// system?: boolean + /// mirai?: MessageMirai + /// reveal?: boolean + /// flash?: boolean + /// title?: string + /// anonymousId?: number + /// anonymousflag?: string + /// hide?: boolean + /// bubble_id?: number + /// subid?: number + /// head_img?: string + /// } + pub fn new_from_json(json: &JsonValue) -> Self { + // room id 还是必定有的 + let room_id = json["roomId"].as_i64().unwrap(); + // message 本体也是 + let message = json.get("message").unwrap(); + // 消息 id + let msg_id = message["_id"].as_str().unwrap(); + // 发送者 id (Optional) + let sender_id = message["senderId"].as_i64().unwrap_or(-1); + // 发送者名字 必有 + let sender_name = message["username"].as_str().unwrap(); + // 消息内容 + let content = message["content"].as_str().unwrap(); + // xml / json 内容 + let code = message["code"].clone(); + // 消息时间 (怎么这个也是可选啊(恼)) + // 没有就取当前时间 + let current = chrono::Utc::now().naive_utc(); + let time = message["time"] + .as_i64() + .map(|t| NaiveDateTime::from_timestamp_micros(t).unwrap_or(current)) + .unwrap_or(current); + // 身份 + let role = message["role"].as_str().unwrap(); + // 文件 + let files: Vec = message["files"] + .as_array() + .unwrap_or(&Vec::new()) + .iter() + .map(|value| serde_json::from_value(value.clone()).unwrap()) + .collect(); + // 回复的消息 + let reply: Option = message + .get("replyMessage") + .map(|value| serde_json::from_value(value.clone()).unwrap()); + // At + let at = At::new_from_json(&message["at"]); + // 是否已撤回 + let deleted = message["deleted"].as_bool().unwrap_or(false); + // 是否是系统消息 + let system = message["system"].as_bool().unwrap_or(false); + // mirai + let mirai = message["mirai"].clone(); + // reveal + let reveal = message["reveal"].as_bool().unwrap_or(false); + // flash + let flash = message["flash"].as_bool().unwrap_or(false); + // "群主授予的头衔" + let title = message["title"].as_str().unwrap(); + // anonymous id + let anonymous_id = message["anonymousId"].as_i64(); + // 是否已被隐藏 + let hide = message["hide"].as_bool().unwrap_or(false); + // 气泡 id + let bubble_id = message["bubble_id"].as_i64().unwrap_or(1); + // 子? id + let subid = message["subid"].as_i64().unwrap_or(1); + // 头像 img? + let head_img = message["head_img"].clone(); + // 原始消息 + let raw_msg = json["message"].clone(); + Self { + room_id, + msg_id: msg_id.to_string(), + sender_id, + sender_name: sender_name.to_string(), + content: content.to_string(), + code, + time, + role: role.to_string(), + files, + reply, + at, + deleted, + system, + mirai, + reveal, + flash, + title: title.to_string(), + anonymous_id, + hide, + bubble_id, + subid, + head_img, + raw_msg, + } + } + + pub fn get_reply(&self) -> Option<&ReplyedMessage> { + self.reply.as_ref() + } + + pub fn get_reply_mut(&mut self) -> Option<&mut ReplyedMessage> { + self.reply.as_mut() + } +} + +#[cfg(test)] +mod test { + use serde_json::json; + + use super::*; + + #[test] + fn test_new_from_json() { + let value = json!({"message": {"_id":"idddddd","anonymousId":null,"anonymousflag":null,"bubble_id":0,"content":"test","date":"2024/02/18","files":[],"role":"admin","senderId":123456,"subid":1,"time":1708267062000_i64,"timestamp":"22:37:42","title":"索引管理员","username":"shenjack"},"roomId":-123456}); + let new_message = NewMessage::new_from_json(&value); + assert_eq!(new_message.sender_id, 123456); + assert_eq!(new_message.room_id, -123456); + assert_eq!(new_message.sender_name, "shenjack"); + assert_eq!(new_message.msg_id, "idddddd"); + assert_eq!(new_message.role, "admin"); + assert_eq!(new_message.title, "索引管理员"); + assert_eq!(new_message.content, "test"); + assert_eq!(new_message.bubble_id, 0); + assert!(new_message.reply.is_none()); + assert_eq!(new_message.raw_msg, value["message"]); + assert_eq!( + new_message.time, + NaiveDateTime::from_timestamp_micros(1708267062000_i64).unwrap() + ); + assert_eq!(new_message.subid, 1); + } + + #[test] + fn test_parse_reply() { + let value = json!({"message": {"_id":"idddddd","anonymousId":null,"anonymousflag":null,"bubble_id":0,"content":"test","date":"2024/02/18","files":[],"role":"admin","senderId":123456,"subid":1,"time":1708267062000_i64,"timestamp":"22:37:42","title":"索引管理员","username":"shenjack", "replyMessage": {"content": "test", "username": "jackyuanjie", "files": [], "_id": "adwadaw"}},"roomId":-123456}); + let new_message = NewMessage::new_from_json(&value); + assert_eq!(new_message.get_reply().unwrap().sender_name, "jackyuanjie"); + assert_eq!(new_message.get_reply().unwrap().content, "test"); + assert_eq!(new_message.get_reply().unwrap().msg_id, "adwadaw"); + assert!(new_message + .get_reply() + .unwrap() + .files + .as_array() + .unwrap() + .is_empty()); + } +} diff --git a/ica-rs/src/data_struct/mod.rs b/ica-rs/src/data_struct/mod.rs index b94a7da..c9916fb 100644 --- a/ica-rs/src/data_struct/mod.rs +++ b/ica-rs/src/data_struct/mod.rs @@ -1,2 +1,9 @@ -pub mod new_message; +pub mod files; +pub mod messages; + +pub mod all_rooms; pub mod online_data; + +pub type RoomId = i64; +pub type UserId = i64; +pub type MessageId = String; diff --git a/ica-rs/src/data_struct/new_message.rs b/ica-rs/src/data_struct/new_message.rs deleted file mode 100644 index 13756c5..0000000 --- a/ica-rs/src/data_struct/new_message.rs +++ /dev/null @@ -1,85 +0,0 @@ -use chrono::NaiveDateTime; -use serde_json::Value as JsonValue; - -/// {"message": {"_id":"idddddd","anonymousId":null,"anonymousflag":null,"bubble_id":0,"content":"test","date":"2024/02/18","files":[],"role":"admin","senderId":123456,"subid":1,"time":1708267062000_i64,"timestamp":"22:37:42","title":"索引管理员","username":"shenjack"},"roomId":-123456} -#[derive(Debug, Clone)] -pub struct NewMessage { - /// 消息 id - pub msg_id: String, - /// 发送者 id - pub sender_id: i64, - /// 子? id - pub subid: i64, - /// 房间 id - pub room_id: i64, - /// 发送者名字 - pub sender_name: String, - /// 消息时间 - pub time: NaiveDateTime, - /// 身份 - pub role: String, - /// "群主授予的头衔" - pub title: String, - /// 消息内容 - pub content: String, - /// 气泡 id - pub bubble_id: i64, - /// 原始消息 - pub raw: JsonValue, -} - -impl NewMessage { - pub fn new_from_json(json: &JsonValue) -> Option { - let message = json["message"].as_object()?; - let room_id = json["roomId"].as_i64()?; - let sender_id = message.get("senderId")?.as_i64()?; - let subid = message.get("subid")?.as_i64()?; - let sender_name = message.get("username")?.as_str()?.to_string(); - let msg_id = message.get("_id")?.as_str()?.to_string(); - let time = message.get("time")?.as_i64()?; - let time = NaiveDateTime::from_timestamp_micros(time)?; - let role = message.get("role")?.as_str()?.to_string(); - let content = message.get("content")?.as_str()?.to_string(); - let title = message.get("title")?.as_str()?.to_string(); - let bubble_id = message.get("bubble_id")?.as_i64()?; - Some(Self { - msg_id, - sender_id, - subid, - room_id, - sender_name, - time, - role, - title, - content, - bubble_id, - raw: json.clone(), - }) - } -} - -#[cfg(test)] -mod test { - use serde_json::json; - - use super::*; - - #[test] - fn test_new_from_json() { - let value = json!({"message": {"_id":"idddddd","anonymousId":null,"anonymousflag":null,"bubble_id":0,"content":"test","date":"2024/02/18","files":[],"role":"admin","senderId":123456,"subid":1,"time":1708267062000_i64,"timestamp":"22:37:42","title":"索引管理员","username":"shenjack"},"roomId":-123456}); - let new_message = NewMessage::new_from_json(&value).unwrap(); - assert_eq!(new_message.sender_id, 123456); - assert_eq!(new_message.room_id, -123456); - assert_eq!(new_message.sender_name, "shenjack"); - assert_eq!(new_message.msg_id, "idddddd"); - assert_eq!(new_message.role, "admin"); - assert_eq!(new_message.content, "test"); - assert_eq!(new_message.title, "索引管理员"); - assert_eq!(new_message.raw, value); - assert_eq!( - new_message.time, - NaiveDateTime::from_timestamp_micros(1708267062000_i64).unwrap() - ); - assert_eq!(new_message.raw, value); - } -} diff --git a/ica-rs/src/events.rs b/ica-rs/src/events.rs index 67d9f17..3f8501e 100644 --- a/ica-rs/src/events.rs +++ b/ica-rs/src/events.rs @@ -2,7 +2,7 @@ use colored::Colorize; use rust_socketio::{Event, Payload, RawClient}; use tracing::{info, warn}; -use crate::data_struct::new_message::NewMessage; +use crate::data_struct::messages::NewMessage; use crate::data_struct::online_data::OnlineData; use crate::py; @@ -14,6 +14,9 @@ pub fn get_online_data(payload: Payload, _client: RawClient) { "update_online_data {}", format!("{:#?}", online_data).cyan() ); + unsafe { + crate::ClientStatus.update_online_data(online_data); + } } } } @@ -36,6 +39,7 @@ pub fn any_event(event: Event, payload: Payload, _client: RawClient) { "requireAuth", "onlineData", "addMessage", + // "setAllRooms", // 忽略的 "notify", "updateRoom", diff --git a/ica-rs/src/main.rs b/ica-rs/src/main.rs index d22acbe..521695c 100644 --- a/ica-rs/src/main.rs +++ b/ica-rs/src/main.rs @@ -1,7 +1,7 @@ use std::time::Duration; -use tracing::info; use rust_socketio::ClientBuilder; +use tracing::info; mod client; mod config; @@ -9,7 +9,19 @@ mod data_struct; mod events; mod py; -fn ws_main() { +#[allow(non_upper_case_globals)] +pub static mut ClientStatus: client::IcalinguaStatus = client::IcalinguaStatus { + login: false, + online_data: None, + rooms: None, +}; + +fn main() { + tracing_subscriber::fmt() + .with_max_level(tracing::Level::DEBUG) + .init(); + py::init_py(); + // 从命令行获取 host 和 key // 从命令行获取配置文件路径 let ica_config = config::IcaConfig::new_from_cli(); @@ -35,13 +47,4 @@ fn ws_main() { std::io::stdin().read_line(&mut input).unwrap(); socket.disconnect().expect("Disconnect failed"); info!("Disconnected"); - -} - -fn main() { - tracing_subscriber::fmt() - .with_max_level(tracing::Level::DEBUG) - .init(); - py::init_py(); - ws_main(); }