进行一个pre 刀耕火种的修改

This commit is contained in:
shenjack 2024-11-22 00:01:17 +08:00
parent 75832bfa2e
commit 86c19bc3db
Signed by: shenjack
GPG Key ID: 7B1134A979775551
10 changed files with 154 additions and 172 deletions

59
Cargo.lock generated
View File

@ -504,9 +504,9 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]] [[package]]
name = "h2" name = "h2"
version = "0.4.6" version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e"
dependencies = [ dependencies = [
"atomic-waker", "atomic-waker",
"bytes", "bytes",
@ -587,9 +587,9 @@ checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946"
[[package]] [[package]]
name = "hyper" name = "hyper"
version = "1.5.0" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-channel", "futures-channel",
@ -682,7 +682,7 @@ dependencies = [
[[package]] [[package]]
name = "ica-rs" name = "ica-rs"
version = "0.7.4" version = "0.8.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"base64 0.22.1", "base64 0.22.1",
@ -698,7 +698,6 @@ dependencies = [
"rust_socketio", "rust_socketio",
"serde", "serde",
"serde_json", "serde_json",
"thiserror 2.0.3",
"tokio", "tokio",
"toml", "toml",
"toml_edit", "toml_edit",
@ -878,9 +877,9 @@ checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708"
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.11" version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" checksum = "540654e97a3f4470a492cd30ff187bc95d89557a903a2bbf112e2fae98104ef2"
[[package]] [[package]]
name = "js-sys" name = "js-sys"
@ -1180,9 +1179,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.89" version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" checksum = "307e3004becf10f5a6e0d59d20f3cd28231b0e0827a96cd3e0ce6d14bc1e4bb3"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@ -1377,7 +1376,7 @@ dependencies = [
"reqwest", "reqwest",
"serde", "serde",
"serde_json", "serde_json",
"thiserror 1.0.69", "thiserror",
"tokio", "tokio",
"tokio-tungstenite", "tokio-tungstenite",
"tungstenite", "tungstenite",
@ -1402,7 +1401,7 @@ dependencies = [
"rust_engineio", "rust_engineio",
"serde", "serde",
"serde_json", "serde_json",
"thiserror 1.0.69", "thiserror",
"tokio", "tokio",
"url", "url",
] ]
@ -1687,9 +1686,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.87" version = "2.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1698,9 +1697,9 @@ dependencies = [
[[package]] [[package]]
name = "sync_wrapper" name = "sync_wrapper"
version = "1.0.1" version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
dependencies = [ dependencies = [
"futures-core", "futures-core",
] ]
@ -1762,16 +1761,7 @@ version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [ dependencies = [
"thiserror-impl 1.0.69", "thiserror-impl",
]
[[package]]
name = "thiserror"
version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa"
dependencies = [
"thiserror-impl 2.0.3",
] ]
[[package]] [[package]]
@ -1785,17 +1775,6 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "thiserror-impl"
version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "thread_local" name = "thread_local"
version = "1.1.8" version = "1.1.8"
@ -2043,7 +2022,7 @@ dependencies = [
"native-tls", "native-tls",
"rand", "rand",
"sha1", "sha1",
"thiserror 1.0.69", "thiserror",
"url", "url",
"utf-8", "utf-8",
] ]
@ -2062,9 +2041,9 @@ checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.13" version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
[[package]] [[package]]
name = "unindent" name = "unindent"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "ica-rs" name = "ica-rs"
version = "0.7.4" version = "0.8.0"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -51,4 +51,3 @@ 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 = "2.0"

View File

@ -1,6 +1,8 @@
pub mod client; pub mod client;
pub mod events; pub mod events;
use std::sync::OnceLock;
use rust_socketio::asynchronous::{Client, ClientBuilder}; use rust_socketio::asynchronous::{Client, ClientBuilder};
use rust_socketio::{async_any_callback, async_callback}; use rust_socketio::{async_any_callback, async_callback};
use rust_socketio::{Event, Payload, TransportType}; use rust_socketio::{Event, Payload, TransportType};
@ -11,7 +13,33 @@ use crate::error::{ClientResult, IcaError};
use crate::{version_str, StopGetter}; use crate::{version_str, StopGetter};
/// icalingua 客户端的兼容版本号 /// icalingua 客户端的兼容版本号
pub const ICA_PROTOCOL_VERSION: &str = "2.12.23"; pub const ICA_PROTOCOL_VERSION: &str = "2.12.24";
mod status {
use crate::data_struct::ica::all_rooms::Room;
pub use crate::data_struct::ica::online_data::OnlineData;
#[derive(Debug, Clone)]
pub struct MainStatus {
/// 是否启用 ica
pub enable: bool,
/// qq 是否登录
pub qq_login: bool,
/// 当前已加载的消息数量
pub current_loaded_messages_count: u64,
/// 房间数据
pub rooms: Vec<Room>,
/// 在线数据 (Icalingua 信息)
pub online_status: OnlineData,
}
impl MainStatus {
pub fn update_rooms(&mut self, room: Vec<Room>) { self.rooms = room; }
pub fn update_online_status(&mut self, status: OnlineData) { self.online_status = status; }
}
}
static ICA_STATUS: OnceLock<status::MainStatus> = OnceLock::new();
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");

View File

@ -9,7 +9,7 @@ use crate::data_struct::ica::all_rooms::Room;
use crate::data_struct::ica::messages::{Message, MessageTrait, NewMessage}; use crate::data_struct::ica::messages::{Message, MessageTrait, NewMessage};
use crate::data_struct::ica::online_data::OnlineData; use crate::data_struct::ica::online_data::OnlineData;
use crate::ica::client::send_message; use crate::ica::client::send_message;
use crate::{client_id, help_msg, py, version_str, MainStatus, VERSION}; use crate::{client_id, help_msg, py, version_str, MainStatus, VERSION, start_up_time};
/// 获取在线数据 /// 获取在线数据
pub async fn get_online_data(payload: Payload, _client: Client) { pub async fn get_online_data(payload: Payload, _client: Client) {
@ -55,6 +55,16 @@ pub async fn add_message(payload: Payload, client: Client) {
let reply = message.reply_with(&help_msg()); let reply = message.reply_with(&help_msg());
send_message(&client, &reply).await; send_message(&client, &reply).await;
} }
// else if message.content() == "/bot-uptime" {
// let duration = match start_up_time().elapsed() {
// Ok(d) => format!("{:?}", d),
// Err(e) => format!("出问题啦 {:?}", e),
// };
// let reply = message.reply_with(&format!(
// "shenbot 已运行: {}", duration
// ));
// send_message(&client, &reply).await;
// }
if MainStatus::global_config().ica().admin_list.contains(&message.sender_id()) { if MainStatus::global_config().ica().admin_list.contains(&message.sender_id()) {
// admin 区 // admin 区
// 先判定是否为 admin // 先判定是否为 admin
@ -63,7 +73,7 @@ pub async fn add_message(payload: Payload, client: Client) {
// 尝试获取后面的信息 // 尝试获取后面的信息
if let Some((_, name)) = message.content().split_once(" ") { if let Some((_, name)) = message.content().split_once(" ") {
let path_name = PathBuf::from(name); let path_name = PathBuf::from(name);
match py::PyStatus::get_status(&path_name) { match py::PyStatus::get().get_status(&path_name) {
None => { None => {
let reply = message.reply_with("未找到插件"); let reply = message.reply_with("未找到插件");
send_message(&client, &reply).await; send_message(&client, &reply).await;
@ -73,7 +83,7 @@ pub async fn add_message(payload: Payload, client: Client) {
send_message(&client, &reply).await; send_message(&client, &reply).await;
} }
Some(false) => { Some(false) => {
py::PyStatus::set_status(&path_name, true); py::PyStatus::get_mut().set_status(&path_name, true);
let reply = message.reply_with("启用插件完成"); let reply = message.reply_with("启用插件完成");
send_message(&client, &reply).await; send_message(&client, &reply).await;
} }
@ -83,7 +93,7 @@ pub async fn add_message(payload: Payload, client: Client) {
{ {
if let Some((_, name)) = message.content().split_once(" ") { if let Some((_, name)) = message.content().split_once(" ") {
let path_name = PathBuf::from(name); let path_name = PathBuf::from(name);
match py::PyStatus::get_status(&path_name) { match py::PyStatus::get().get_status(&path_name) {
None => { None => {
let reply = message.reply_with("未找到插件"); let reply = message.reply_with("未找到插件");
send_message(&client, &reply).await; send_message(&client, &reply).await;
@ -93,7 +103,7 @@ pub async fn add_message(payload: Payload, client: Client) {
send_message(&client, &reply).await; send_message(&client, &reply).await;
} }
Some(true) => { Some(true) => {
py::PyStatus::set_status(&path_name, false); py::PyStatus::get_mut().set_status(&path_name, false);
let reply = message.reply_with("禁用插件完成"); let reply = message.reply_with("禁用插件完成");
send_message(&client, &reply).await; send_message(&client, &reply).await;
} }

View File

@ -65,17 +65,17 @@ pub fn verify_and_reload_plugins() {
let plugin_path = MainStatus::global_config().py().plugin_path.clone(); let plugin_path = MainStatus::global_config().py().plugin_path.clone();
// 先检查是否有插件被删除 // 先检查是否有插件被删除
for path in PyStatus::get_map_mut().keys() { for path in PyStatus::get().files.keys() {
if !path.exists() { if !path.exists() {
event!(Level::INFO, "Python 插件: {:?} 已被删除", path); event!(Level::INFO, "Python 插件: {:?} 已被删除", path);
PyStatus::delete_file(path); PyStatus::get_mut().delete_file(path);
} }
} }
for entry in std::fs::read_dir(plugin_path).unwrap().flatten() { for entry in std::fs::read_dir(plugin_path).unwrap().flatten() {
let path = entry.path(); let path = entry.path();
if let Some(ext) = path.extension() { if let Some(ext) = path.extension() {
if ext == "py" && !PyStatus::verify_file(&path) { if ext == "py" && !PyStatus::get().verify_file(&path) {
need_reload_files.push(path); need_reload_files.push(path);
} }
} }
@ -85,15 +85,15 @@ pub fn verify_and_reload_plugins() {
return; return;
} }
event!(Level::INFO, "更改列表: {:?}", need_reload_files); event!(Level::INFO, "更改列表: {:?}", need_reload_files);
let exist_plugins = PyStatus::get_map_mut(); let plugins = PyStatus::get_mut();
for reload_file in need_reload_files { for reload_file in need_reload_files {
if let Some(plugin) = exist_plugins.get_mut(&reload_file) { if let Some(plugin) = plugins.files.get_mut(&reload_file) {
plugin.reload_from_file(); plugin.reload_from_file();
event!(Level::INFO, "重载 Python 插件: {:?} 完成", reload_file); event!(Level::INFO, "重载 Python 插件: {:?} 完成", reload_file);
} else { } else {
match PyPlugin::new_from_path(&reload_file) { match PyPlugin::new_from_path(&reload_file) {
Some(plugin) => { Some(plugin) => {
PyStatus::add_file(reload_file.clone(), plugin); plugins.add_file(reload_file.clone(), plugin);
info!("加载 Python 插件: {:?} 完成", reload_file); info!("加载 Python 插件: {:?} 完成", reload_file);
} }
None => { None => {
@ -149,8 +149,8 @@ pub async fn ica_new_message_py(message: &ica::messages::NewMessage, client: &Cl
// 验证插件是否改变 // 验证插件是否改变
verify_and_reload_plugins(); verify_and_reload_plugins();
let plugins = PyStatus::get_map(); let plugins = PyStatus::get();
for (path, plugin) in plugins.iter().filter(|(_, plugin)| plugin.enabled) { for (path, plugin) in plugins.files.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);
let args = (msg, client); let args = (msg, client);
@ -162,8 +162,8 @@ 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_and_reload_plugins(); verify_and_reload_plugins();
let plugins = PyStatus::get_map(); let plugins = PyStatus::get();
for (path, plugin) in plugins.iter().filter(|(_, plugin)| plugin.enabled) { for (path, plugin) in plugins.files.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);
let args = (msg_id.clone(), client); let args = (msg_id.clone(), client);
@ -177,8 +177,8 @@ pub async fn tailchat_new_message_py(
) { ) {
verify_and_reload_plugins(); verify_and_reload_plugins();
let plugins = PyStatus::get_map(); let plugins = PyStatus::get();
for (path, plugin) in plugins.iter().filter(|(_, plugin)| plugin.enabled) { for (path, plugin) in plugins.files.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);
let args = (msg, client); let args = (msg, client);

View File

@ -2,9 +2,9 @@ pub mod ica;
pub mod tailchat; pub mod tailchat;
use pyo3::{ use pyo3::{
pyclass, pymethods, IntoPyObject, Bound, pyclass, pymethods,
PyAny, PyRef,
types::{PyBool, PyString}, types::{PyBool, PyString},
Bound, IntoPyObject, PyAny, PyRef,
}; };
use toml::Value as TomlValue; use toml::Value as TomlValue;
@ -33,7 +33,6 @@ impl ConfigDataPy {
pub fn __getitem__(self_: PyRef<'_, Self>, key: String) -> Option<Bound<PyAny>> { pub fn __getitem__(self_: PyRef<'_, Self>, key: String) -> Option<Bound<PyAny>> {
match self_.data.get(&key) { match self_.data.get(&key) {
Some(value) => match value { Some(value) => match value {
// TomlValue::String(s) => Some(s.into_pyobject(self_.py()).unwrap().as_any().as_unbound().to_owned()),
TomlValue::String(s) => Some(PyString::new(self_.py(), s).into_any()), TomlValue::String(s) => Some(PyString::new(self_.py(), s).into_any()),
TomlValue::Integer(i) => Some(i.into_pyobject(self_.py()).unwrap().into_any()), TomlValue::Integer(i) => Some(i.into_pyobject(self_.py()).unwrap().into_any()),
TomlValue::Float(f) => Some(f.into_pyobject(self_.py()).unwrap().into_any()), TomlValue::Float(f) => Some(f.into_pyobject(self_.py()).unwrap().into_any()),

View File

@ -116,9 +116,9 @@ impl PluginConfigFile {
} }
pub fn sync_status_from_config(&mut self) { pub fn sync_status_from_config(&mut self) {
let plugins = PyStatus::get_map_mut(); let plugins = PyStatus::get_mut();
self.verify_and_init(); self.verify_and_init();
plugins.iter_mut().for_each(|(path, status)| { plugins.files.iter_mut().for_each(|(path, status)| {
let config_status = self.get_status(path); let config_status = self.get_status(path);
event!(Level::INFO, "插件状态: {:?} {} -> {}", path, status.enabled, config_status); event!(Level::INFO, "插件状态: {:?} {} -> {}", path, status.enabled, config_status);
status.enabled = config_status; status.enabled = config_status;
@ -126,11 +126,11 @@ impl PluginConfigFile {
} }
pub fn sync_status_to_config(&mut self) { pub fn sync_status_to_config(&mut self) {
let plugins = PyStatus::get_map(); let plugins = PyStatus::get();
self.verify_and_init(); self.verify_and_init();
let table = self.data.get_mut(CONFIG_KEY).unwrap().as_table_mut().unwrap(); let table = self.data.get_mut(CONFIG_KEY).unwrap().as_table_mut().unwrap();
table.clear(); table.clear();
plugins.iter().for_each(|(path, status)| { plugins.files.iter().for_each(|(path, status)| {
table.insert(path.to_str().unwrap(), value(status.enabled)); table.insert(path.to_str().unwrap(), value(status.enabled));
}); });
} }

View File

@ -4,6 +4,7 @@ pub mod config;
use std::ffi::CString; use std::ffi::CString;
use std::path::Path; use std::path::Path;
use std::sync::OnceLock;
use std::time::SystemTime; use std::time::SystemTime;
use std::{collections::HashMap, path::PathBuf}; use std::{collections::HashMap, path::PathBuf};
@ -16,116 +17,65 @@ use crate::MainStatus;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct PyStatus { pub struct PyStatus {
pub files: Option<PyPlugins>, pub files: PyPlugins,
pub config: Option<config::PluginConfigFile>, pub config: config::PluginConfigFile,
} }
pub type PyPlugins = HashMap<PathBuf, PyPlugin>; pub type PyPlugins = HashMap<PathBuf, PyPlugin>;
pub type RawPyPlugin = (PathBuf, Option<SystemTime>, String); pub type RawPyPlugin = (PathBuf, Option<SystemTime>, String);
#[allow(non_upper_case_globals)]
static mut PyPluginStatus: OnceLock<PyStatus> = OnceLock::new();
impl PyStatus { impl PyStatus {
pub fn init() { pub fn init() {
unsafe { let plugin_path = MainStatus::global_config().py().plugin_path.clone();
if PYSTATUS.files.is_none() {
PYSTATUS.files = Some(HashMap::new());
}
if PYSTATUS.config.is_none() {
let plugin_path = MainStatus::global_config().py().config_path.clone();
let mut config = let mut config =
config::PluginConfigFile::from_config_path(&PathBuf::from(plugin_path)) config::PluginConfigFile::from_config_path(&PathBuf::from(plugin_path)).unwrap();
.unwrap();
config.verify_and_init(); config.verify_and_init();
PYSTATUS.config = Some(config); let status = PyStatus {
} files: HashMap::new(),
} config,
};
let _ = unsafe { PyPluginStatus.get_or_init(|| status) };
} }
pub fn add_file(path: PathBuf, plugin: PyPlugin) { Self::get_map_mut().insert(path, plugin); } pub fn get() -> &'static PyStatus { unsafe { PyPluginStatus.get().unwrap() } }
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(path: &PathBuf) -> Option<PyPlugin> { Self::get_map_mut().remove(path) } pub fn delete_file(&mut self, path: &PathBuf) -> Option<PyPlugin> { self.files.remove(path) }
pub fn verify_file(path: &PathBuf) -> bool { pub fn verify_file(&self, path: &PathBuf) -> bool {
Self::get_map().get(path).is_some_and(|plugin| plugin.verifiy()) self.files.get(path).is_some_and(|plugin| plugin.verifiy())
}
pub fn get_map() -> &'static PyPlugins {
unsafe {
let ptr = &raw const PYSTATUS.files;
let ptr = &*ptr;
match ptr.as_ref() {
Some(files) => files,
None => {
Self::init();
ptr.as_ref().unwrap()
}
}
}
}
pub fn get_map_mut() -> &'static mut PyPlugins {
unsafe {
let ptr = &raw mut PYSTATUS.files;
let ptr = &mut *ptr;
match ptr {
Some(files) => files,
None => {
Self::init();
ptr.as_mut().unwrap()
}
}
}
}
pub fn get_config() -> &'static config::PluginConfigFile {
unsafe {
let ptr = &raw const PYSTATUS.config;
let ptr = &*ptr;
match ptr {
Some(config) => config,
None => {
Self::init();
ptr.as_ref().unwrap()
}
}
}
}
pub fn get_config_mut() -> &'static mut config::PluginConfigFile {
unsafe {
let ptr = &raw mut PYSTATUS.config;
let ptr = &mut *ptr;
match ptr {
Some(config) => config,
None => {
Self::init();
ptr.as_mut().unwrap()
}
}
}
} }
/// 获取某个插件的状态 /// 获取某个插件的状态
/// 以 config 优先 /// 以 config 优先
pub fn get_status(path: &PathBuf) -> Option<bool> { pub fn get_status(&self, path: &PathBuf) -> Option<bool> {
Self::get_config_mut().sync_status_from_config(); self.files.get(path).map(|plugin| plugin.enabled)
Self::get_map().get(path).map(|plugin| plugin.enabled)
} }
pub fn set_status(path: &Path, status: bool) { pub fn sync_status(&mut self) {
let cfg = Self::get_config_mut(); self.config.sync_status_from_config();
cfg.set_status(path, status); }
let map = Self::get_map_mut();
if let Some(plugin) = map.get_mut(path) { 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; plugin.enabled = status;
} }
} }
pub fn display() -> String { pub fn display() -> String {
let map = Self::get_map();
format!( format!(
"Python 插件 {{ {} }}", "Python 插件 {{ {} }}",
map.iter() Self::get()
.files
.iter()
.map(|(k, v)| format!("{:?}-{}", k, v.enabled)) .map(|(k, v)| format!("{:?}-{}", k, v.enabled))
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join("\n") .join("\n")
@ -185,7 +135,7 @@ impl PyPlugin {
Ok(plugin) => { Ok(plugin) => {
self.py_module = plugin.py_module; self.py_module = plugin.py_module;
self.changed_time = plugin.changed_time; 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.file_path.as_path());
event!(Level::INFO, "更新 Python 插件文件 {:?} 完成", self.file_path); event!(Level::INFO, "更新 Python 插件文件 {:?} 完成", self.file_path);
} }
Err(e) => { Err(e) => {
@ -356,12 +306,8 @@ impl TryFrom<RawPyPlugin> for PyPlugin {
} }
} }
pub static mut PYSTATUS: PyStatus = PyStatus {
files: None,
config: None,
};
pub fn load_py_plugins(path: &PathBuf) { pub fn load_py_plugins(path: &PathBuf) {
let plugins = PyStatus::get_mut();
if path.exists() { if path.exists() {
event!(Level::INFO, "找到位于 {:?} 的插件", path); event!(Level::INFO, "找到位于 {:?} 的插件", path);
// 搜索所有的 py 文件 和 文件夹单层下面的 py 文件 // 搜索所有的 py 文件 和 文件夹单层下面的 py 文件
@ -376,7 +322,7 @@ pub fn load_py_plugins(path: &PathBuf) {
if let Some(ext) = path.extension() { if let Some(ext) = path.extension() {
if ext == "py" { if ext == "py" {
if let Some(plugin) = PyPlugin::new_from_path(&path) { if let Some(plugin) = PyPlugin::new_from_path(&path) {
PyStatus::add_file(path, plugin); plugins.add_file(path, plugin);
} }
} }
} }
@ -386,12 +332,12 @@ pub fn load_py_plugins(path: &PathBuf) {
} else { } else {
event!(Level::WARN, "插件加载目录不存在: {:?}", path); event!(Level::WARN, "插件加载目录不存在: {:?}", path);
} }
PyStatus::get_config_mut().sync_status_from_config(); plugins.config.sync_status_from_config();
event!( event!(
Level::INFO, Level::INFO,
"python 插件目录: {:?} 加载完成, 加载到 {} 个插件", "python 插件目录: {:?} 加载完成, 加载到 {} 个插件",
path, path,
PyStatus::get_map().len() plugins.files.len()
); );
} }
@ -403,7 +349,9 @@ pub fn py_module_from_code(content: &str, path: &Path) -> PyResult<Py<PyAny>> {
py, py,
CString::new(content).unwrap().as_c_str(), CString::new(content).unwrap().as_c_str(),
CString::new(path.to_string_lossy().as_bytes()).unwrap().as_c_str(), CString::new(path.to_string_lossy().as_bytes()).unwrap().as_c_str(),
CString::new(path.file_name().unwrap().to_string_lossy().as_bytes()).unwrap().as_c_str(), CString::new(path.file_name().unwrap().to_string_lossy().as_bytes())
.unwrap()
.as_c_str(),
// !!!! 请注意, 一定要给他一个名字, cpython 会自动把后面的重名模块覆盖掉前面的 // !!!! 请注意, 一定要给他一个名字, cpython 会自动把后面的重名模块覆盖掉前面的
) )
.map(|module| module.into()); .map(|module| module.into());
@ -439,8 +387,9 @@ pub fn init_py() {
} }
pub fn post_py() -> anyhow::Result<()> { pub fn post_py() -> anyhow::Result<()> {
PyStatus::get_config_mut().sync_status_to_config(); PyStatus::get_mut().config.sync_status_to_config();
PyStatus::get_config() PyStatus::get()
.config
.write_to_file(&PathBuf::from(MainStatus::global_config().py().config_path))?; .write_to_file(&PathBuf::from(MainStatus::global_config().py().config_path))?;
Ok(()) Ok(())
} }

View File

@ -9,7 +9,9 @@ use tracing::{event, info, Level};
use crate::data_struct::tailchat::messages::ReceiveMessage; use crate::data_struct::tailchat::messages::ReceiveMessage;
use crate::data_struct::tailchat::status::{BotStatus, UpdateDMConverse}; use crate::data_struct::tailchat::status::{BotStatus, UpdateDMConverse};
use crate::tailchat::client::{emit_join_room, send_message}; use crate::tailchat::client::{emit_join_room, send_message};
use crate::{client_id, help_msg, py, version_str, MainStatus, VERSION}; use crate::py::PyStatus;
use crate::py::call::tailchat_new_message_py;
use crate::{client_id, help_msg, version_str, MainStatus, VERSION, start_up_time};
/// 所有 /// 所有
pub async fn any_event(event: Event, payload: Payload, _client: Client, _status: Arc<BotStatus>) { pub async fn any_event(event: Event, payload: Payload, _client: Client, _status: Arc<BotStatus>) {
@ -86,7 +88,7 @@ pub async fn on_message(payload: Payload, client: Client, _status: Arc<BotStatus
VERSION, VERSION,
client_id(), client_id(),
if MainStatus::global_config().check_py() { if MainStatus::global_config().check_py() {
py::PyStatus::display() PyStatus::display()
} else { } else {
"未启用 Python 插件".to_string() "未启用 Python 插件".to_string()
} }
@ -96,6 +98,16 @@ pub async fn on_message(payload: Payload, client: Client, _status: Arc<BotStatus
let reply = message.reply_with(&help_msg()); let reply = message.reply_with(&help_msg());
send_message(&client, &reply).await; send_message(&client, &reply).await;
} }
// else if message.content == "/bot-uptime" {
// let duration = match start_up_time().elapsed() {
// Ok(d) => format!("{:?}", d),
// Err(e) => format!("出问题啦 {:?}", e),
// };
// let reply = message.reply_with(&format!(
// "shenbot 已运行: {}", duration
// ));
// send_message(&client, &reply).await;
// }
if MainStatus::global_config().tailchat().admin_list.contains(&message.sender_id) { if MainStatus::global_config().tailchat().admin_list.contains(&message.sender_id) {
// admin 区 // admin 区
let client_id = client_id(); let client_id = client_id();
@ -104,7 +116,7 @@ pub async fn on_message(payload: Payload, client: Client, _status: Arc<BotStatus
// 尝试获取后面的信息 // 尝试获取后面的信息
if let Some((_, name)) = message.content.split_once(" ") { if let Some((_, name)) = message.content.split_once(" ") {
let path_name = PathBuf::from(name); let path_name = PathBuf::from(name);
match py::PyStatus::get_status(&path_name) { match PyStatus::get().get_status(&path_name) {
None => { None => {
let reply = message.reply_with("未找到插件"); let reply = message.reply_with("未找到插件");
send_message(&client, &reply).await; send_message(&client, &reply).await;
@ -114,7 +126,7 @@ pub async fn on_message(payload: Payload, client: Client, _status: Arc<BotStatus
send_message(&client, &reply).await; send_message(&client, &reply).await;
} }
Some(false) => { Some(false) => {
py::PyStatus::set_status(&path_name, true); PyStatus::get_mut().set_status(&path_name, true);
let reply = message.reply_with("启用插件完成"); let reply = message.reply_with("启用插件完成");
send_message(&client, &reply).await; send_message(&client, &reply).await;
} }
@ -123,7 +135,7 @@ pub async fn on_message(payload: Payload, client: Client, _status: Arc<BotStatus
} else if message.content.starts_with(&format!("/bot-disable-{}", client_id)) { } else if message.content.starts_with(&format!("/bot-disable-{}", client_id)) {
if let Some((_, name)) = message.content.split_once(" ") { if let Some((_, name)) = message.content.split_once(" ") {
let path_name = PathBuf::from(name); let path_name = PathBuf::from(name);
match py::PyStatus::get_status(&path_name) { match PyStatus::get().get_status(&path_name) {
None => { None => {
let reply = message.reply_with("未找到插件"); let reply = message.reply_with("未找到插件");
send_message(&client, &reply).await; send_message(&client, &reply).await;
@ -133,7 +145,7 @@ pub async fn on_message(payload: Payload, client: Client, _status: Arc<BotStatus
send_message(&client, &reply).await; send_message(&client, &reply).await;
} }
Some(true) => { Some(true) => {
py::PyStatus::set_status(&path_name, false); PyStatus::get_mut().set_status(&path_name, false);
let reply = message.reply_with("禁用插件完成"); let reply = message.reply_with("禁用插件完成");
send_message(&client, &reply).await; send_message(&client, &reply).await;
} }
@ -142,7 +154,7 @@ pub async fn on_message(payload: Payload, client: Client, _status: Arc<BotStatus
} }
} }
} }
py::call::tailchat_new_message_py(&message, &client).await; tailchat_new_message_py(&message, &client).await;
} }
} }
} }

View File

@ -1,5 +1,11 @@
# 更新日志 # 更新日志
## 0.8.0
- ica 兼容版本号更新到 `2.12.24`
- 从 `py::PyStatus` 开始进行一个 `static mut` -> `static mut OnceLock` 的改造
- 用于看着更舒服(逃)
## 0.7.4 ## 0.7.4
- ica 兼容版本号更新到 `2.12.23` - ica 兼容版本号更新到 `2.12.23`