Compare commits
2 Commits
5636c8e1d9
...
113a1518d1
Author | SHA1 | Date | |
---|---|---|---|
113a1518d1 | |||
680934ad3f |
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -659,7 +659,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ica-rs"
|
name = "ica-rs"
|
||||||
version = "0.6.11"
|
version = "0.7.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ica-rs"
|
name = "ica-rs"
|
||||||
version = "0.6.11"
|
version = "0.7.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
|
||||||
|
@ -4,7 +4,6 @@ use std::fs;
|
|||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use toml::from_str;
|
use toml::from_str;
|
||||||
use tracing::warn;
|
|
||||||
|
|
||||||
use crate::data_struct::{ica, tailchat};
|
use crate::data_struct::{ica, tailchat};
|
||||||
|
|
||||||
@ -18,12 +17,16 @@ pub struct IcaConfig {
|
|||||||
/// bot 的 qq
|
/// bot 的 qq
|
||||||
pub self_id: ica::UserId,
|
pub self_id: ica::UserId,
|
||||||
/// 提醒的房间
|
/// 提醒的房间
|
||||||
|
#[serde(default = "default_empty_i64_vec")]
|
||||||
pub notice_room: Vec<ica::RoomId>,
|
pub notice_room: Vec<ica::RoomId>,
|
||||||
/// 是否提醒
|
/// 是否提醒
|
||||||
|
#[serde(default = "default_false")]
|
||||||
pub notice_start: bool,
|
pub notice_start: bool,
|
||||||
/// 管理员列表
|
/// 管理员列表
|
||||||
|
#[serde(default = "default_empty_i64_vec")]
|
||||||
pub admin_list: Vec<ica::UserId>,
|
pub admin_list: Vec<ica::UserId>,
|
||||||
/// 过滤列表
|
/// 过滤列表
|
||||||
|
#[serde(default = "default_empty_i64_vec")]
|
||||||
pub filter_list: Vec<ica::UserId>,
|
pub filter_list: Vec<ica::UserId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,36 +41,51 @@ pub struct TailchatConfig {
|
|||||||
/// 提醒的房间
|
/// 提醒的房间
|
||||||
pub notice_room: Vec<(tailchat::GroupId, tailchat::ConverseId)>,
|
pub notice_room: Vec<(tailchat::GroupId, tailchat::ConverseId)>,
|
||||||
/// 是否提醒
|
/// 是否提醒
|
||||||
|
#[serde(default = "default_false")]
|
||||||
pub notice_start: bool,
|
pub notice_start: bool,
|
||||||
/// 管理员列表
|
/// 管理员列表
|
||||||
|
#[serde(default = "default_empty_str_vec")]
|
||||||
pub admin_list: Vec<tailchat::UserId>,
|
pub admin_list: Vec<tailchat::UserId>,
|
||||||
/// 过滤列表
|
/// 过滤列表
|
||||||
|
#[serde(default = "default_empty_str_vec")]
|
||||||
pub filter_list: Vec<tailchat::UserId>,
|
pub filter_list: Vec<tailchat::UserId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_plugin_path() -> String { "./plugins".to_string() }
|
||||||
|
fn default_config_path() -> String { "./config".to_string() }
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize)]
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
pub struct PyConfig {
|
pub struct PyConfig {
|
||||||
/// 插件路径
|
/// 插件路径
|
||||||
|
#[serde(default = "default_plugin_path")]
|
||||||
pub plugin_path: String,
|
pub plugin_path: String,
|
||||||
/// 配置文件路径
|
/// 配置文件夹路径
|
||||||
|
#[serde(default = "default_config_path")]
|
||||||
pub config_path: String,
|
pub config_path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_empty_i64_vec() -> Vec<i64> { Vec::new() }
|
||||||
|
fn default_empty_str_vec() -> Vec<String> { Vec::new() }
|
||||||
|
fn default_false() -> bool { false }
|
||||||
|
|
||||||
/// 主配置
|
/// 主配置
|
||||||
#[derive(Debug, Clone, Deserialize)]
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
pub struct BotConfig {
|
pub struct BotConfig {
|
||||||
/// 是否启用 icalingua
|
/// 是否启用 icalingua
|
||||||
pub enable_ica: Option<bool>,
|
#[serde(default = "default_false")]
|
||||||
|
pub enable_ica: bool,
|
||||||
/// Ica 配置
|
/// Ica 配置
|
||||||
pub ica: Option<IcaConfig>,
|
pub ica: Option<IcaConfig>,
|
||||||
|
|
||||||
/// 是否启用 Tailchat
|
/// 是否启用 Tailchat
|
||||||
pub enable_tailchat: Option<bool>,
|
#[serde(default = "default_false")]
|
||||||
|
pub enable_tailchat: bool,
|
||||||
/// Tailchat 配置
|
/// Tailchat 配置
|
||||||
pub tailchat: Option<TailchatConfig>,
|
pub tailchat: Option<TailchatConfig>,
|
||||||
|
|
||||||
/// 是否启用 Python 插件
|
/// 是否启用 Python 插件
|
||||||
pub enable_py: Option<bool>,
|
#[serde(default = "default_false")]
|
||||||
|
pub enable_py: bool,
|
||||||
/// Python 插件配置
|
/// Python 插件配置
|
||||||
pub py: Option<PyConfig>,
|
pub py: Option<PyConfig>,
|
||||||
}
|
}
|
||||||
@ -88,10 +106,9 @@ impl BotConfig {
|
|||||||
let mut args = env::args();
|
let mut args = env::args();
|
||||||
while let Some(arg) = args.next() {
|
while let Some(arg) = args.next() {
|
||||||
if arg == "-c" {
|
if arg == "-c" {
|
||||||
config_file_path = args.next().expect(&format!(
|
config_file_path = args.next().unwrap_or_else(|| {
|
||||||
"{}",
|
panic!("{}", "No config path given\nUsage: -c <config_file_path>".red())
|
||||||
"No config path given\nUsage: -c <config_file_path>".red()
|
});
|
||||||
));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,64 +116,13 @@ impl BotConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 检查是否启用 ica
|
/// 检查是否启用 ica
|
||||||
pub fn check_ica(&self) -> bool {
|
pub fn check_ica(&self) -> bool { self.enable_ica }
|
||||||
match self.enable_ica {
|
|
||||||
Some(enable) => {
|
|
||||||
if enable && self.ica.is_none() {
|
|
||||||
warn!("enable_ica 为 true 但未填写 [ica] 配置\n将不启用 ica");
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
enable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
if self.ica.is_some() {
|
|
||||||
warn!("未填写 enable_ica 但填写了 [ica] 配置\n将不启用 ica");
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 检查是否启用 Tailchat
|
/// 检查是否启用 Tailchat
|
||||||
pub fn check_tailchat(&self) -> bool {
|
pub fn check_tailchat(&self) -> bool { self.enable_tailchat }
|
||||||
match self.enable_tailchat {
|
|
||||||
Some(enable) => {
|
|
||||||
if enable && self.tailchat.is_none() {
|
|
||||||
warn!("enable_tailchat 为 true 但未填写 [tailchat] 配置\n将不启用 Tailchat");
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
enable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
if self.tailchat.is_some() {
|
|
||||||
warn!("未填写 enable_tailchat 但填写了 [tailchat] 配置\n将不启用 Tailchat");
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 检查是否启用 Python 插件
|
/// 检查是否启用 Python 插件
|
||||||
pub fn check_py(&self) -> bool {
|
pub fn check_py(&self) -> bool { self.enable_py }
|
||||||
match self.enable_py {
|
|
||||||
Some(enable) => {
|
|
||||||
if enable && self.py.is_none() {
|
|
||||||
warn!("enable_py 为 true 但未填写 [py] 配置\n将不启用 Python 插件");
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
if self.py.is_some() {
|
|
||||||
warn!("未填写 enable_py 但填写了 [py] 配置\n将不启用 Python 插件");
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ica(&self) -> IcaConfig { self.ica.clone().expect("No ica config found") }
|
pub fn ica(&self) -> IcaConfig { self.ica.clone().expect("No ica config found") }
|
||||||
pub fn tailchat(&self) -> TailchatConfig {
|
pub fn tailchat(&self) -> TailchatConfig {
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use rust_socketio::asynchronous::Client;
|
use rust_socketio::asynchronous::Client;
|
||||||
use rust_socketio::{Event, Payload};
|
use rust_socketio::{Event, Payload};
|
||||||
@ -7,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::{py, MainStatus, ICA_VERSION, VERSION};
|
use crate::{py, version_str, MainStatus, VERSION};
|
||||||
|
|
||||||
/// 获取在线数据
|
/// 获取在线数据
|
||||||
pub async fn get_online_data(payload: Payload, _client: Client) {
|
pub async fn get_online_data(payload: Payload, _client: Client) {
|
||||||
@ -20,7 +22,7 @@ pub async fn get_online_data(payload: Payload, _client: Client) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::collapsible_if)]
|
// #[allow(clippy::collapsible_if)]
|
||||||
/// 接收消息
|
/// 接收消息
|
||||||
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 {
|
||||||
@ -36,12 +38,68 @@ pub async fn add_message(payload: Payload, client: Client) {
|
|||||||
// 之后的处理交给插件
|
// 之后的处理交给插件
|
||||||
if !message.is_from_self() && !message.is_reply() {
|
if !message.is_from_self() && !message.is_reply() {
|
||||||
if message.content() == "/bot-rs" {
|
if message.content() == "/bot-rs" {
|
||||||
|
let reply = message.reply_with(&version_str());
|
||||||
|
send_message(&client, &reply).await;
|
||||||
|
} else if message.content() == "/bot-ls" {
|
||||||
let reply = message.reply_with(&format!(
|
let reply = message.reply_with(&format!(
|
||||||
"shenbot v{}\nica-async-rs pong v{}",
|
"shenbot-py v{}\n{}",
|
||||||
VERSION, ICA_VERSION
|
VERSION,
|
||||||
|
if MainStatus::global_config().check_py() {
|
||||||
|
py::PyStatus::display()
|
||||||
|
} else {
|
||||||
|
"未启用 Python 插件".to_string()
|
||||||
|
}
|
||||||
));
|
));
|
||||||
send_message(&client, &reply).await;
|
send_message(&client, &reply).await;
|
||||||
}
|
}
|
||||||
|
if MainStatus::global_config().ica().admin_list.contains(&message.sender_id()) {
|
||||||
|
// admin 区
|
||||||
|
if message.content().starts_with("/bot-enable") {
|
||||||
|
// 先判定是否为 admin
|
||||||
|
// 尝试获取后面的信息
|
||||||
|
let mut content = message.content().split_whitespace();
|
||||||
|
content.next();
|
||||||
|
if let Some(name) = content.next() {
|
||||||
|
let path_name = PathBuf::from(name);
|
||||||
|
match py::PyStatus::get_status(&path_name) {
|
||||||
|
None => {
|
||||||
|
let reply = message.reply_with("未找到插件");
|
||||||
|
send_message(&client, &reply).await;
|
||||||
|
}
|
||||||
|
Some(true) => {
|
||||||
|
let reply = message.reply_with("无变化, 插件已经启用");
|
||||||
|
send_message(&client, &reply).await;
|
||||||
|
}
|
||||||
|
Some(false) => {
|
||||||
|
py::PyStatus::set_status(&path_name, true);
|
||||||
|
let reply = message.reply_with("启用插件完成");
|
||||||
|
send_message(&client, &reply).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if message.content().starts_with("/bot-disable") {
|
||||||
|
let mut content = message.content().split_whitespace();
|
||||||
|
content.next();
|
||||||
|
if let Some(name) = content.next() {
|
||||||
|
let path_name = PathBuf::from(name);
|
||||||
|
match py::PyStatus::get_status(&path_name) {
|
||||||
|
None => {
|
||||||
|
let reply = message.reply_with("未找到插件");
|
||||||
|
send_message(&client, &reply).await;
|
||||||
|
}
|
||||||
|
Some(false) => {
|
||||||
|
let reply = message.reply_with("无变化, 插件已经禁用");
|
||||||
|
send_message(&client, &reply).await;
|
||||||
|
}
|
||||||
|
Some(true) => {
|
||||||
|
py::PyStatus::set_status(&path_name, false);
|
||||||
|
let reply = message.reply_with("禁用插件完成");
|
||||||
|
send_message(&client, &reply).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// python 插件
|
// python 插件
|
||||||
py::call::ica_new_message_py(&message, &client).await;
|
py::call::ica_new_message_py(&message, &client).await;
|
||||||
|
@ -29,6 +29,17 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
|||||||
pub const ICA_VERSION: &str = "1.6.1";
|
pub const ICA_VERSION: &str = "1.6.1";
|
||||||
pub const TAILCHAT_VERSION: &str = "1.2.1";
|
pub const TAILCHAT_VERSION: &str = "1.2.1";
|
||||||
|
|
||||||
|
pub fn version_str() -> String {
|
||||||
|
format!(
|
||||||
|
"shenbot-rs v{}-{} ica v{}({}) tailchat v{}",
|
||||||
|
VERSION,
|
||||||
|
if STABLE { "" } else { "开发版" },
|
||||||
|
ICA_VERSION,
|
||||||
|
ica::ICA_PROTOCOL_VERSION,
|
||||||
|
TAILCHAT_VERSION,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// 是否为稳定版本
|
/// 是否为稳定版本
|
||||||
/// 会在 release 的时候设置为 true
|
/// 会在 release 的时候设置为 true
|
||||||
pub const STABLE: bool = false;
|
pub const STABLE: bool = false;
|
||||||
@ -54,7 +65,9 @@ macro_rules! async_any_callback_with_state {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() -> anyhow::Result<()> { inner_main().await }
|
||||||
|
|
||||||
|
async fn inner_main() -> anyhow::Result<()> {
|
||||||
// -d -> debug
|
// -d -> debug
|
||||||
// none -> info
|
// none -> info
|
||||||
let level = {
|
let level = {
|
||||||
@ -82,7 +95,9 @@ async fn main() {
|
|||||||
MainStatus::static_init(bot_config);
|
MainStatus::static_init(bot_config);
|
||||||
let bot_config = MainStatus::global_config();
|
let bot_config = MainStatus::global_config();
|
||||||
|
|
||||||
|
if bot_config.check_py() {
|
||||||
py::init_py();
|
py::init_py();
|
||||||
|
}
|
||||||
|
|
||||||
// 准备一个用于停止 socket 的变量
|
// 准备一个用于停止 socket 的变量
|
||||||
event!(Level::INFO, "启动 ICA");
|
event!(Level::INFO, "启动 ICA");
|
||||||
@ -120,9 +135,14 @@ async fn main() {
|
|||||||
tailchat_send.send(()).ok();
|
tailchat_send.send(()).ok();
|
||||||
|
|
||||||
event!(Level::INFO, "Disconnected");
|
event!(Level::INFO, "Disconnected");
|
||||||
|
|
||||||
|
py::post_py()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code, unused_variables)]
|
#[allow(dead_code, unused_variables)]
|
||||||
|
#[cfg(test)]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_macro() {
|
async fn test_macro() {
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
use std::{path::{Path, PathBuf}, str::FromStr};
|
use std::{
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
str::FromStr,
|
||||||
|
};
|
||||||
|
|
||||||
use toml_edit::{value, DocumentMut, Key, Table, TomlError, Value};
|
use toml_edit::{value, DocumentMut, Key, Table, TomlError, Value};
|
||||||
|
use tracing::{event, Level};
|
||||||
|
|
||||||
use crate::py::PyStatus;
|
use crate::py::PyStatus;
|
||||||
|
|
||||||
@ -18,7 +22,7 @@ pub struct PluginConfigFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const CONFIG_KEY: &str = "plugins";
|
const CONFIG_KEY: &str = "plugins";
|
||||||
pub const CONFIG_FILE_NAME: &str = "/plugins.toml";
|
pub const CONFIG_FILE_NAME: &str = "plugins.toml";
|
||||||
pub const DEFAULT_CONFIG: &str = r#"
|
pub const DEFAULT_CONFIG: &str = r#"
|
||||||
# 这个文件是由 shenbot 自动生成的, 请 **谨慎** 修改
|
# 这个文件是由 shenbot 自动生成的, 请 **谨慎** 修改
|
||||||
# 请不要修改这个文件, 除非你知道你在做什么
|
# 请不要修改这个文件, 除非你知道你在做什么
|
||||||
@ -34,6 +38,7 @@ impl PluginConfigFile {
|
|||||||
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, "插件配置文件不存在, 正在创建");
|
||||||
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 {
|
||||||
@ -44,6 +49,7 @@ impl PluginConfigFile {
|
|||||||
|
|
||||||
pub fn verify_and_init(&mut self) {
|
pub fn verify_and_init(&mut self) {
|
||||||
if self.data.get(CONFIG_KEY).is_none() {
|
if self.data.get(CONFIG_KEY).is_none() {
|
||||||
|
event!(Level::INFO, "插件配置文件缺少 plugins 字段, 正在初始化");
|
||||||
self.data.insert_formatted(
|
self.data.insert_formatted(
|
||||||
&Key::from_str(CONFIG_KEY).unwrap(),
|
&Key::from_str(CONFIG_KEY).unwrap(),
|
||||||
toml_edit::Item::Table(Table::new()),
|
toml_edit::Item::Table(Table::new()),
|
||||||
@ -88,7 +94,9 @@ impl PluginConfigFile {
|
|||||||
let plugins = PyStatus::get_map_mut();
|
let plugins = PyStatus::get_map_mut();
|
||||||
self.verify_and_init();
|
self.verify_and_init();
|
||||||
plugins.iter_mut().for_each(|(path, status)| {
|
plugins.iter_mut().for_each(|(path, status)| {
|
||||||
status.enabled = self.get_status(path);
|
let config_status = self.get_status(path);
|
||||||
|
event!(Level::INFO, "插件状态: {:?} {} -> {}", path, status.enabled, config_status);
|
||||||
|
status.enabled = config_status;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +111,8 @@ impl PluginConfigFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_to_file(&self, path: &PathBuf) -> Result<(), std::io::Error> {
|
pub fn write_to_file(&self, path: &PathBuf) -> Result<(), std::io::Error> {
|
||||||
std::fs::write(path, self.data.to_string())?;
|
let config_path = path.join(CONFIG_FILE_NAME);
|
||||||
|
std::fs::write(config_path, self.data.to_string())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ impl PyStatus {
|
|||||||
PYSTATUS.files = Some(HashMap::new());
|
PYSTATUS.files = Some(HashMap::new());
|
||||||
}
|
}
|
||||||
if PYSTATUS.config.is_none() {
|
if PYSTATUS.config.is_none() {
|
||||||
let plugin_path = MainStatus::global_config().py().plugin_path;
|
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();
|
||||||
@ -93,18 +93,27 @@ impl PyStatus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_status(path: &Path) -> bool { Self::get_config().get_status(path) }
|
/// 获取某个插件的状态
|
||||||
|
/// 以 config 优先
|
||||||
|
pub fn get_status(path: &PathBuf) -> Option<bool> {
|
||||||
|
Self::get_config_mut().sync_status_from_config();
|
||||||
|
Self::get_map().get(path).map(|plugin| plugin.enabled)
|
||||||
|
}
|
||||||
|
|
||||||
// pub fn list_plugins() -> Vec<PathBuf> { Self::get_map().keys().cloned().collect() }
|
pub fn set_status(path: &Path, status: bool) {
|
||||||
|
let cfg = Self::get_config_mut();
|
||||||
|
cfg.set_status(path, status);
|
||||||
|
cfg.sync_status_from_config();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn display() -> String {
|
pub fn display() -> String {
|
||||||
let map = Self::get_map();
|
let map = Self::get_map();
|
||||||
format!(
|
format!(
|
||||||
"Python 插件 {{ {} }}",
|
"Python 插件 {{ {} }}",
|
||||||
map.iter()
|
map.iter()
|
||||||
.map(|(k, v)| format!("{:?}: {:?}", k, v))
|
.map(|(k, v)| format!("{:?}-{}", k, v.enabled))
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
.join(", ")
|
.join("\n")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -161,7 +170,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_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) => {
|
||||||
@ -343,7 +352,7 @@ pub fn load_py_plugins(path: &PathBuf) {
|
|||||||
// 搜索所有的 py 文件 和 文件夹单层下面的 py 文件
|
// 搜索所有的 py 文件 和 文件夹单层下面的 py 文件
|
||||||
match path.read_dir() {
|
match path.read_dir() {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
event!(Level::WARN, "failed to read plugin path: {:?}", e);
|
event!(Level::WARN, "读取插件路径失败 {:?}", e);
|
||||||
}
|
}
|
||||||
Ok(dir) => {
|
Ok(dir) => {
|
||||||
for entry in dir {
|
for entry in dir {
|
||||||
@ -413,3 +422,10 @@ pub fn init_py() {
|
|||||||
|
|
||||||
info!("python inited")
|
info!("python inited")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn post_py() -> anyhow::Result<()> {
|
||||||
|
PyStatus::get_config_mut().sync_status_to_config();
|
||||||
|
PyStatus::get_config()
|
||||||
|
.write_to_file(&PathBuf::from(MainStatus::global_config().py().config_path))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
@ -8,6 +9,7 @@ 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::{py, MainStatus, TAILCHAT_VERSION, VERSION};
|
||||||
|
|
||||||
/// 所有
|
/// 所有
|
||||||
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>) {
|
||||||
@ -61,7 +63,6 @@ pub async fn any_event(event: Event, payload: Payload, _client: Client, _status:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::collapsible_if)]
|
|
||||||
pub async fn on_message(payload: Payload, client: Client, _status: Arc<BotStatus>) {
|
pub async fn on_message(payload: Payload, client: Client, _status: Arc<BotStatus>) {
|
||||||
if let Payload::Text(values) = payload {
|
if let Payload::Text(values) = payload {
|
||||||
if let Some(value) = values.first() {
|
if let Some(value) = values.first() {
|
||||||
@ -79,13 +80,71 @@ pub async fn on_message(payload: Payload, client: Client, _status: Arc<BotStatus
|
|||||||
if message.content == "/bot-rs" {
|
if message.content == "/bot-rs" {
|
||||||
let reply = message.reply_with(&format!(
|
let reply = message.reply_with(&format!(
|
||||||
"shenbot v{}\ntailchat-async-rs pong v{}",
|
"shenbot v{}\ntailchat-async-rs pong v{}",
|
||||||
crate::VERSION,
|
VERSION, TAILCHAT_VERSION
|
||||||
crate::TAILCHAT_VERSION
|
));
|
||||||
|
send_message(&client, &reply).await;
|
||||||
|
} else if message.content == "/bot-ls" {
|
||||||
|
let reply = message.reply_with(&format!(
|
||||||
|
"shenbot-py v{}\n{}",
|
||||||
|
VERSION,
|
||||||
|
if MainStatus::global_config().check_py() {
|
||||||
|
py::PyStatus::display()
|
||||||
|
} else {
|
||||||
|
"未启用 Python 插件".to_string()
|
||||||
|
}
|
||||||
));
|
));
|
||||||
send_message(&client, &reply).await;
|
send_message(&client, &reply).await;
|
||||||
}
|
}
|
||||||
|
if MainStatus::global_config().tailchat().admin_list.contains(&message.sender_id) {
|
||||||
|
// admin 区
|
||||||
|
if message.content.starts_with("/bot-enable") {
|
||||||
|
// 先判定是否为 admin
|
||||||
|
// 尝试获取后面的信息
|
||||||
|
let mut content = message.content.split_whitespace();
|
||||||
|
content.next();
|
||||||
|
if let Some(name) = content.next() {
|
||||||
|
let path_name = PathBuf::from(name);
|
||||||
|
match py::PyStatus::get_status(&path_name) {
|
||||||
|
None => {
|
||||||
|
let reply = message.reply_with("未找到插件");
|
||||||
|
send_message(&client, &reply).await;
|
||||||
}
|
}
|
||||||
crate::py::call::tailchat_new_message_py(&message, &client).await;
|
Some(true) => {
|
||||||
|
let reply = message.reply_with("无变化, 插件已经启用");
|
||||||
|
send_message(&client, &reply).await;
|
||||||
|
}
|
||||||
|
Some(false) => {
|
||||||
|
py::PyStatus::set_status(&path_name, true);
|
||||||
|
let reply = message.reply_with("启用插件完成");
|
||||||
|
send_message(&client, &reply).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if message.content.starts_with("/bot-disable") {
|
||||||
|
let mut content = message.content.split_whitespace();
|
||||||
|
content.next();
|
||||||
|
if let Some(name) = content.next() {
|
||||||
|
let path_name = PathBuf::from(name);
|
||||||
|
match py::PyStatus::get_status(&path_name) {
|
||||||
|
None => {
|
||||||
|
let reply = message.reply_with("未找到插件");
|
||||||
|
send_message(&client, &reply).await;
|
||||||
|
}
|
||||||
|
Some(false) => {
|
||||||
|
let reply = message.reply_with("无变化, 插件已经禁用");
|
||||||
|
send_message(&client, &reply).await;
|
||||||
|
}
|
||||||
|
Some(true) => {
|
||||||
|
py::PyStatus::set_status(&path_name, false);
|
||||||
|
let reply = message.reply_with("禁用插件完成");
|
||||||
|
send_message(&client, &reply).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
py::call::tailchat_new_message_py(&message, &client).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
13
news.md
13
news.md
@ -1,6 +1,9 @@
|
|||||||
# 更新日志
|
# 更新日志
|
||||||
|
|
||||||
## 0.6.11
|
## 0.7.0
|
||||||
|
|
||||||
|
> 我决定叫他 0.7.0
|
||||||
|
> 因为修改太多了.png
|
||||||
|
|
||||||
- 加入了 禁用/启用 插件功能
|
- 加入了 禁用/启用 插件功能
|
||||||
- 现在会在插件加载时警告你的插件原来定义了 `CONFIG_DATA` 这一项
|
- 现在会在插件加载时警告你的插件原来定义了 `CONFIG_DATA` 这一项
|
||||||
@ -8,6 +11,14 @@
|
|||||||
- `get_sender_name` 获取发送人昵称
|
- `get_sender_name` 获取发送人昵称
|
||||||
- `ica` 兼容版本号 `2.12.11` -> `2.12.12`
|
- `ica` 兼容版本号 `2.12.11` -> `2.12.12`
|
||||||
- 加入了 `STABLE` 信息, 用于标记稳定版本
|
- 加入了 `STABLE` 信息, 用于标记稳定版本
|
||||||
|
- 添加了 `version_str() -> String` 用于方便的获取版本信息
|
||||||
|
- 同样在 `py` 侧也有 `version_str` 方法
|
||||||
|
- 加入了 `/help` 命令
|
||||||
|
- 用于获取帮助信息
|
||||||
|
- 加入了 `/bot-ls`
|
||||||
|
- 用于展示所有插件的信息
|
||||||
|
- 加入了 `/bot-enable` 和 `/bot-disable`
|
||||||
|
- 用于启用/禁用插件
|
||||||
|
|
||||||
## 0.6.10
|
## 0.6.10
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user