From fcf88f0ebb651ed931f09b70d24c7780ce486761 Mon Sep 17 00:00:00 2001 From: shenjack <3695888@qq.com> Date: Mon, 6 Jan 2025 20:12:35 +0800 Subject: [PATCH] =?UTF-8?q?=E8=83=BD=E8=B7=91=E4=BA=86=E5=90=97=EF=BC=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ica-rs/src/ica.rs | 2 +- ica-rs/src/ica/client.rs | 6 ++-- ica-rs/src/ica/events.rs | 10 +++--- ica-rs/src/py/config.rs | 66 +++++++++++++++++++++++------------ ica-rs/src/py/mod.rs | 62 ++++++++++++++++++++------------ ica-rs/src/tailchat/events.rs | 10 +++--- news.md | 4 ++- 7 files changed, 97 insertions(+), 63 deletions(-) diff --git a/ica-rs/src/ica.rs b/ica-rs/src/ica.rs index 63d8d1c..21138de 100644 --- a/ica-rs/src/ica.rs +++ b/ica-rs/src/ica.rs @@ -13,7 +13,7 @@ use crate::error::{ClientResult, IcaError}; use crate::{version_str, StopGetter}; /// icalingua 客户端的兼容版本号 -pub const ICA_PROTOCOL_VERSION: &str = "2.12.24"; +pub const ICA_PROTOCOL_VERSION: &str = "2.12.26"; mod status { use crate::data_struct::ica::all_rooms::Room; diff --git a/ica-rs/src/ica/client.rs b/ica-rs/src/ica/client.rs index 8f30cfc..2ec1345 100644 --- a/ica-rs/src/ica/client.rs +++ b/ica-rs/src/ica/client.rs @@ -7,7 +7,7 @@ use colored::Colorize; use ed25519_dalek::{Signature, Signer, SigningKey}; use rust_socketio::asynchronous::Client; use rust_socketio::Payload; -use serde_json::{Value, json}; +use serde_json::{json, Value}; use tracing::{debug, event, span, warn, Level}; /// "安全" 的 发送一条消息 @@ -130,9 +130,7 @@ pub async fn send_room_sign_in(client: &Client, room_id: RoomId) -> bool { /// 向某个群/私聊的某个人发送戳一戳 pub async fn send_poke(client: &Client, room_id: RoomId, target: UserId) -> bool { let data = json!([room_id, target]); - match client.emit( - "sendGroupPoke", data - ).await { + match client.emit("sendGroupPoke", data).await { Ok(_) => { event!(Level::INFO, "已向 {} 的 {} 发送戳一戳", room_id, target); true diff --git a/ica-rs/src/ica/events.rs b/ica-rs/src/ica/events.rs index 2a733c8..28aac60 100644 --- a/ica-rs/src/ica/events.rs +++ b/ica-rs/src/ica/events.rs @@ -72,8 +72,7 @@ pub async fn add_message(payload: Payload, client: Client) { if message.content().starts_with(&format!("/bot-enable-{}", client_id)) { // 尝试获取后面的信息 if let Some((_, name)) = message.content().split_once(" ") { - let path_name = PathBuf::from(name); - match py::PyStatus::get().get_status(&path_name) { + match py::PyStatus::get().get_status(name) { None => { let reply = message.reply_with("未找到插件"); send_message(&client, &reply).await; @@ -83,7 +82,7 @@ pub async fn add_message(payload: Payload, client: Client) { send_message(&client, &reply).await; } Some(false) => { - py::PyStatus::get_mut().set_status(&path_name, true); + py::PyStatus::get_mut().set_status(name, true); let reply = message.reply_with("启用插件完成"); send_message(&client, &reply).await; } @@ -92,8 +91,7 @@ pub async fn add_message(payload: Payload, client: Client) { } else if message.content().starts_with(&format!("/bot-disable-{}", client_id)) { if let Some((_, name)) = message.content().split_once(" ") { - let path_name = PathBuf::from(name); - match py::PyStatus::get().get_status(&path_name) { + match py::PyStatus::get().get_status(name) { None => { let reply = message.reply_with("未找到插件"); send_message(&client, &reply).await; @@ -103,7 +101,7 @@ pub async fn add_message(payload: Payload, client: Client) { send_message(&client, &reply).await; } Some(true) => { - py::PyStatus::get_mut().set_status(&path_name, false); + py::PyStatus::get_mut().set_status(name, false); let reply = message.reply_with("禁用插件完成"); send_message(&client, &reply).await; } diff --git a/ica-rs/src/py/config.rs b/ica-rs/src/py/config.rs index c0b98fe..6e8ca5e 100644 --- a/ica-rs/src/py/config.rs +++ b/ica-rs/src/py/config.rs @@ -7,6 +7,7 @@ use toml_edit::{value, DocumentMut, Key, Table, TomlError, Value}; use tracing::{event, Level}; use crate::py::PyStatus; +use crate::MainStatus; /// ```toml /// # 这个文件是由 shenbot 自动生成的, 请 **谨慎** 修改 @@ -31,14 +32,37 @@ pub const DEFAULT_CONFIG: &str = r#" impl PluginConfigFile { pub fn from_str(data: &str) -> Result { - let data = DocumentMut::from_str(data)?; + let mut data = DocumentMut::from_str(data)?; + if data.get(CONFIG_KEY).is_none() { + event!(Level::WARN, "插件配置文件缺少 plugins 字段, 正在初始化"); + data.insert_formatted( + &Key::from_str(CONFIG_KEY).unwrap(), + toml_edit::Item::Table(Table::new()), + ); + } Ok(Self { data }) } + pub fn default_init() -> anyhow::Result { + let config_path = MainStatus::global_config().py().config_path.clone(); + let path = Path::new(&config_path); + Self::from_config_path(&path) + } + + pub fn reload_from_default(&mut self) { + let new_config = Self::default_init(); + if let Err(e) = new_config { + event!(Level::ERROR, "从配置文件重加载时遇到错误: {}", e); + return; + } + let new_config = new_config.unwrap(); + self.data = new_config.data; + } + pub fn from_config_path(path: &Path) -> anyhow::Result { let config_path = path.join(CONFIG_FILE_NAME); if !config_path.exists() { - event!(Level::INFO, "插件配置文件不存在, 正在创建"); + event!(Level::WARN, "插件配置文件不存在, 正在创建"); std::fs::write(&config_path, DEFAULT_CONFIG)?; Ok(Self::from_str(DEFAULT_CONFIG)?) } else { @@ -47,16 +71,6 @@ impl PluginConfigFile { } } - pub fn verify_and_init(&mut self) { - if self.data.get(CONFIG_KEY).is_none() { - event!(Level::INFO, "插件配置文件缺少 plugins 字段, 正在初始化"); - self.data.insert_formatted( - &Key::from_str(CONFIG_KEY).unwrap(), - toml_edit::Item::Table(Table::new()), - ); - } - } - fn get_table(&self) -> Option<&Table> { self.data.get(CONFIG_KEY).and_then(|item| item.as_table()) } @@ -67,11 +81,10 @@ impl PluginConfigFile { /// 获取插件状态 /// 默认为 true - pub fn get_status(&self, path: &Path) -> bool { - let path_str = path.to_str().unwrap(); + pub fn get_status(&self, plugin_id: &str) -> bool { if let Some(item) = self.data.get(CONFIG_KEY) { if let Some(table) = item.as_table() { - if let Some(item) = table.get(path_str) { + if let Some(item) = table.get(plugin_id) { if let Some(bool) = item.as_bool() { return bool; } @@ -100,7 +113,6 @@ impl PluginConfigFile { /// 设置插件状态 pub fn set_status(&mut self, path: &Path, status: bool) { - self.verify_and_init(); let path_str = path.to_str().unwrap(); let table = self.data.get_mut(CONFIG_KEY).unwrap().as_table_mut().unwrap(); if table.contains_key(path_str) { @@ -115,23 +127,31 @@ impl PluginConfigFile { } } - pub fn sync_status_from_config(&mut self) { + pub fn read_status_from_file(&mut self) { + self.reload_from_default(); + event!(Level::INFO, "同步插件状态"); let plugins = PyStatus::get_mut(); - self.verify_and_init(); plugins.files.iter_mut().for_each(|(path, status)| { - let config_status = self.get_status(path); - event!(Level::INFO, "插件状态: {:?} {} -> {}", path, status.enabled, config_status); + let plugin_id = status.get_id(); + let config_status = self.get_status(&plugin_id); + event!( + Level::INFO, + "插件状态: {}({:?}) {} -> {}", + status.get_id(), + path, + status.enabled, + config_status + ); status.enabled = config_status; }); } pub fn sync_status_to_config(&mut self) { let plugins = PyStatus::get(); - self.verify_and_init(); let table = self.data.get_mut(CONFIG_KEY).unwrap().as_table_mut().unwrap(); table.clear(); - plugins.files.iter().for_each(|(path, status)| { - table.insert(path.to_str().unwrap(), value(status.enabled)); + plugins.files.iter().for_each(|(_, status)| { + table.insert(&status.get_id(), value(status.enabled)); }); } diff --git a/ica-rs/src/py/mod.rs b/ica-rs/src/py/mod.rs index 8d2ff10..4eb474b 100644 --- a/ica-rs/src/py/mod.rs +++ b/ica-rs/src/py/mod.rs @@ -29,10 +29,8 @@ static mut PyPluginStatus: OnceLock = OnceLock::new(); impl PyStatus { pub fn init() { - let plugin_path = MainStatus::global_config().py().plugin_path.clone(); - let mut config = - config::PluginConfigFile::from_config_path(&PathBuf::from(plugin_path)).unwrap(); - config.verify_and_init(); + let config = + config::PluginConfigFile::default_init().expect("初始化 Python 插件配置文件失败"); let status = PyStatus { files: HashMap::new(), config, @@ -44,37 +42,40 @@ impl PyStatus { pub fn get_mut() -> &'static mut PyStatus { unsafe { PyPluginStatus.get_mut().unwrap() } } + /// 添加一个插件 pub fn add_file(&mut self, path: PathBuf, plugin: PyPlugin) { self.files.insert(path, plugin); } /// 删除一个插件 pub fn delete_file(&mut self, path: &PathBuf) -> Option { self.files.remove(path) } + pub fn get_status(&self, pluging_id: &str) -> Option { + self.files.iter().find_map(|(_, plugin)| { + if plugin.get_id() == pluging_id { + return Some(plugin.enabled); + } + None + }) + } + + pub fn set_status(&mut self, pluging_id: &str, status: bool) { + self.files.iter_mut().for_each(|(_, plugin)| { + if plugin.get_id() == pluging_id { + plugin.enabled = status; + } + }); + } + pub fn verify_file(&self, path: &PathBuf) -> bool { self.files.get(path).is_some_and(|plugin| plugin.verifiy()) } - /// 获取某个插件的状态 - /// 以 config 优先 - pub fn get_status(&self, path: &PathBuf) -> Option { - self.files.get(path).map(|plugin| plugin.enabled) - } - - pub fn sync_status(&mut self) { self.config.sync_status_from_config(); } - - pub fn set_status(&mut self, path: &Path, status: bool) { - self.config.set_status(path, status); - if let Some(plugin) = self.files.get_mut(path) { - plugin.enabled = status; - } - } - pub fn display() -> String { format!( "Python 插件 {{ {} }}", Self::get() .files .iter() - .map(|(k, v)| format!("{:?}-{}", k, v.enabled)) + .map(|(_, v)| v.to_string()) .collect::>() .join("\n") ) @@ -133,7 +134,7 @@ impl PyPlugin { Ok(plugin) => { self.py_module = plugin.py_module; self.changed_time = plugin.changed_time; - self.enabled = PyStatus::get().config.get_status(self.file_path.as_path()); + self.enabled = PyStatus::get().config.get_status(&self.get_id()); event!(Level::INFO, "更新 Python 插件文件 {:?} 完成", self.file_path); } Err(e) => { @@ -164,6 +165,14 @@ impl PyPlugin { } } } + + pub fn get_id(&self) -> String { plugin_path_as_id(&self.file_path) } +} + +impl ToString for PyPlugin { + fn to_string(&self) -> String { + format!("{}({:?})-{}", self.get_id(), self.file_path, self.enabled) + } } pub const CONFIG_DATA_NAME: &str = "CONFIG_DATA"; @@ -304,6 +313,15 @@ impl TryFrom for PyPlugin { } } +/// 插件路径转换为 id +pub fn plugin_path_as_id(path: &PathBuf) -> String { + path.file_name() + .unwrap_or_default() + .to_str() + .unwrap_or("decode-failed") + .to_string() +} + pub fn load_py_plugins(path: &PathBuf) { let plugins = PyStatus::get_mut(); if path.exists() { @@ -330,7 +348,7 @@ pub fn load_py_plugins(path: &PathBuf) { } else { event!(Level::WARN, "插件加载目录不存在: {:?}", path); } - plugins.config.sync_status_from_config(); + plugins.config.read_status_from_file(); event!( Level::INFO, "python 插件目录: {:?} 加载完成, 加载到 {} 个插件", diff --git a/ica-rs/src/tailchat/events.rs b/ica-rs/src/tailchat/events.rs index ff682b1..2138640 100644 --- a/ica-rs/src/tailchat/events.rs +++ b/ica-rs/src/tailchat/events.rs @@ -115,8 +115,7 @@ pub async fn on_message(payload: Payload, client: Client, _status: Arc { let reply = message.reply_with("未找到插件"); send_message(&client, &reply).await; @@ -126,7 +125,7 @@ pub async fn on_message(payload: Payload, client: Client, _status: Arc { - PyStatus::get_mut().set_status(&path_name, true); + PyStatus::get_mut().set_status(name, true); let reply = message.reply_with("启用插件完成"); send_message(&client, &reply).await; } @@ -134,8 +133,7 @@ pub async fn on_message(payload: Payload, client: Client, _status: Arc { let reply = message.reply_with("未找到插件"); send_message(&client, &reply).await; @@ -145,7 +143,7 @@ pub async fn on_message(payload: Payload, client: Client, _status: Arc { - PyStatus::get_mut().set_status(&path_name, false); + PyStatus::get_mut().set_status(name, false); let reply = message.reply_with("禁用插件完成"); send_message(&client, &reply).await; } diff --git a/news.md b/news.md index 7d43f5f..b91f35f 100644 --- a/news.md +++ b/news.md @@ -2,9 +2,10 @@ ## 0.8.0 -- ica 兼容版本号更新到 `2.12.24` +- ica 兼容版本号更新到 ~~`2.12.24`~~ `2.12.26` - 从 `py::PyStatus` 开始进行一个 `static mut` -> `static mut OnceLock` 的改造 - 用于看着更舒服(逃) +- 部分重构了一下 读取插件启用状态 的配置文件的代码 ### ica 1.6.5 @@ -136,6 +137,7 @@ 好耶! [!note] + ```text notice_room = [] notice_start = true