继续重构

This commit is contained in:
shenjack 2024-02-20 14:47:53 +08:00
parent 06ee237bf5
commit e6df56b04d
Signed by: shenjack
GPG Key ID: 7B1134A979775551
8 changed files with 393 additions and 98 deletions

View File

@ -1,10 +1,40 @@
use crate::config::IcaConfig; use crate::config::IcaConfig;
use crate::data_struct::{all_rooms::Room, online_data::OnlineData};
use ed25519_dalek::{Signature, Signer, SigningKey}; use ed25519_dalek::{Signature, Signer, SigningKey};
use rust_socketio::{Payload, RawClient}; use rust_socketio::{Payload, RawClient};
use serde_json::Value; use serde_json::Value;
use tracing::debug; use tracing::debug;
#[derive(Debug, Clone)]
pub struct IcalinguaStatus {
pub login: bool,
pub online_data: Option<OnlineData>,
pub rooms: Option<Vec<Room>>,
}
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<Room>) {
self.rooms = Some(rooms);
}
pub fn update_login_status(&mut self, login: bool) {
self.login = login;
}
}
pub struct IcalinguaSinger { pub struct IcalinguaSinger {
pub host: String, pub host: String,
pub private_key: SigningKey, pub private_key: SigningKey,

View File

@ -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,
}

View File

@ -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<i32>,
pub name: Option<String>,
pub fid: Option<String>,
}
impl MessageFile {
pub fn get_name(&self) -> Option<&String> {
self.name.as_ref()
}
pub fn get_fid(&self) -> Option<&String> {
self.fid.as_ref()
}
}

View File

@ -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<String>,
pub timestamp: Option<String>,
pub username: Option<String>,
#[serde(rename = "userId")]
pub user_id: Option<i64>,
}
#[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<MessageFile>,
/// 回复的消息
pub reply: Option<ReplyedMessage>,
/// 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<i64>,
/// 是否已被隐藏
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<MessageFile> = message["files"]
.as_array()
.unwrap_or(&Vec::new())
.iter()
.map(|value| serde_json::from_value(value.clone()).unwrap())
.collect();
// 回复的消息
let reply: Option<ReplyedMessage> = 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());
}
}

View File

@ -1,2 +1,9 @@
pub mod new_message; pub mod files;
pub mod messages;
pub mod all_rooms;
pub mod online_data; pub mod online_data;
pub type RoomId = i64;
pub type UserId = i64;
pub type MessageId = String;

View File

@ -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<Self> {
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);
}
}

View File

@ -2,7 +2,7 @@ use colored::Colorize;
use rust_socketio::{Event, Payload, RawClient}; use rust_socketio::{Event, Payload, RawClient};
use tracing::{info, warn}; 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::data_struct::online_data::OnlineData;
use crate::py; use crate::py;
@ -14,6 +14,9 @@ pub fn get_online_data(payload: Payload, _client: RawClient) {
"update_online_data {}", "update_online_data {}",
format!("{:#?}", online_data).cyan() 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", "requireAuth",
"onlineData", "onlineData",
"addMessage", "addMessage",
// "setAllRooms",
// 忽略的 // 忽略的
"notify", "notify",
"updateRoom", "updateRoom",

View File

@ -1,7 +1,7 @@
use std::time::Duration; use std::time::Duration;
use tracing::info;
use rust_socketio::ClientBuilder; use rust_socketio::ClientBuilder;
use tracing::info;
mod client; mod client;
mod config; mod config;
@ -9,7 +9,19 @@ mod data_struct;
mod events; mod events;
mod py; 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 // 从命令行获取 host 和 key
// 从命令行获取配置文件路径 // 从命令行获取配置文件路径
let ica_config = config::IcaConfig::new_from_cli(); let ica_config = config::IcaConfig::new_from_cli();
@ -35,13 +47,4 @@ fn ws_main() {
std::io::stdin().read_line(&mut input).unwrap(); std::io::stdin().read_line(&mut input).unwrap();
socket.disconnect().expect("Disconnect failed"); socket.disconnect().expect("Disconnect failed");
info!("Disconnected"); info!("Disconnected");
}
fn main() {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::DEBUG)
.init();
py::init_py();
ws_main();
} }