能跑了吗?

This commit is contained in:
shenjack 2025-01-06 20:12:35 +08:00
parent 16fee092ba
commit fcf88f0ebb
Signed by: shenjack
GPG Key ID: 7B1134A979775551
7 changed files with 97 additions and 63 deletions

View File

@ -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;

View File

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

View File

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

View File

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

View File

@ -29,10 +29,8 @@ static mut PyPluginStatus: OnceLock<PyStatus> = 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,28 +42,31 @@ 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<PyPlugin> { self.files.remove(path) }
pub fn verify_file(&self, path: &PathBuf) -> bool {
self.files.get(path).is_some_and(|plugin| plugin.verifiy())
pub fn get_status(&self, pluging_id: &str) -> Option<bool> {
self.files.iter().find_map(|(_, plugin)| {
if plugin.get_id() == pluging_id {
return Some(plugin.enabled);
}
None
})
}
/// 获取某个插件的状态
/// 以 config 优先
pub fn get_status(&self, path: &PathBuf) -> Option<bool> {
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) {
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())
}
pub fn display() -> String {
@ -74,7 +75,7 @@ impl PyStatus {
Self::get()
.files
.iter()
.map(|(k, v)| format!("{:?}-{}", k, v.enabled))
.map(|(_, v)| v.to_string())
.collect::<Vec<String>>()
.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<RawPyPlugin> 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 插件目录: {:?} 加载完成, 加载到 {} 个插件",

View File

@ -115,8 +115,7 @@ pub async fn on_message(payload: Payload, client: Client, _status: Arc<BotStatus
// 先判定是否为 admin
// 尝试获取后面的信息
if let Some((_, name)) = message.content.split_once(" ") {
let path_name = PathBuf::from(name);
match PyStatus::get().get_status(&path_name) {
match PyStatus::get().get_status(name) {
None => {
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<BotStatus
send_message(&client, &reply).await;
}
Some(false) => {
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<BotStatus
}
} 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 PyStatus::get().get_status(&path_name) {
match PyStatus::get().get_status(name) {
None => {
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<BotStatus
send_message(&client, &reply).await;
}
Some(true) => {
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;
}

View File

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