diff --git a/ica-rs/Cargo.toml b/ica-rs/Cargo.toml index 67763c0..3a88190 100644 --- a/ica-rs/Cargo.toml +++ b/ica-rs/Cargo.toml @@ -13,6 +13,7 @@ rust_socketio = "0.4.4" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +chrono = "0.4.34" toml = "0.8.10" colored = "2.1.0" diff --git a/ica-rs/src/client.rs b/ica-rs/src/client.rs index b52d648..b46fe10 100644 --- a/ica-rs/src/client.rs +++ b/ica-rs/src/client.rs @@ -3,6 +3,7 @@ use crate::config::IcaConfig; use ed25519_dalek::{Signature, Signer, SigningKey}; use rust_socketio::{Payload, RawClient}; use serde_json::Value; +use tracing::debug; pub struct IcalinguaSinger { pub host: String, @@ -40,7 +41,7 @@ impl IcalinguaSinger { .expect("Payload should be Json data"); let (auth_key, version) = (&require_data[0], &require_data[1]); - println!("auth_key: {:?}, version: {:?}", auth_key, version); + debug!("auth_key: {:?}, version: {:?}", auth_key, version); let auth_key = match &require_data.get(0) { Some(Value::String(auth_key)) => Some(auth_key), _ => None, diff --git a/ica-rs/src/config.rs b/ica-rs/src/config.rs index 7e55f88..3c80c67 100644 --- a/ica-rs/src/config.rs +++ b/ica-rs/src/config.rs @@ -4,6 +4,7 @@ use std::fs; use serde::Deserialize; use toml; +/// Icalingua bot 的配置 #[derive(Debug, Deserialize)] pub struct IcaConfig { /// icalingua 私钥 diff --git a/ica-rs/src/data_struct/mod.rs b/ica-rs/src/data_struct/mod.rs index b0aa8bd..b94a7da 100644 --- a/ica-rs/src/data_struct/mod.rs +++ b/ica-rs/src/data_struct/mod.rs @@ -1 +1,2 @@ +pub mod new_message; pub mod online_data; diff --git a/ica-rs/src/data_struct/new_message.rs b/ica-rs/src/data_struct/new_message.rs new file mode 100644 index 0000000..934b8b1 --- /dev/null +++ b/ica-rs/src/data_struct/new_message.rs @@ -0,0 +1,78 @@ +use chrono::NaiveDateTime; +use serde_json::Value as JsonValue; +use tracing::warn; + +/// {"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 sender_id: i64, + /// 房间 id + pub roomd_id: i64, + /// 发送者名字 + pub sender_name: String, + /// 消息 id + pub msg_id: String, + /// 消息时间 + pub time: NaiveDateTime, + /// 身份 + pub role: String, + /// 消息内容 + pub content: String, + /// "群主授予的头衔" + pub title: String, + /// 原始消息 + 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 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(); + Some(Self { + sender_id, + roomd_id: room_id, + sender_name, + msg_id, + time, + role, + content, + title, + 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.roomd_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 ec8d7d2..10a15e5 100644 --- a/ica-rs/src/events.rs +++ b/ica-rs/src/events.rs @@ -9,18 +9,34 @@ pub fn get_online_data(payload: Payload, _client: RawClient) { if let Payload::Text(values) = payload { if let Some(value) = values.first() { let online_data = OnlineData::new_from_json(value); - info!("update_online_data {}", format!("{:#?}", online_data).cyan()); + info!( + "update_online_data {}", + format!("{:#?}", online_data).cyan() + ); + } + } +} + +pub fn add_message(payload: Payload, _client: RawClient) { + if let Payload::Text(values) = payload { + if let Some(value) = values.first() { + info!("add_message {}", value); } } } pub fn any_event(event: Event, payload: Payload, _client: RawClient) { let handled = vec![ + // 真正处理过的 "authSucceed", "authFailed", "authRequired", "requireAuth", "onlineData", + "addMessage", + // 忽略的 + "notify", + "updateRoom", ]; match &event { Event::Custom(event_name) => { @@ -48,9 +64,6 @@ pub fn connect_callback(payload: Payload, _client: RawClient) { match payload { Payload::Text(values) => { if let Some(value) = values.first() { - // if let Some("authSucceed") = value.as_str() { - // println!("{}", "已经登录到 icalingua!".green()); - // } match value.as_str() { Some("authSucceed") => { py::run(); diff --git a/ica-rs/src/main.rs b/ica-rs/src/main.rs index 58b88cc..6d4ea6b 100644 --- a/ica-rs/src/main.rs +++ b/ica-rs/src/main.rs @@ -9,8 +9,6 @@ mod events; mod py; fn ws_main() { - py::init_py(); - // 从命令行获取 host 和 key // 从命令行获取配置文件路径 let ica_config = config::IcaConfig::new_from_cli(); @@ -19,12 +17,12 @@ fn ws_main() { let socket = ClientBuilder::new(ica_singer.host.clone()) .transport_type(rust_socketio::TransportType::Websocket) .on_any(events::any_event) - .on("onlineData", events::get_online_data) - .on("message", events::connect_callback) .on("requireAuth", move |a, b| ica_singer.sign_callback(a, b)) .on("authRequired", events::connect_callback) .on("authSucceed", events::connect_callback) .on("authFailed", events::connect_callback) + .on("onlineData", events::get_online_data) + .on("addMessage", events::add_message) .connect() .expect("Connection failed"); @@ -37,5 +35,6 @@ fn main() { tracing_subscriber::fmt() .with_max_level(tracing::Level::DEBUG) .init(); + py::init_py(); ws_main(); } diff --git a/ica-rs/src/py.rs b/ica-rs/src/py.rs index 25accd2..698fe93 100644 --- a/ica-rs/src/py.rs +++ b/ica-rs/src/py.rs @@ -1,6 +1,5 @@ -// use inline_python::{python, Context}; - use pyo3::{prelude::*, types::IntoPyDict}; +use tracing::{debug, info}; #[pyclass] #[pyo3(name = "BotStatus")] @@ -16,12 +15,7 @@ pub fn run() { } pub fn init_py() { + debug!("initing python threads"); pyo3::prepare_freethreaded_python(); + info!("python inited") } - -// pub fn run() { -// let con: Context = python! { -// print("Hello, world!"); -// }; - -// } diff --git a/plugins/yw.py b/plugins/yw.py deleted file mode 100644 index 6cd2b30..0000000 --- a/plugins/yw.py +++ /dev/null @@ -1,2 +0,0 @@ -def yw(): - return "🚧 TODO" diff --git a/router.py b/router.py index 54b13e6..c435575 100644 --- a/router.py +++ b/router.py @@ -6,7 +6,7 @@ from lib_not_dr.loggers import config from main import BOTCONFIG, _version_ from data_struct import SendMessage, ReplyMessage, NewMessage -from plugins import bmcl, yw, safe_eval +from plugins import bmcl, safe_eval logger = config.get_logger("router") @@ -23,8 +23,9 @@ async def route(data, sio): reply_msg = SendMessage(content="", room_id=room_id, reply_to=ReplyMessage(id=msg_id)) if content == "/bot": - message = reply_msg.to_content(f"icalingua bot pong v{_version_}") + message = reply_msg.to_content(f"icalingua bot-python pong v{_version_}") await sio.emit("sendMessage", message.to_json()) + elif content.startswith("=="): evals: str = content[2:] @@ -44,6 +45,7 @@ async def route(data, sio): await asyncio.sleep(random.random() * 2) await sio.emit("sendMessage", message.to_json()) + elif content == "!!jrrp": randomer = random.Random( f'{sender_id}-{data["message"]["date"]}-jrrp-{_version_}' @@ -53,10 +55,8 @@ async def route(data, sio): message = reply_msg.to_content(f"{sender_name} 今日人品为 {result}") await asyncio.sleep(0.5) await sio.emit("sendMessage", message.to_json()) + elif content == "/bmcl": await bmcl.bmcl(sio, reply_msg, msg) - # elif content == "/yw": - # message = yw.yw() - # await asyncio.sleep(random.random() * 2) - # await sio.emit("sendMessage", message.to_json()) +