This commit is contained in:
shenjack 2024-08-17 21:49:16 +08:00
parent 4da93570c9
commit d12773981d
Signed by: shenjack
GPG Key ID: 7B1134A979775551
9 changed files with 82 additions and 65 deletions

9
Cargo.lock generated
View File

@ -675,6 +675,7 @@ dependencies = [
"rust_socketio", "rust_socketio",
"serde", "serde",
"serde_json", "serde_json",
"thiserror",
"tokio", "tokio",
"toml", "toml",
"tracing", "tracing",
@ -1557,18 +1558,18 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.61" version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.61" version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View File

@ -50,3 +50,4 @@ anyhow = { version = "1.0", features = ["backtrace"] }
# log # log
tracing = "0.1.40" tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18", features = ["time"] } tracing-subscriber = { version = "0.3.18", features = ["time"] }
thiserror = "1.0.63"

View File

@ -1,3 +1,5 @@
// use thiserror::Error;
pub type ClientResult<T, E> = Result<T, E>; pub type ClientResult<T, E> = Result<T, E>;
#[derive(Debug)] #[derive(Debug)]

View File

@ -10,7 +10,8 @@ use crate::config::IcaConfig;
use crate::error::{ClientResult, IcaError}; use crate::error::{ClientResult, IcaError};
use crate::StopGetter; use crate::StopGetter;
const ICA_PROTOCOL_VERSION: &str = "2.12.12"; /// icalingua 客户端的兼容版本号
pub const ICA_PROTOCOL_VERSION: &str = "2.12.12";
pub async fn start_ica(config: &IcaConfig, stop_reciver: StopGetter) -> ClientResult<(), IcaError> { pub async fn start_ica(config: &IcaConfig, stop_reciver: StopGetter) -> ClientResult<(), IcaError> {
let span = span!(Level::INFO, "Icalingua Client"); let span = span!(Level::INFO, "Icalingua Client");
@ -80,7 +81,7 @@ pub async fn start_ica(config: &IcaConfig, stop_reciver: StopGetter) -> ClientRe
event!(Level::INFO, "socketio client stopped"); event!(Level::INFO, "socketio client stopped");
Ok(()) Ok(())
} else { } else {
event!(Level::ERROR, "socketio client stopped with error: {:?}", inner_e); event!(Level::ERROR, "socketio 客户端出现了 Error: {:?}", inner_e);
Err(IcaError::SocketIoError( Err(IcaError::SocketIoError(
rust_socketio::Error::IncompleteResponseFromEngineIo(inner_e), rust_socketio::Error::IncompleteResponseFromEngineIo(inner_e),
)) ))

View File

@ -7,7 +7,7 @@ use ed25519_dalek::{Signature, Signer, SigningKey};
use rust_socketio::asynchronous::Client; use rust_socketio::asynchronous::Client;
use rust_socketio::Payload; use rust_socketio::Payload;
use serde_json::Value; use serde_json::Value;
use tracing::{debug, info, span, warn, event, Level}; use tracing::{debug, event, span, warn, Level};
/// "安全" 的 发送一条消息 /// "安全" 的 发送一条消息
pub async fn send_message(client: &Client, message: &SendMessage) -> bool { pub async fn send_message(client: &Client, message: &SendMessage) -> bool {
@ -56,7 +56,12 @@ async fn inner_sign(payload: Payload, client: Client) -> ClientResult<(), IcaErr
let (auth_key, version) = (&require_data[0], &require_data[1]); let (auth_key, version) = (&require_data[0], &require_data[1]);
event!(Level::INFO, "服务器发过来的待签名key: {:?}, 服务端版本号: {:?}", auth_key, version); event!(
Level::INFO,
"服务器发过来的待签名key: {:?}, 服务端版本号: {:?}",
auth_key,
version
);
// 判定和自己的兼容版本号是否 一致 // 判定和自己的兼容版本号是否 一致
let server_protocol_version = version let server_protocol_version = version
.get("protocolVersion") .get("protocolVersion")

View File

@ -25,8 +25,6 @@ pub async fn get_online_data(payload: Payload, _client: Client) {
pub async fn add_message(payload: Payload, client: Client) { pub async fn add_message(payload: Payload, client: Client) {
if let Payload::Text(values) = payload { if let Payload::Text(values) = payload {
if let Some(value) = values.first() { if let Some(value) = values.first() {
let span = span!(Level::INFO, "ica new_msg");
let _enter = span.enter();
let message: NewMessage = serde_json::from_value(value.clone()).unwrap(); let message: NewMessage = serde_json::from_value(value.clone()).unwrap();
// 检测是否在过滤列表内 // 检测是否在过滤列表内
if MainStatus::global_config().ica().filter_list.contains(&message.msg.sender_id) { if MainStatus::global_config().ica().filter_list.contains(&message.msg.sender_id) {
@ -184,7 +182,7 @@ pub async fn connect_callback(payload: Payload, _client: Client) {
Some(msg) => { Some(msg) => {
event!(Level::INFO, "{}{}", "未知消息".yellow(), msg); event!(Level::INFO, "{}{}", "未知消息".yellow(), msg);
} }
None => (), _ => (),
} }
} }
} }

View File

@ -135,7 +135,7 @@ pub async fn ica_new_message_py(message: &ica::messages::NewMessage, client: &Cl
// 验证插件是否改变 // 验证插件是否改变
verify_plugins(); verify_plugins();
let plugins = PyStatus::get_files(); let plugins = PyStatus::get_map();
for (path, plugin) in plugins.iter().filter(|(_, plugin)| plugin.enabled) { for (path, plugin) in plugins.iter().filter(|(_, plugin)| plugin.enabled) {
let msg = class::ica::NewMessagePy::new(message); let msg = class::ica::NewMessagePy::new(message);
let client = class::ica::IcaClientPy::new(client); let client = class::ica::IcaClientPy::new(client);
@ -148,7 +148,7 @@ pub async fn ica_new_message_py(message: &ica::messages::NewMessage, client: &Cl
pub async fn ica_delete_message_py(msg_id: ica::MessageId, client: &Client) { pub async fn ica_delete_message_py(msg_id: ica::MessageId, client: &Client) {
verify_plugins(); verify_plugins();
let plugins = PyStatus::get_files(); let plugins = PyStatus::get_map();
for (path, plugin) in plugins.iter().filter(|(_, plugin)| plugin.enabled) { for (path, plugin) in plugins.iter().filter(|(_, plugin)| plugin.enabled) {
let msg_id = msg_id.clone(); let msg_id = msg_id.clone();
let client = class::ica::IcaClientPy::new(client); let client = class::ica::IcaClientPy::new(client);
@ -163,7 +163,7 @@ pub async fn tailchat_new_message_py(
) { ) {
verify_plugins(); verify_plugins();
let plugins = PyStatus::get_files(); let plugins = PyStatus::get_map();
for (path, plugin) in plugins.iter().filter(|(_, plugin)| plugin.enabled) { for (path, plugin) in plugins.iter().filter(|(_, plugin)| plugin.enabled) {
let msg = class::tailchat::TailchatReceiveMessagePy::from_recive_message(message); let msg = class::tailchat::TailchatReceiveMessagePy::from_recive_message(message);
let client = class::tailchat::TailchatClientPy::new(client); let client = class::tailchat::TailchatClientPy::new(client);

View File

@ -0,0 +1 @@

View File

@ -2,6 +2,7 @@ pub mod call;
pub mod class; pub mod class;
pub mod config; pub mod config;
use std::fmt::Display;
use std::path::Path; use std::path::Path;
use std::time::SystemTime; use std::time::SystemTime;
use std::{collections::HashMap, path::PathBuf}; use std::{collections::HashMap, path::PathBuf};
@ -9,18 +10,65 @@ use std::{collections::HashMap, path::PathBuf};
use colored::Colorize; use colored::Colorize;
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::types::PyTuple; use pyo3::types::PyTuple;
use tracing::{debug, info, span, warn, Level}; use tracing::{debug, event, info, span, warn, Level};
use crate::MainStatus; use crate::MainStatus;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct PyStatus { pub struct PyStatus {
pub files: Option<HashMap<PathBuf, PyPlugin>>, pub files: Option<PyPlugins>,
} }
pub type PyPluginData = HashMap<PathBuf, PyPlugin>; pub type PyPlugins = HashMap<PathBuf, PyPlugin>;
pub type RawPyPlugin = (PathBuf, Option<SystemTime>, String); pub type RawPyPlugin = (PathBuf, Option<SystemTime>, String);
impl PyStatus {
pub fn init() {
unsafe {
if PYSTATUS.files.is_none() {
PYSTATUS.files = Some(HashMap::new());
}
}
}
pub fn add_file(path: PathBuf, plugin: PyPlugin) { Self::get_mut_map().insert(path, plugin); }
pub fn verify_file(path: &PathBuf) -> bool {
Self::get_map().get(path).map_or(false, |plugin| plugin.verifiy())
}
fn get_map() -> &'static PyPlugins {
unsafe {
match PYSTATUS.files.as_ref() {
Some(files) => files,
None => {
Self::init();
PYSTATUS.files.as_ref().unwrap()
}
}
}
}
fn get_mut_map() -> &'static mut PyPlugins {
unsafe {
match PYSTATUS.files.as_mut() {
Some(files) => files,
None => {
Self::init();
PYSTATUS.files.as_mut().unwrap()
}
}
}
}
pub fn list_plugins() -> Vec<PathBuf> { Self::get_map().keys().cloned().collect() }
pub fn display() -> String {
let map = Self::get_map();
format!("Python 插件 {{ {} }}", (",".join(map.keys().map(|x| x.to_string()))))
}
}
pub fn get_py_err_traceback(py_err: &PyErr) -> String { pub fn get_py_err_traceback(py_err: &PyErr) -> String {
Python::with_gil(|py| match py_err.traceback_bound(py) { Python::with_gil(|py| match py_err.traceback_bound(py) {
Some(traceback) => match traceback.format() { Some(traceback) => match traceback.format() {
@ -218,56 +266,15 @@ impl TryFrom<RawPyPlugin> for PyPlugin {
} }
} }
impl PyStatus {
pub fn get_files() -> &'static PyPluginData {
unsafe {
match PYSTATUS.files.as_ref() {
Some(files) => files,
None => {
PYSTATUS.files = Some(HashMap::new());
PYSTATUS.files.as_ref().unwrap()
}
}
}
}
pub fn add_file(path: PathBuf, plugin: PyPlugin) {
unsafe {
match PYSTATUS.files.as_mut() {
Some(files) => {
files.insert(path, plugin);
}
None => {
let mut files: PyPluginData = HashMap::new();
files.insert(path, plugin);
PYSTATUS.files = Some(files);
}
}
}
}
pub fn verify_file(path: &PathBuf) -> bool {
unsafe {
match PYSTATUS.files.as_ref() {
Some(files) => match files.get(path) {
Some(plugin) => plugin.verifiy(),
None => false,
},
None => false,
}
}
}
}
pub static mut PYSTATUS: PyStatus = PyStatus { files: None }; pub static mut PYSTATUS: PyStatus = PyStatus { files: None };
pub fn load_py_plugins(path: &PathBuf) { pub fn load_py_plugins(path: &PathBuf) {
if path.exists() { if path.exists() {
info!("finding plugins in: {:?}", path); event!(Level::INFO, "finding plugins in: {:?}", path);
// 搜索所有的 py 文件 和 文件夹单层下面的 py 文件 // 搜索所有的 py 文件 和 文件夹单层下面的 py 文件
match path.read_dir() { match path.read_dir() {
Err(e) => { Err(e) => {
warn!("failed to read plugin path: {:?}", e); event!(Level::WARN, "failed to read plugin path: {:?}", e);
} }
Ok(dir) => { Ok(dir) => {
for entry in dir { for entry in dir {
@ -284,12 +291,13 @@ pub fn load_py_plugins(path: &PathBuf) {
} }
} }
} else { } else {
warn!("plugin path not exists: {:?}", path); event!(Level::WARN, "插件加载目录不存在: {:?}", path);
} }
info!( event!(
Level::INFO,
"python 插件目录: {:?} 加载完成, 加载到 {} 个插件", "python 插件目录: {:?} 加载完成, 加载到 {} 个插件",
path, path,
PyStatus::get_files().len() PyStatus::get_map().len()
); );
} }
@ -325,12 +333,12 @@ pub fn init_py() {
let global_config = MainStatus::global_config().py(); let global_config = MainStatus::global_config().py();
debug!("initing python threads"); event!(Level::INFO, "正在初始化 python");
pyo3::prepare_freethreaded_python(); pyo3::prepare_freethreaded_python();
let plugin_path = PathBuf::from(global_config.plugin_path); let plugin_path = PathBuf::from(global_config.plugin_path);
load_py_plugins(&plugin_path); load_py_plugins(&plugin_path);
debug!("python 插件列表: {:#?}", PyStatus::get_files()); event!(Level::DEBUG, "python 插件列表: {}", PyStatus::display());
info!("python inited") info!("python inited")
} }