mirror of
http://shenjack.top:5100/shenjack/icalingua-python-bot.git
synced 2024-11-23 12:41:05 +08:00
好歹过编译+test了……
This commit is contained in:
parent
9ce466f000
commit
974368166b
|
@ -20,12 +20,13 @@ colored = "2.1.0"
|
|||
|
||||
tokio = { version = "1.0", features = ["full"] }
|
||||
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-subscriber = { version = "0.3.18", features = ["time"] }
|
||||
|
||||
[dependencies.pyo3]
|
||||
version = "0.20.2"
|
||||
|
||||
[patch.crates-io]
|
||||
rust_socketio = { git = "https://github.com/shenjackyuanjie/rust-socketio.git", branch = "mult_payload" }
|
||||
# pyo3 = { git = "https://github.com/PyO3/pyo3.git", branch = "main" }
|
||||
|
|
|
@ -44,3 +44,9 @@ class SendMessage:
|
|||
class NewMessage:
|
||||
def reply_with(self, message: str) -> SendMessage:
|
||||
...
|
||||
|
||||
|
||||
class IcaClient:
|
||||
@staticmethod
|
||||
async def send_message(client: "IcaClient", message: SendMessage) -> bool:
|
||||
...
|
||||
|
|
|
@ -11,11 +11,17 @@ use serde_json::Value;
|
|||
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();
|
||||
match client.emit("sendMessage", value).await {
|
||||
Ok(_) => debug!("send_message {}", format!("{:#?}", message).cyan()),
|
||||
Err(e) => warn!("send_message faild:{}", format!("{:#?}", e).red()),
|
||||
Ok(_) => {
|
||||
debug!("send_message {}", format!("{:#?}", message).cyan());
|
||||
true
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("send_message faild:{}", format!("{:#?}", e).red());
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ pub async fn add_message(payload: Payload, client: Client) {
|
|||
// 之后的处理交给插件
|
||||
if message.content.eq("/bot-rs") {
|
||||
let reply = message.reply_with(&format!("ica-async-rs pong v{}", VERSION));
|
||||
send_message(client, reply).await;
|
||||
send_message(&client, &reply).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use pyo3::prelude::*;
|
||||
use rust_socketio::asynchronous::Client;
|
||||
|
||||
use crate::client::send_message;
|
||||
use crate::data_struct::messages::{NewMessage, ReplyMessage, SendMessage};
|
||||
use crate::ClientStatus;
|
||||
|
||||
|
@ -137,6 +139,7 @@ impl ReplyMessagePy {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[pyclass]
|
||||
#[pyo3(name = "SendMessage")]
|
||||
pub struct SendMessagePy {
|
||||
|
@ -148,3 +151,36 @@ impl SendMessagePy {
|
|||
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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,22 @@
|
|||
pub mod class;
|
||||
|
||||
use std::time::SystemTime;
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use blake3::Hasher;
|
||||
use pyo3::{prelude::*, types::IntoPyDict};
|
||||
use rust_socketio::asynchronous::Client;
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
use crate::config::IcaConfig;
|
||||
use crate::data_struct::messages::NewMessage;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PyStatus {
|
||||
pub files: Option<HashMap<PathBuf, (Vec<u8>, String)>>,
|
||||
pub files: Option<HashMap<PathBuf, (Option<SystemTime>, Py<PyAny>)>>,
|
||||
}
|
||||
|
||||
impl PyStatus {
|
||||
pub fn get_files() -> &'static HashMap<PathBuf, (Vec<u8>, String)> {
|
||||
pub fn get_files() -> &'static HashMap<PathBuf, (Option<SystemTime>, Py<PyAny>)> {
|
||||
unsafe {
|
||||
match PYSTATUS.files.as_ref() {
|
||||
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 {
|
||||
match PYSTATUS.files.as_mut() {
|
||||
Some(files) => {
|
||||
files.insert(path, (content, hash));
|
||||
files.insert(path, (changed_time, py_module));
|
||||
}
|
||||
None => {
|
||||
let mut files = HashMap::new();
|
||||
files.insert(path, (content, hash));
|
||||
files.insert(path, (changed_time, py_module));
|
||||
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 {
|
||||
match PYSTATUS.files.as_ref() {
|
||||
Some(files) => match files.get(path) {
|
||||
Some((_, file_hash)) => file_hash == hash,
|
||||
Some((changed_time, _)) => change_time == changed_time,
|
||||
None => false,
|
||||
},
|
||||
None => false,
|
||||
|
@ -72,12 +74,65 @@ pub fn run() {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn load_py_file(path: &PathBuf) -> (Vec<u8>, String) {
|
||||
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 load_py_plugins(path: &PathBuf) {
|
||||
if path.exists() {
|
||||
info!("finding plugins in: {:?}", path);
|
||||
// 搜索所有的 py 文件 和 文件夹单层下面的 py 文件
|
||||
match path.read_dir() {
|
||||
Err(e) => {
|
||||
warn!("failed to read plugin path: {:?}", e);
|
||||
}
|
||||
Ok(dir) => {
|
||||
for entry in dir {
|
||||
if let Ok(entry) = entry {
|
||||
let path = entry.path();
|
||||
if let Some(ext) = path.extension() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
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) {
|
||||
|
@ -85,28 +140,14 @@ pub fn init_py(config: &IcaConfig) {
|
|||
pyo3::prepare_freethreaded_python();
|
||||
if let Some(plugin_path) = &config.py_plugin_path {
|
||||
let path = PathBuf::from(plugin_path);
|
||||
if path.exists() {
|
||||
info!("finding plugins in: {:?}", path);
|
||||
// 搜索所有的 py 文件 和 文件夹单层下面的 py 文件
|
||||
match path.read_dir() {
|
||||
Err(e) => {
|
||||
warn!("failed to read plugin path: {:?}", e);
|
||||
}
|
||||
Ok(dir) => {
|
||||
for entry in dir {
|
||||
if let Ok(entry) = entry {
|
||||
let path = entry.path();
|
||||
if let Some(ext) = path.extension() {
|
||||
if ext == "py" {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warn!("plugin path not exists: {:?}", path);
|
||||
}
|
||||
load_py_plugins(&path);
|
||||
debug!("python 插件列表: {:#?}", PyStatus::get_files());
|
||||
}
|
||||
|
||||
info!("python inited")
|
||||
}
|
||||
|
||||
/// 执行 new message 的 python 插件
|
||||
pub fn new_message_py(message: &NewMessage, client: &Client) {
|
||||
let msg = class::NewMessagePy::new(message);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user