大的还没来(

This commit is contained in:
shenjack 2024-02-20 20:11:25 +08:00
parent f2ea1764ae
commit 00dc10f395
Signed by: shenjack
GPG Key ID: 7B1134A979775551
7 changed files with 153 additions and 16 deletions

View File

@ -9,6 +9,7 @@ edition = "2021"
ed25519 = "2.2.3" ed25519 = "2.2.3"
ed25519-dalek = "2.1.1" ed25519-dalek = "2.1.1"
hex = "0.4.3" hex = "0.4.3"
blake3 = "1.5.0"
rust_socketio = "0.4.4" rust_socketio = "0.4.4"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }

45
ica-rs/ica_typing.py Normal file
View File

@ -0,0 +1,45 @@
# Python 兼容版本 3.8+
from typing import Optional
class IcaStatus:
@property
def login(self) -> bool:
...
@property
def online(self) -> bool:
...
@property
def self_id(self) -> Optional[bool]:
...
@property
def nick_name(self) -> Optional[str]:
...
@property
def ica_version(self) -> Optional[str]:
...
@property
def os_info(self) -> Optional[str]:
...
@property
def resident_set_size(self) -> Optional[str]:
...
@property
def head_used(self) -> Optional[str]:
...
@property
def load_average(self) -> Optional[str]:
...
class NewMessage:
...
class ReplyMessage:
...
class SendMessage:
...

0
ica-rs/plugins/test.py Normal file
View File

View File

@ -20,7 +20,7 @@ pub struct IcaConfig {
/// 管理员列表 /// 管理员列表
pub admin_list: Vec<i64>, pub admin_list: Vec<i64>,
/// Python 插件路径 /// Python 插件路径
pub py_plugin_path: String, pub py_plugin_path: Option<String>,
} }
impl IcaConfig { impl IcaConfig {

View File

@ -21,7 +21,6 @@ fn main() {
tracing_subscriber::fmt() tracing_subscriber::fmt()
.with_max_level(tracing::Level::DEBUG) .with_max_level(tracing::Level::DEBUG)
.init(); .init();
py::init_py();
// 从命令行获取 host 和 key // 从命令行获取 host 和 key
// 从命令行获取配置文件路径 // 从命令行获取配置文件路径
@ -29,6 +28,7 @@ fn main() {
unsafe { unsafe {
ClientStatus.update_config(ica_config.clone()); ClientStatus.update_config(ica_config.clone());
} }
py::init_py(&ica_config);
let ica_singer = client::IcalinguaSinger::new_from_config(&ica_config); let ica_singer = client::IcalinguaSinger::new_from_config(&ica_config);
let socket = ClientBuilder::new(ica_singer.host.clone()) let socket = ClientBuilder::new(ica_singer.host.clone())

View File

@ -19,6 +19,16 @@ impl IcaStatusPy {
unsafe { ClientStatus.login } unsafe { ClientStatus.login }
} }
#[getter]
pub fn get_online(&self) -> bool {
unsafe {
match ClientStatus.online_data.as_ref() {
Some(data) => data.online,
None => false,
}
}
}
#[getter] #[getter]
pub fn get_self_id(&self) -> Option<i64> { pub fn get_self_id(&self) -> Option<i64> {
unsafe { unsafe {
@ -30,7 +40,7 @@ impl IcaStatusPy {
} }
#[getter] #[getter]
pub fn get_nicn_name(&self) -> Option<String> { pub fn get_nick_name(&self) -> Option<String> {
unsafe { unsafe {
match ClientStatus.online_data.as_ref() { match ClientStatus.online_data.as_ref() {
Some(data) => Some(data.nick.clone()), Some(data) => Some(data.nick.clone()),
@ -39,16 +49,6 @@ impl IcaStatusPy {
} }
} }
#[getter]
pub fn get_online(&self) -> bool {
unsafe {
match ClientStatus.online_data.as_ref() {
Some(data) => data.online,
None => false,
}
}
}
#[getter] #[getter]
pub fn get_ica_version(&self) -> Option<String> { pub fn get_ica_version(&self) -> Option<String> {
unsafe { unsafe {

View File

@ -1,7 +1,63 @@
pub mod class; pub mod class;
use std::{collections::HashMap, path::PathBuf};
use pyo3::{prelude::*, types::IntoPyDict}; use pyo3::{prelude::*, types::IntoPyDict};
use tracing::{debug, info}; use tracing::{debug, info, warn};
use blake3::Hasher;
use crate::config::IcaConfig;
#[derive(Debug, Clone)]
pub struct PyStatus {
pub files: Option<HashMap<PathBuf, (Vec<u8>, String)>>,
}
impl PyStatus {
pub fn get_files() -> &'static HashMap<PathBuf, (Vec<u8>, String)> {
unsafe {
match PYSTATUS.files.as_ref() {
Some(files) => files,
None => {
debug!("No files in py status");
PYSTATUS.files = Some(HashMap::new());
PYSTATUS.files.as_ref().unwrap()
},
}
}
}
pub fn add_file(path: PathBuf, content: Vec<u8>, hash: String) {
unsafe {
match PYSTATUS.files.as_mut() {
Some(files) => {
files.insert(path, (content, hash));
},
None => {
let mut files = HashMap::new();
files.insert(path, (content, hash));
PYSTATUS.files = Some(files);
},
}
}
}
pub fn verify_file(path: &PathBuf, hash: &String) -> bool {
unsafe {
match PYSTATUS.files.as_ref() {
Some(files) => {
match files.get(path) {
Some((_, file_hash)) => file_hash == hash,
None => false,
}
},
None => false,
}
}
}
}
pub static mut PYSTATUS: PyStatus = PyStatus { files: None };
pub fn run() { pub fn run() {
Python::with_gil(|py| { Python::with_gil(|py| {
@ -9,12 +65,47 @@ pub fn run() {
let _bot_status: &PyCell<_> = PyCell::new(py, bot_status).unwrap(); let _bot_status: &PyCell<_> = PyCell::new(py, bot_status).unwrap();
let locals = [("state", _bot_status)].into_py_dict(py); let locals = [("state", _bot_status)].into_py_dict(py);
py.run("print(state)", None, Some(locals)).unwrap(); py.run("from pathlib import Path\nprint(Path.cwd())\nprint(state)", None, Some(locals)).unwrap();
}); });
} }
pub fn init_py() { 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 init_py(config: &IcaConfig) {
debug!("initing python threads"); debug!("initing python threads");
pyo3::prepare_freethreaded_python(); 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);
}
}
info!("python inited") info!("python inited")
} }