mirror of
http://shenjack.top:5100/shenjack/icalingua-python-bot.git
synced 2025-02-23 01:49:57 +08:00
能跑了吗?
This commit is contained in:
parent
16fee092ba
commit
fcf88f0ebb
|
@ -13,7 +13,7 @@ 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.24";
|
pub const ICA_PROTOCOL_VERSION: &str = "2.12.26";
|
||||||
|
|
||||||
mod status {
|
mod status {
|
||||||
use crate::data_struct::ica::all_rooms::Room;
|
use crate::data_struct::ica::all_rooms::Room;
|
||||||
|
|
|
@ -7,7 +7,7 @@ use colored::Colorize;
|
||||||
use ed25519_dalek::{Signature, Signer, SigningKey};
|
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, json};
|
use serde_json::{json, Value};
|
||||||
use tracing::{debug, event, span, warn, Level};
|
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 {
|
pub async fn send_poke(client: &Client, room_id: RoomId, target: UserId) -> bool {
|
||||||
let data = json!([room_id, target]);
|
let data = json!([room_id, target]);
|
||||||
match client.emit(
|
match client.emit("sendGroupPoke", data).await {
|
||||||
"sendGroupPoke", data
|
|
||||||
).await {
|
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
event!(Level::INFO, "已向 {} 的 {} 发送戳一戳", room_id, target);
|
event!(Level::INFO, "已向 {} 的 {} 发送戳一戳", room_id, target);
|
||||||
true
|
true
|
||||||
|
|
|
@ -72,8 +72,7 @@ pub async fn add_message(payload: Payload, client: Client) {
|
||||||
if message.content().starts_with(&format!("/bot-enable-{}", client_id)) {
|
if message.content().starts_with(&format!("/bot-enable-{}", client_id)) {
|
||||||
// 尝试获取后面的信息
|
// 尝试获取后面的信息
|
||||||
if let Some((_, name)) = message.content().split_once(" ") {
|
if let Some((_, name)) = message.content().split_once(" ") {
|
||||||
let path_name = PathBuf::from(name);
|
match py::PyStatus::get().get_status(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;
|
||||||
|
@ -83,7 +82,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::get_mut().set_status(&path_name, true);
|
py::PyStatus::get_mut().set_status(name, true);
|
||||||
let reply = message.reply_with("启用插件完成");
|
let reply = message.reply_with("启用插件完成");
|
||||||
send_message(&client, &reply).await;
|
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))
|
} 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);
|
match py::PyStatus::get().get_status(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;
|
||||||
|
@ -103,7 +101,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::get_mut().set_status(&path_name, false);
|
py::PyStatus::get_mut().set_status(name, false);
|
||||||
let reply = message.reply_with("禁用插件完成");
|
let reply = message.reply_with("禁用插件完成");
|
||||||
send_message(&client, &reply).await;
|
send_message(&client, &reply).await;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ use toml_edit::{value, DocumentMut, Key, Table, TomlError, Value};
|
||||||
use tracing::{event, Level};
|
use tracing::{event, Level};
|
||||||
|
|
||||||
use crate::py::PyStatus;
|
use crate::py::PyStatus;
|
||||||
|
use crate::MainStatus;
|
||||||
|
|
||||||
/// ```toml
|
/// ```toml
|
||||||
/// # 这个文件是由 shenbot 自动生成的, 请 **谨慎** 修改
|
/// # 这个文件是由 shenbot 自动生成的, 请 **谨慎** 修改
|
||||||
|
@ -31,14 +32,37 @@ pub const DEFAULT_CONFIG: &str = r#"
|
||||||
|
|
||||||
impl PluginConfigFile {
|
impl PluginConfigFile {
|
||||||
pub fn from_str(data: &str) -> Result<Self, TomlError> {
|
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 })
|
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> {
|
pub fn from_config_path(path: &Path) -> anyhow::Result<Self> {
|
||||||
let config_path = path.join(CONFIG_FILE_NAME);
|
let config_path = path.join(CONFIG_FILE_NAME);
|
||||||
if !config_path.exists() {
|
if !config_path.exists() {
|
||||||
event!(Level::INFO, "插件配置文件不存在, 正在创建");
|
event!(Level::WARN, "插件配置文件不存在, 正在创建");
|
||||||
std::fs::write(&config_path, DEFAULT_CONFIG)?;
|
std::fs::write(&config_path, DEFAULT_CONFIG)?;
|
||||||
Ok(Self::from_str(DEFAULT_CONFIG)?)
|
Ok(Self::from_str(DEFAULT_CONFIG)?)
|
||||||
} else {
|
} 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> {
|
fn get_table(&self) -> Option<&Table> {
|
||||||
self.data.get(CONFIG_KEY).and_then(|item| item.as_table())
|
self.data.get(CONFIG_KEY).and_then(|item| item.as_table())
|
||||||
}
|
}
|
||||||
|
@ -67,11 +81,10 @@ impl PluginConfigFile {
|
||||||
|
|
||||||
/// 获取插件状态
|
/// 获取插件状态
|
||||||
/// 默认为 true
|
/// 默认为 true
|
||||||
pub fn get_status(&self, path: &Path) -> bool {
|
pub fn get_status(&self, plugin_id: &str) -> bool {
|
||||||
let path_str = path.to_str().unwrap();
|
|
||||||
if let Some(item) = self.data.get(CONFIG_KEY) {
|
if let Some(item) = self.data.get(CONFIG_KEY) {
|
||||||
if let Some(table) = item.as_table() {
|
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() {
|
if let Some(bool) = item.as_bool() {
|
||||||
return bool;
|
return bool;
|
||||||
}
|
}
|
||||||
|
@ -100,7 +113,6 @@ impl PluginConfigFile {
|
||||||
|
|
||||||
/// 设置插件状态
|
/// 设置插件状态
|
||||||
pub fn set_status(&mut self, path: &Path, status: bool) {
|
pub fn set_status(&mut self, path: &Path, status: bool) {
|
||||||
self.verify_and_init();
|
|
||||||
let path_str = path.to_str().unwrap();
|
let path_str = path.to_str().unwrap();
|
||||||
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();
|
||||||
if table.contains_key(path_str) {
|
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();
|
let plugins = PyStatus::get_mut();
|
||||||
self.verify_and_init();
|
|
||||||
plugins.files.iter_mut().for_each(|(path, status)| {
|
plugins.files.iter_mut().for_each(|(path, status)| {
|
||||||
let config_status = self.get_status(path);
|
let plugin_id = status.get_id();
|
||||||
event!(Level::INFO, "插件状态: {:?} {} -> {}", path, status.enabled, config_status);
|
let config_status = self.get_status(&plugin_id);
|
||||||
|
event!(
|
||||||
|
Level::INFO,
|
||||||
|
"插件状态: {}({:?}) {} -> {}",
|
||||||
|
status.get_id(),
|
||||||
|
path,
|
||||||
|
status.enabled,
|
||||||
|
config_status
|
||||||
|
);
|
||||||
status.enabled = config_status;
|
status.enabled = config_status;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sync_status_to_config(&mut self) {
|
pub fn sync_status_to_config(&mut self) {
|
||||||
let plugins = PyStatus::get();
|
let plugins = PyStatus::get();
|
||||||
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.files.iter().for_each(|(path, status)| {
|
plugins.files.iter().for_each(|(_, status)| {
|
||||||
table.insert(path.to_str().unwrap(), value(status.enabled));
|
table.insert(&status.get_id(), value(status.enabled));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,10 +29,8 @@ static mut PyPluginStatus: OnceLock<PyStatus> = OnceLock::new();
|
||||||
|
|
||||||
impl PyStatus {
|
impl PyStatus {
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
let plugin_path = MainStatus::global_config().py().plugin_path.clone();
|
let config =
|
||||||
let mut config =
|
config::PluginConfigFile::default_init().expect("初始化 Python 插件配置文件失败");
|
||||||
config::PluginConfigFile::from_config_path(&PathBuf::from(plugin_path)).unwrap();
|
|
||||||
config.verify_and_init();
|
|
||||||
let status = PyStatus {
|
let status = PyStatus {
|
||||||
files: HashMap::new(),
|
files: HashMap::new(),
|
||||||
config,
|
config,
|
||||||
|
@ -44,37 +42,40 @@ impl PyStatus {
|
||||||
|
|
||||||
pub fn get_mut() -> &'static mut PyStatus { unsafe { PyPluginStatus.get_mut().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 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 delete_file(&mut self, path: &PathBuf) -> Option<PyPlugin> { self.files.remove(path) }
|
||||||
|
|
||||||
|
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
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
pub fn verify_file(&self, path: &PathBuf) -> bool {
|
||||||
self.files.get(path).is_some_and(|plugin| plugin.verifiy())
|
self.files.get(path).is_some_and(|plugin| plugin.verifiy())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 获取某个插件的状态
|
|
||||||
/// 以 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) {
|
|
||||||
plugin.enabled = status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn display() -> String {
|
pub fn display() -> String {
|
||||||
format!(
|
format!(
|
||||||
"Python 插件 {{ {} }}",
|
"Python 插件 {{ {} }}",
|
||||||
Self::get()
|
Self::get()
|
||||||
.files
|
.files
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(k, v)| format!("{:?}-{}", k, v.enabled))
|
.map(|(_, v)| v.to_string())
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
.join("\n")
|
.join("\n")
|
||||||
)
|
)
|
||||||
|
@ -133,7 +134,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.get_id());
|
||||||
event!(Level::INFO, "更新 Python 插件文件 {:?} 完成", self.file_path);
|
event!(Level::INFO, "更新 Python 插件文件 {:?} 完成", self.file_path);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
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";
|
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) {
|
pub fn load_py_plugins(path: &PathBuf) {
|
||||||
let plugins = PyStatus::get_mut();
|
let plugins = PyStatus::get_mut();
|
||||||
if path.exists() {
|
if path.exists() {
|
||||||
|
@ -330,7 +348,7 @@ pub fn load_py_plugins(path: &PathBuf) {
|
||||||
} else {
|
} else {
|
||||||
event!(Level::WARN, "插件加载目录不存在: {:?}", path);
|
event!(Level::WARN, "插件加载目录不存在: {:?}", path);
|
||||||
}
|
}
|
||||||
plugins.config.sync_status_from_config();
|
plugins.config.read_status_from_file();
|
||||||
event!(
|
event!(
|
||||||
Level::INFO,
|
Level::INFO,
|
||||||
"python 插件目录: {:?} 加载完成, 加载到 {} 个插件",
|
"python 插件目录: {:?} 加载完成, 加载到 {} 个插件",
|
||||||
|
|
|
@ -115,8 +115,7 @@ pub async fn on_message(payload: Payload, client: Client, _status: Arc<BotStatus
|
||||||
// 先判定是否为 admin
|
// 先判定是否为 admin
|
||||||
// 尝试获取后面的信息
|
// 尝试获取后面的信息
|
||||||
if let Some((_, name)) = message.content.split_once(" ") {
|
if let Some((_, name)) = message.content.split_once(" ") {
|
||||||
let path_name = PathBuf::from(name);
|
match PyStatus::get().get_status(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;
|
||||||
|
@ -126,7 +125,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) => {
|
||||||
PyStatus::get_mut().set_status(&path_name, true);
|
PyStatus::get_mut().set_status(name, true);
|
||||||
let reply = message.reply_with("启用插件完成");
|
let reply = message.reply_with("启用插件完成");
|
||||||
send_message(&client, &reply).await;
|
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)) {
|
} 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);
|
match PyStatus::get().get_status(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;
|
||||||
|
@ -145,7 +143,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) => {
|
||||||
PyStatus::get_mut().set_status(&path_name, false);
|
PyStatus::get_mut().set_status(name, false);
|
||||||
let reply = message.reply_with("禁用插件完成");
|
let reply = message.reply_with("禁用插件完成");
|
||||||
send_message(&client, &reply).await;
|
send_message(&client, &reply).await;
|
||||||
}
|
}
|
||||||
|
|
4
news.md
4
news.md
|
@ -2,9 +2,10 @@
|
||||||
|
|
||||||
## 0.8.0
|
## 0.8.0
|
||||||
|
|
||||||
- ica 兼容版本号更新到 `2.12.24`
|
- ica 兼容版本号更新到 ~~`2.12.24`~~ `2.12.26`
|
||||||
- 从 `py::PyStatus` 开始进行一个 `static mut` -> `static mut OnceLock` 的改造
|
- 从 `py::PyStatus` 开始进行一个 `static mut` -> `static mut OnceLock` 的改造
|
||||||
- 用于看着更舒服(逃)
|
- 用于看着更舒服(逃)
|
||||||
|
- 部分重构了一下 读取插件启用状态 的配置文件的代码
|
||||||
|
|
||||||
### ica 1.6.5
|
### ica 1.6.5
|
||||||
|
|
||||||
|
@ -136,6 +137,7 @@
|
||||||
好耶!
|
好耶!
|
||||||
|
|
||||||
[!note]
|
[!note]
|
||||||
|
|
||||||
```text
|
```text
|
||||||
notice_room = []
|
notice_room = []
|
||||||
notice_start = true
|
notice_start = true
|
||||||
|
|
Loading…
Reference in New Issue
Block a user