进行一个 clicppy

This commit is contained in:
shenjack 2024-03-13 01:20:41 +08:00
parent f6e760e234
commit 0843826435
Signed by: shenjack
GPG Key ID: 7B1134A979775551
9 changed files with 38 additions and 33 deletions

View File

@ -61,7 +61,7 @@ impl BotConfig {
// try read config from file // try read config from file
let config = fs::read_to_string(&config_file_path).expect("Failed to read config file"); let config = fs::read_to_string(&config_file_path).expect("Failed to read config file");
let ret: Self = from_str(&config) let ret: Self = from_str(&config)
.expect(format!("Failed to parse config file {}", &config_file_path).as_str()); .unwrap_or_else(|_| panic!("Failed to parse config file {}", &config_file_path));
ret ret
} }
pub fn new_from_cli() -> Self { pub fn new_from_cli() -> Self {
@ -74,7 +74,7 @@ impl BotConfig {
match self.enable_ica { match self.enable_ica {
Some(enable) => { Some(enable) => {
if enable { if enable {
if let None = self.ica { if self.ica.is_none() {
warn!("enable_ica 为 true 但未填写 [ica] 配置\n将不启用 ica"); warn!("enable_ica 为 true 但未填写 [ica] 配置\n将不启用 ica");
false false
} else { } else {
@ -85,7 +85,7 @@ impl BotConfig {
} }
} }
None => { None => {
if let Some(_) = self.ica { if self.ica.is_some() {
warn!("未填写 enable_ica 但填写了 [ica] 配置\n将不启用 ica"); warn!("未填写 enable_ica 但填写了 [ica] 配置\n将不启用 ica");
} }
false false
@ -98,7 +98,7 @@ impl BotConfig {
match self.enable_matrix { match self.enable_matrix {
Some(enable) => { Some(enable) => {
if enable { if enable {
if let None = self.matrix { if self.matrix.is_none() {
warn!("enable_matrix 为 true 但未填写 [matrix] 配置\n将不启用 Matrix"); warn!("enable_matrix 为 true 但未填写 [matrix] 配置\n将不启用 Matrix");
false false
} else { } else {
@ -109,7 +109,7 @@ impl BotConfig {
} }
} }
None => { None => {
if let Some(_) = self.matrix { if self.matrix.is_some() {
warn!("未填写 enable_matrix 但填写了 [matrix] 配置\n将不启用 Matrix"); warn!("未填写 enable_matrix 但填写了 [matrix] 配置\n将不启用 Matrix");
} }
false false

View File

@ -24,7 +24,7 @@ impl IcalinguaInfo {
let mut load = None; let mut load = None;
let mut server_node = None; let mut server_node = None;
let mut client_count = None; let mut client_count = None;
let info_list = s.split("\n").collect::<Vec<&str>>(); let info_list = s.split('\n').collect::<Vec<&str>>();
for info in info_list { for info in info_list {
if info.starts_with("icalingua-bridge-oicq") { if info.starts_with("icalingua-bridge-oicq") {
ica_version = Some(info.split_at(22).1.to_string()); ica_version = Some(info.split_at(22).1.to_string());
@ -40,9 +40,9 @@ impl IcalinguaInfo {
server_node = Some(info.split_at(12).1.to_string()); server_node = Some(info.split_at(12).1.to_string());
} else if info.ends_with("clients connected") { } else if info.ends_with("clients connected") {
client_count = Some( client_count = Some(
info.split(" ") info.split(' ')
.collect::<Vec<&str>>() .collect::<Vec<&str>>()
.get(0) .first()
.unwrap_or(&"1") .unwrap_or(&"1")
.parse::<u16>() .parse::<u16>()
.unwrap_or_else(|e| { .unwrap_or_else(|e| {
@ -194,7 +194,7 @@ mod tests {
})); }));
assert_eq!(online_data.bkn, 123); assert_eq!(online_data.bkn, 123);
assert_eq!(online_data.nick, "test"); assert_eq!(online_data.nick, "test");
assert_eq!(online_data.online, true); assert!(online_data.online);
assert_eq!(online_data.qqid, 123456); assert_eq!(online_data.qqid, 123456);
assert_eq!(online_data.icalingua_info.ica_version, "2.11.1"); assert_eq!(online_data.icalingua_info.ica_version, "2.11.1");
assert_eq!(online_data.icalingua_info.os_info, "Linux c038fad79f13 4.4.302+"); assert_eq!(online_data.icalingua_info.os_info, "Linux c038fad79f13 4.4.302+");
@ -210,7 +210,7 @@ mod tests {
let online_data = OnlineData::new_from_json(&serde_json::json!({})); let online_data = OnlineData::new_from_json(&serde_json::json!({}));
assert_eq!(online_data.bkn, -1); assert_eq!(online_data.bkn, -1);
assert_eq!(online_data.nick, "UNKNOWN"); assert_eq!(online_data.nick, "UNKNOWN");
assert_eq!(online_data.online, false); assert!(!online_data.online);
assert_eq!(online_data.qqid, -1); assert_eq!(online_data.qqid, -1);
assert_eq!(online_data.icalingua_info.ica_version, "UNKNOWN"); assert_eq!(online_data.icalingua_info.ica_version, "UNKNOWN");
assert_eq!(online_data.icalingua_info.os_info, "UNKNOWN"); assert_eq!(online_data.icalingua_info.os_info, "UNKNOWN");

View File

@ -34,7 +34,7 @@ pub async fn start_ica(config: &IcaConfig, stop_reciver: tokio::sync::oneshot::R
for room in config.notice_room.iter() { for room in config.notice_room.iter() {
let startup_msg = crate::data_struct::ica::messages::SendMessage::new( let startup_msg = crate::data_struct::ica::messages::SendMessage::new(
format!("ica-async-rs bot v{}", crate::VERSION), format!("ica-async-rs bot v{}", crate::VERSION),
room.clone(), *room,
None, None,
); );
tokio::time::sleep(std::time::Duration::from_secs(1)).await; tokio::time::sleep(std::time::Duration::from_secs(1)).await;

View File

@ -56,6 +56,10 @@ pub struct BotStatus {
pub config: Option<BotConfig>, pub config: Option<BotConfig>,
} }
impl Default for BotStatus {
fn default() -> Self { Self::new() }
}
impl BotStatus { impl BotStatus {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
@ -139,7 +143,7 @@ pub async fn sign_callback(payload: Payload, client: Client) {
let (auth_key, version) = (&require_data[0], &require_data[1]); let (auth_key, version) = (&require_data[0], &require_data[1]);
debug!("auth_key: {:?}, version: {:?}", auth_key, version); debug!("auth_key: {:?}, version: {:?}", auth_key, version);
let auth_key = match &require_data.get(0) { let auth_key = match &require_data.first() {
Some(Value::String(auth_key)) => Some(auth_key), Some(Value::String(auth_key)) => Some(auth_key),
_ => None, _ => None,
} }

View File

@ -62,7 +62,7 @@ pub async fn delete_message(payload: Payload, client: Client) {
// 消息 id // 消息 id
if let Some(value) = values.first() { if let Some(value) = values.first() {
if let Some(msg_id) = value.as_str() { if let Some(msg_id) = value.as_str() {
info!("delete_message {}", format!("{}", msg_id).yellow()); info!("delete_message {}", msg_id.to_string().yellow());
py::call::delete_message_py(msg_id.to_string(), &client).await; py::call::delete_message_py(msg_id.to_string(), &client).await;
} }
@ -74,8 +74,7 @@ pub async fn update_all_room(payload: Payload, _client: Client) {
if let Payload::Text(values) = payload { if let Payload::Text(values) = payload {
if let Some(value) = values.first() { if let Some(value) = values.first() {
if let Some(raw_rooms) = value.as_array() { if let Some(raw_rooms) = value.as_array() {
let rooms: Vec<Room> = let rooms: Vec<Room> = raw_rooms.iter().map(Room::new_from_json).collect();
raw_rooms.iter().map(|room| Room::new_from_json(room)).collect();
BotStatus::update_rooms(rooms.clone()); BotStatus::update_rooms(rooms.clone());
info!("update_all_room {}", rooms.len()); info!("update_all_room {}", rooms.len());
} }
@ -151,7 +150,7 @@ pub async fn any_event(event: Event, payload: Payload, _client: Client) {
Payload::Text(ref data) => { Payload::Text(ref data) => {
print!("event: {}", event.as_str().purple()); print!("event: {}", event.as_str().purple());
for value in data { for value in data {
println!("|{}", value.to_string()); println!("|{}", value);
} }
} }
_ => (), _ => (),

View File

@ -8,7 +8,7 @@ mod ica;
mod matrix; mod matrix;
mod py; mod py;
use config::{BotConfig, IcaConfig}; use config::BotConfig;
use tracing::info; use tracing::info;
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]

View File

@ -46,23 +46,21 @@ pub fn get_func<'py>(py_module: &'py PyAny, path: &PathBuf, name: &'py str) -> O
pub fn verify_plugins() { pub fn verify_plugins() {
let mut need_reload_files: Vec<PathBuf> = Vec::new(); let mut need_reload_files: Vec<PathBuf> = Vec::new();
let plugin_path = BotStatus::get_config().py_plugin_path.as_ref(); let plugin_path = BotStatus::get_config().py_plugin_path.as_ref();
if let None = plugin_path { if plugin_path.is_none() {
warn!("未配置 Python 插件路径"); warn!("未配置 Python 插件路径");
return; return;
} }
let plugin_path = plugin_path.unwrap(); let plugin_path = plugin_path.unwrap();
for entry in std::fs::read_dir(&plugin_path).unwrap() { for entry in std::fs::read_dir(plugin_path).unwrap() {
if let Ok(entry) = entry { if let Ok(entry) = entry {
let path = entry.path(); let path = entry.path();
if let Some(ext) = path.extension() { if let Some(ext) = path.extension() {
if ext == "py" { if ext == "py" && !PyStatus::verify_file(&path) {
if !PyStatus::verify_file(&path) {
need_reload_files.push(path); need_reload_files.push(path);
} }
} }
} }
} }
}
if need_reload_files.is_empty() { if need_reload_files.is_empty() {
return; return;
@ -94,7 +92,7 @@ pub async fn new_message_py(message: &NewMessage, client: &Client) {
// 甚至实际上压根不需要await这个spawn, 直接让他自己跑就好了(离谱) // 甚至实际上压根不需要await这个spawn, 直接让他自己跑就好了(离谱)
tokio::spawn(async move { tokio::spawn(async move {
Python::with_gil(|py| { Python::with_gil(|py| {
if let Some(py_func) = get_func(plugin.py_module.as_ref(py), &path, "on_message") { if let Some(py_func) = get_func(plugin.py_module.as_ref(py), path, "on_message") {
if let Err(e) = py_func.call1(args) { if let Err(e) = py_func.call1(args) {
warn!("failed to call function<on_message>: {:?}", e); warn!("failed to call function<on_message>: {:?}", e);
} }
@ -115,7 +113,7 @@ pub async fn delete_message_py(msg_id: MessageId, client: &Client) {
tokio::spawn(async move { tokio::spawn(async move {
Python::with_gil(|py| { Python::with_gil(|py| {
if let Some(py_func) = if let Some(py_func) =
get_func(plugin.py_module.as_ref(py), &path, "on_delete_message") get_func(plugin.py_module.as_ref(py), path, "on_delete_message")
{ {
if let Err(e) = py_func.call1(args) { if let Err(e) = py_func.call1(args) {
warn!("failed to call function<on_delete_message>: {:?}", e); warn!("failed to call function<on_delete_message>: {:?}", e);

View File

@ -53,6 +53,10 @@ impl IcaStatusPy {
pub fn get_load(&self) -> String { BotStatus::get_online_data().icalingua_info.load.clone() } pub fn get_load(&self) -> String { BotStatus::get_online_data().icalingua_info.load.clone() }
} }
impl Default for IcaStatusPy {
fn default() -> Self { Self::new() }
}
impl IcaStatusPy { impl IcaStatusPy {
pub fn new() -> Self { Self {} } pub fn new() -> Self { Self {} }
} }

View File

@ -8,7 +8,7 @@ use pyo3::prelude::*;
use pyo3::types::PyTuple; use pyo3::types::PyTuple;
use tracing::{debug, info, warn}; use tracing::{debug, info, warn};
use crate::config::{BotConfig, IcaConfig}; use crate::config::BotConfig;
use crate::ica::client::BotStatus; use crate::ica::client::BotStatus;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -28,7 +28,7 @@ pub struct PyPlugin {
impl PyPlugin { impl PyPlugin {
pub fn new_from_path(path: &PathBuf) -> Option<Self> { pub fn new_from_path(path: &PathBuf) -> Option<Self> {
let raw_file = load_py_file(&path); let raw_file = load_py_file(path);
match raw_file { match raw_file {
Ok(raw_file) => match Self::try_from(raw_file) { Ok(raw_file) => match Self::try_from(raw_file) {
Ok(plugin) => Some(plugin), Ok(plugin) => Some(plugin),
@ -122,9 +122,9 @@ impl TryFrom<RawPyPlugin> for PyPlugin {
"加载 Python 插件 {:?} 的配置文件信息时失败:返回的不是 [str, str]", "加载 Python 插件 {:?} 的配置文件信息时失败:返回的不是 [str, str]",
path path
); );
Err(PyErr::new::<pyo3::exceptions::PyTypeError, _>(format!( Err(PyErr::new::<pyo3::exceptions::PyTypeError, _>(
"返回的不是 [str, str]" "返回的不是 [str, str]".to_string(),
))) ))
} }
} }
Err(e) => { Err(e) => {
@ -186,7 +186,7 @@ impl PyStatus {
pub static mut PYSTATUS: PyStatus = PyStatus { files: None }; pub static mut PYSTATUS: PyStatus = PyStatus { files: None };
pub fn load_py_plugins(path: &PathBuf) -> () { pub fn load_py_plugins(path: &PathBuf) {
if path.exists() { if path.exists() {
info!("finding plugins in: {:?}", path); info!("finding plugins in: {:?}", path);
// 搜索所有的 py 文件 和 文件夹单层下面的 py 文件 // 搜索所有的 py 文件 和 文件夹单层下面的 py 文件
@ -226,7 +226,7 @@ pub fn py_module_from_code(content: &str, path: &PathBuf) -> PyResult<Py<PyAny>>
Python::with_gil(|py| -> PyResult<Py<PyAny>> { Python::with_gil(|py| -> PyResult<Py<PyAny>> {
let module: PyResult<Py<PyAny>> = PyModule::from_code( let module: PyResult<Py<PyAny>> = PyModule::from_code(
py, py,
&content, content,
&path.to_string_lossy(), &path.to_string_lossy(),
&path.file_name().unwrap().to_string_lossy(), &path.file_name().unwrap().to_string_lossy(),
// !!!! 请注意, 一定要给他一个名字, cpython 会自动把后面的重名模块覆盖掉前面的 // !!!! 请注意, 一定要给他一个名字, cpython 会自动把后面的重名模块覆盖掉前面的
@ -239,7 +239,7 @@ pub fn py_module_from_code(content: &str, path: &PathBuf) -> PyResult<Py<PyAny>>
/// 传入文件路径 /// 传入文件路径
/// 返回 hash 和 文件内容 /// 返回 hash 和 文件内容
pub fn load_py_file(path: &PathBuf) -> std::io::Result<RawPyPlugin> { pub fn load_py_file(path: &PathBuf) -> std::io::Result<RawPyPlugin> {
let changed_time = get_change_time(&path); let changed_time = get_change_time(path);
let content = std::fs::read_to_string(path)?; let content = std::fs::read_to_string(path)?;
Ok((path.clone(), changed_time, content)) Ok((path.clone(), changed_time, content))
} }