好歹过编译+test了……

This commit is contained in:
shenjack 2024-02-22 02:40:39 +08:00
parent 9ce466f000
commit 974368166b
Signed by: shenjack
GPG Key ID: 7B1134A979775551
6 changed files with 132 additions and 42 deletions

View File

@ -20,12 +20,13 @@ colored = "2.1.0"
tokio = { version = "1.0", features = ["full"] } tokio = { version = "1.0", features = ["full"] }
futures-util = "0.3.30" futures-util = "0.3.30"
pyo3 = "0.20.2"
# pyo3-async = "0.3.2"
pyo3-asyncio = { version = "0.20.0", features = ["attributes", "tokio-runtime"] }
tracing = "0.1.40" tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18", features = ["time"] } tracing-subscriber = { version = "0.3.18", features = ["time"] }
[dependencies.pyo3]
version = "0.20.2"
[patch.crates-io] [patch.crates-io]
rust_socketio = { git = "https://github.com/shenjackyuanjie/rust-socketio.git", branch = "mult_payload" } rust_socketio = { git = "https://github.com/shenjackyuanjie/rust-socketio.git", branch = "mult_payload" }
# pyo3 = { git = "https://github.com/PyO3/pyo3.git", branch = "main" }

View File

@ -44,3 +44,9 @@ class SendMessage:
class NewMessage: class NewMessage:
def reply_with(self, message: str) -> SendMessage: def reply_with(self, message: str) -> SendMessage:
... ...
class IcaClient:
@staticmethod
async def send_message(client: "IcaClient", message: SendMessage) -> bool:
...

View File

@ -11,11 +11,17 @@ use serde_json::Value;
use tracing::{debug, warn}; use tracing::{debug, warn};
/// "安全" 的 发送一条消息 /// "安全" 的 发送一条消息
pub async fn send_message(client: Client, message: SendMessage) { pub async fn send_message(client: &Client, message: &SendMessage) -> bool {
let value = message.as_value(); let value = message.as_value();
match client.emit("sendMessage", value).await { match client.emit("sendMessage", value).await {
Ok(_) => debug!("send_message {}", format!("{:#?}", message).cyan()), Ok(_) => {
Err(e) => warn!("send_message faild:{}", format!("{:#?}", e).red()), debug!("send_message {}", format!("{:#?}", message).cyan());
true
}
Err(e) => {
warn!("send_message faild:{}", format!("{:#?}", e).red());
false
}
} }
} }

View File

@ -41,7 +41,7 @@ pub async fn add_message(payload: Payload, client: Client) {
// 之后的处理交给插件 // 之后的处理交给插件
if message.content.eq("/bot-rs") { if message.content.eq("/bot-rs") {
let reply = message.reply_with(&format!("ica-async-rs pong v{}", VERSION)); let reply = message.reply_with(&format!("ica-async-rs pong v{}", VERSION));
send_message(client, reply).await; send_message(&client, &reply).await;
} }
} }
} }

View File

@ -1,5 +1,7 @@
use pyo3::prelude::*; use pyo3::prelude::*;
use rust_socketio::asynchronous::Client;
use crate::client::send_message;
use crate::data_struct::messages::{NewMessage, ReplyMessage, SendMessage}; use crate::data_struct::messages::{NewMessage, ReplyMessage, SendMessage};
use crate::ClientStatus; use crate::ClientStatus;
@ -137,6 +139,7 @@ impl ReplyMessagePy {
} }
} }
#[derive(Clone)]
#[pyclass] #[pyclass]
#[pyo3(name = "SendMessage")] #[pyo3(name = "SendMessage")]
pub struct SendMessagePy { pub struct SendMessagePy {
@ -148,3 +151,36 @@ impl SendMessagePy {
Self { msg } Self { msg }
} }
} }
#[derive(Clone)]
#[pyclass]
#[pyo3(name = "IcaClient")]
pub struct IcaClientPy {
pub client: Client,
}
#[pymethods]
impl IcaClientPy {
// fn send_message(&self, message: SendMessagePy) -> bool {
// // Some(send_message(&self.client, &message.msg).await)
// true
// // // Ok(send_message(&self.client, &message.msg).await)
// // let mut future;
// // Python::with_gil(|gil| {
// // let this = self_.borrow(gil);
// // future = send_message(&this.client, &message.msg);
// // });
// // Ok(future.await)
// }
#[staticmethod]
pub fn send_message(
py: Python,
client: IcaClientPy,
message: SendMessagePy,
) -> PyResult<&PyAny> {
// send_message(&client.client, &message.msg).await
pyo3_asyncio::tokio::future_into_py(py, async move {
Ok(send_message(&client.client, &message.msg).await)
})
}
}

View File

@ -1,20 +1,22 @@
pub mod class; pub mod class;
use std::time::SystemTime;
use std::{collections::HashMap, path::PathBuf}; use std::{collections::HashMap, path::PathBuf};
use blake3::Hasher;
use pyo3::{prelude::*, types::IntoPyDict}; use pyo3::{prelude::*, types::IntoPyDict};
use rust_socketio::asynchronous::Client;
use tracing::{debug, info, warn}; use tracing::{debug, info, warn};
use crate::config::IcaConfig; use crate::config::IcaConfig;
use crate::data_struct::messages::NewMessage;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct PyStatus { pub struct PyStatus {
pub files: Option<HashMap<PathBuf, (Vec<u8>, String)>>, pub files: Option<HashMap<PathBuf, (Option<SystemTime>, Py<PyAny>)>>,
} }
impl PyStatus { impl PyStatus {
pub fn get_files() -> &'static HashMap<PathBuf, (Vec<u8>, String)> { pub fn get_files() -> &'static HashMap<PathBuf, (Option<SystemTime>, Py<PyAny>)> {
unsafe { unsafe {
match PYSTATUS.files.as_ref() { match PYSTATUS.files.as_ref() {
Some(files) => files, Some(files) => files,
@ -27,26 +29,26 @@ impl PyStatus {
} }
} }
pub fn add_file(path: PathBuf, content: Vec<u8>, hash: String) { pub fn add_file(path: PathBuf, changed_time: Option<SystemTime>, py_module: Py<PyAny>) {
unsafe { unsafe {
match PYSTATUS.files.as_mut() { match PYSTATUS.files.as_mut() {
Some(files) => { Some(files) => {
files.insert(path, (content, hash)); files.insert(path, (changed_time, py_module));
} }
None => { None => {
let mut files = HashMap::new(); let mut files = HashMap::new();
files.insert(path, (content, hash)); files.insert(path, (changed_time, py_module));
PYSTATUS.files = Some(files); PYSTATUS.files = Some(files);
} }
} }
} }
} }
pub fn verify_file(path: &PathBuf, hash: &String) -> bool { pub fn verify_file(path: &PathBuf, change_time: &Option<SystemTime>) -> bool {
unsafe { unsafe {
match PYSTATUS.files.as_ref() { match PYSTATUS.files.as_ref() {
Some(files) => match files.get(path) { Some(files) => match files.get(path) {
Some((_, file_hash)) => file_hash == hash, Some((changed_time, _)) => change_time == changed_time,
None => false, None => false,
}, },
None => false, None => false,
@ -72,19 +74,7 @@ pub fn run() {
}); });
} }
pub fn load_py_file(path: &PathBuf) -> (Vec<u8>, String) { pub fn load_py_plugins(path: &PathBuf) {
let mut hasher = Hasher::new();
let content = std::fs::read(path).unwrap();
hasher.update(&content);
let hash = hasher.finalize().as_bytes().to_vec();
(content, hex::encode(hash))
}
pub fn init_py(config: &IcaConfig) {
debug!("initing python threads");
pyo3::prepare_freethreaded_python();
if let Some(plugin_path) = &config.py_plugin_path {
let path = PathBuf::from(plugin_path);
if path.exists() { if path.exists() {
info!("finding plugins in: {:?}", path); info!("finding plugins in: {:?}", path);
// 搜索所有的 py 文件 和 文件夹单层下面的 py 文件 // 搜索所有的 py 文件 和 文件夹单层下面的 py 文件
@ -97,7 +87,27 @@ pub fn init_py(config: &IcaConfig) {
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" {
match load_py_file(&path) {
Ok((changed_time, content)) => {
let py_module = Python::with_gil(|py| -> Py<PyAny> {
let module: Py<PyAny> = PyModule::from_code(
py,
&content,
&path.to_string_lossy(),
"",
)
.unwrap()
.into();
module
});
PyStatus::add_file(path, changed_time, py_module);
}
Err(e) => {
warn!("failed to load file: {:?} | e: {:?}", path, e);
}
}
}
} }
} }
} }
@ -106,7 +116,38 @@ pub fn init_py(config: &IcaConfig) {
} else { } else {
warn!("plugin path not exists: {:?}", path); warn!("plugin path not exists: {:?}", path);
} }
info!(
"python 插件目录: {:?} 加载完成, 加载到 {} 个插件",
path,
PyStatus::get_files().len()
);
}
pub fn get_change_time(path: &PathBuf) -> Option<SystemTime> {
path.metadata().ok()?.modified().ok()
}
/// 传入文件路径
/// 返回 hash 和 文件内容
pub fn load_py_file(path: &PathBuf) -> std::io::Result<(Option<SystemTime>, String)> {
let changed_time = get_change_time(&path);
let content = std::fs::read_to_string(path)?;
Ok((changed_time, content))
}
pub fn init_py(config: &IcaConfig) {
debug!("initing python threads");
pyo3::prepare_freethreaded_python();
if let Some(plugin_path) = &config.py_plugin_path {
let path = PathBuf::from(plugin_path);
load_py_plugins(&path);
debug!("python 插件列表: {:#?}", PyStatus::get_files());
} }
info!("python inited") info!("python inited")
} }
/// 执行 new message 的 python 插件
pub fn new_message_py(message: &NewMessage, client: &Client) {
let msg = class::NewMessagePy::new(message);
}