mirror of
http://shenjack.top:5100/shenjack/icalingua-python-bot.git
synced 2024-11-23 20:45:06 +08:00
可算是改成 async了
This commit is contained in:
parent
a5f916542e
commit
1aeabb3e13
|
@ -10,15 +10,17 @@ 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"
|
blake3 = "1.5.0"
|
||||||
rust_socketio = "0.4.4"
|
rust_socketio = { version = "0.4.4", features = ["async"]}
|
||||||
|
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
chrono = "0.4.34"
|
chrono = "0.4.34"
|
||||||
toml = "0.8.10"
|
toml = "0.8.10"
|
||||||
|
|
||||||
colored = "2.1.0"
|
colored = "2.1.0"
|
||||||
|
|
||||||
|
tokio = { version = "1.0", features = ["full"] }
|
||||||
|
futures-util = "0.3.30"
|
||||||
|
|
||||||
tracing = "0.1.40"
|
tracing = "0.1.40"
|
||||||
tracing-subscriber = { version = "0.3.18", features = ["time"] }
|
tracing-subscriber = { version = "0.3.18", features = ["time"] }
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
use crate::config::IcaConfig;
|
use crate::config::IcaConfig;
|
||||||
use crate::data_struct::messages::SendMessage;
|
use crate::data_struct::messages::SendMessage;
|
||||||
use crate::data_struct::{all_rooms::Room, online_data::OnlineData};
|
use crate::data_struct::{all_rooms::Room, online_data::OnlineData};
|
||||||
|
use crate::ClientStatus;
|
||||||
|
|
||||||
use ed25519_dalek::{Signature, Signer, SigningKey};
|
|
||||||
use rust_socketio::{Payload, RawClient};
|
|
||||||
use serde_json::Value;
|
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
|
use ed25519_dalek::{Signature, Signer, SigningKey};
|
||||||
|
use rust_socketio::asynchronous::Client;
|
||||||
|
use rust_socketio::Payload;
|
||||||
|
use serde_json::Value;
|
||||||
use tracing::{debug, warn};
|
use tracing::{debug, warn};
|
||||||
|
|
||||||
/// "安全" 的 发送一条消息
|
/// "安全" 的 发送一条消息
|
||||||
pub fn send_message(client: RawClient, message: SendMessage) {
|
pub async fn send_message(client: Client, message: SendMessage) {
|
||||||
let value = message.as_value();
|
let value = message.as_value();
|
||||||
match client.emit("sendMessage", value) {
|
match client.emit("sendMessage", value).await {
|
||||||
Ok(_) => debug!("send_message {}", format!("{:#?}", message).cyan()),
|
Ok(_) => debug!("send_message {}", format!("{:#?}", message).cyan()),
|
||||||
Err(e) => warn!("send_message faild:{}", format!("{:#?}", e).red()),
|
Err(e) => warn!("send_message faild:{}", format!("{:#?}", e).red()),
|
||||||
}
|
}
|
||||||
|
@ -51,64 +53,48 @@ impl IcalinguaStatus {
|
||||||
self.config = Some(config);
|
self.config = Some(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_online_data(&self) -> &OnlineData {
|
pub fn get_online_data() -> &'static OnlineData {
|
||||||
self.online_data.as_ref().unwrap()
|
unsafe {
|
||||||
}
|
ClientStatus
|
||||||
|
.online_data
|
||||||
pub fn get_config(&self) -> &IcaConfig {
|
.as_ref()
|
||||||
self.config.as_ref().unwrap()
|
.expect("online_data should be set")
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct IcalinguaSinger {
|
|
||||||
pub host: String,
|
|
||||||
pub private_key: SigningKey,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IcalinguaSinger {
|
|
||||||
pub fn new_from_config(config: &IcaConfig) -> Self {
|
|
||||||
let host = config.host.clone();
|
|
||||||
let pub_key = config.private_key.clone();
|
|
||||||
Self::new_from_raw(host, pub_key)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_from_raw(host: String, pub_key: String) -> Self {
|
|
||||||
let array_key: [u8; 32] = hex::decode(pub_key)
|
|
||||||
.expect("Not a vaild pub key")
|
|
||||||
.try_into()
|
|
||||||
.expect("Not a vaild pub key");
|
|
||||||
|
|
||||||
let signing_key: SigningKey = SigningKey::from_bytes(&array_key);
|
|
||||||
Self {
|
|
||||||
host,
|
|
||||||
private_key: signing_key,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 最痛苦的一集
|
pub fn get_config() -> &'static IcaConfig {
|
||||||
///
|
unsafe { ClientStatus.config.as_ref().expect("config should be set") }
|
||||||
/// 签名的回调函数
|
|
||||||
pub fn sign_callback(&self, payload: Payload, client: RawClient) {
|
|
||||||
let require_data = match payload {
|
|
||||||
Payload::Text(json_value) => Some(json_value),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
.expect("Payload should be Json data");
|
|
||||||
|
|
||||||
let (auth_key, version) = (&require_data[0], &require_data[1]);
|
|
||||||
debug!("auth_key: {:?}, version: {:?}", auth_key, version);
|
|
||||||
let auth_key = match &require_data.get(0) {
|
|
||||||
Some(Value::String(auth_key)) => Some(auth_key),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
.expect("auth_key should be string");
|
|
||||||
|
|
||||||
let salt = hex::decode(auth_key).expect("Got an invalid salt from the server");
|
|
||||||
let signature: Signature = self.private_key.sign(salt.as_slice());
|
|
||||||
|
|
||||||
let sign = signature.to_bytes().to_vec();
|
|
||||||
client
|
|
||||||
.emit("auth", sign)
|
|
||||||
.expect("Faild to send signin data");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn sign_callback(payload: Payload, client: Client) {
|
||||||
|
// 获取数据
|
||||||
|
let require_data = match payload {
|
||||||
|
Payload::Text(json_value) => Some(json_value),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
.expect("Payload should be Json data");
|
||||||
|
|
||||||
|
let (auth_key, version) = (&require_data[0], &require_data[1]);
|
||||||
|
debug!("auth_key: {:?}, version: {:?}", auth_key, version);
|
||||||
|
let auth_key = match &require_data.get(0) {
|
||||||
|
Some(Value::String(auth_key)) => Some(auth_key),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
.expect("auth_key should be string");
|
||||||
|
let salt = hex::decode(auth_key).expect("Got an invalid salt from the server");
|
||||||
|
// 签名
|
||||||
|
let private_key = IcalinguaStatus::get_config().private_key.clone();
|
||||||
|
let array_key: [u8; 32] = hex::decode(private_key)
|
||||||
|
.expect("Not a vaild pub key")
|
||||||
|
.try_into()
|
||||||
|
.expect("Not a vaild pub key");
|
||||||
|
let signing_key: SigningKey = SigningKey::from_bytes(&array_key);
|
||||||
|
let signature: Signature = signing_key.sign(salt.as_slice());
|
||||||
|
|
||||||
|
let sign = signature.to_bytes().to_vec();
|
||||||
|
client
|
||||||
|
.emit("auth", sign)
|
||||||
|
.await
|
||||||
|
.expect("Faild to send signin data");
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
use crate::client::IcalinguaStatus;
|
||||||
use crate::data_struct::files::MessageFile;
|
use crate::data_struct::files::MessageFile;
|
||||||
use crate::data_struct::{MessageId, RoomId, UserId};
|
use crate::data_struct::{MessageId, RoomId, UserId};
|
||||||
use crate::ClientStatus;
|
|
||||||
|
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -217,9 +217,7 @@ impl NewMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_from_self(&self) -> bool {
|
pub fn is_from_self(&self) -> bool {
|
||||||
let qq_id = unsafe {
|
let qq_id = IcalinguaStatus::get_online_data().qqid;
|
||||||
ClientStatus.get_online_data().qqid
|
|
||||||
};
|
|
||||||
self.sender_id == qq_id
|
self.sender_id == qq_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use rust_socketio::{Event, Payload, RawClient};
|
use rust_socketio::asynchronous::Client;
|
||||||
|
use rust_socketio::{Event, Payload};
|
||||||
use tracing::{info, warn};
|
use tracing::{info, warn};
|
||||||
|
|
||||||
use crate::client::send_message;
|
use crate::client::send_message;
|
||||||
|
@ -9,7 +10,7 @@ use crate::data_struct::online_data::OnlineData;
|
||||||
use crate::{py, VERSION};
|
use crate::{py, VERSION};
|
||||||
|
|
||||||
/// 获取在线数据
|
/// 获取在线数据
|
||||||
pub fn get_online_data(payload: Payload, _client: RawClient) {
|
pub async fn get_online_data(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() {
|
||||||
let online_data = OnlineData::new_from_json(value);
|
let online_data = OnlineData::new_from_json(value);
|
||||||
|
@ -25,7 +26,7 @@ pub fn get_online_data(payload: Payload, _client: RawClient) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 接收消息
|
/// 接收消息
|
||||||
pub fn add_message(payload: Payload, client: RawClient) {
|
pub async fn add_message(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() {
|
||||||
let message = NewMessage::new_from_json(value);
|
let message = NewMessage::new_from_json(value);
|
||||||
|
@ -40,14 +41,14 @@ pub fn add_message(payload: Payload, client: RawClient) {
|
||||||
// 之后的处理交给插件
|
// 之后的处理交给插件
|
||||||
if message.content.eq("/bot-rs") {
|
if message.content.eq("/bot-rs") {
|
||||||
let reply = message.reply_with(&format!("ica-rs pong v{}", VERSION));
|
let reply = message.reply_with(&format!("ica-rs pong v{}", VERSION));
|
||||||
send_message(client, reply)
|
send_message(client, reply).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 撤回消息
|
/// 撤回消息
|
||||||
pub fn delete_message(payload: Payload, _client: RawClient) {
|
pub async fn delete_message(payload: Payload, _client: Client) {
|
||||||
if let Payload::Text(values) = payload {
|
if let Payload::Text(values) = payload {
|
||||||
// 消息 id
|
// 消息 id
|
||||||
if let Some(value) = values.first() {
|
if let Some(value) = values.first() {
|
||||||
|
@ -58,7 +59,7 @@ pub fn delete_message(payload: Payload, _client: RawClient) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_all_room(payload: Payload, _client: RawClient) {
|
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() {
|
||||||
|
@ -76,7 +77,7 @@ pub fn update_all_room(payload: Payload, _client: RawClient) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 所有
|
/// 所有
|
||||||
pub fn any_event(event: Event, payload: Payload, _client: RawClient) {
|
pub async fn any_event(event: Event, payload: Payload, _client: Client) {
|
||||||
let handled = vec![
|
let handled = vec![
|
||||||
// 真正处理过的
|
// 真正处理过的
|
||||||
"authSucceed",
|
"authSucceed",
|
||||||
|
@ -128,7 +129,7 @@ pub fn any_event(event: Event, payload: Payload, _client: RawClient) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn connect_callback(payload: Payload, _client: RawClient) {
|
pub async fn connect_callback(payload: Payload, _client: Client) {
|
||||||
match payload {
|
match payload {
|
||||||
Payload::Text(values) => {
|
Payload::Text(values) => {
|
||||||
if let Some(value) = values.first() {
|
if let Some(value) = values.first() {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use rust_socketio::ClientBuilder;
|
use futures_util::FutureExt;
|
||||||
|
use rust_socketio::asynchronous::{Client, ClientBuilder};
|
||||||
|
use rust_socketio::{Event, Payload, TransportType};
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
mod client;
|
mod client;
|
||||||
|
@ -19,7 +21,20 @@ pub static mut ClientStatus: client::IcalinguaStatus = client::IcalinguaStatus {
|
||||||
|
|
||||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
fn main() {
|
macro_rules! wrap_callback {
|
||||||
|
($f:expr) => {
|
||||||
|
|payload: Payload, client: Client| $f(payload, client).boxed()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! wrap_any_callback {
|
||||||
|
($f:expr) => {
|
||||||
|
|event: Event, payload: Payload, client: Client| $f(event, payload, client).boxed()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
tracing_subscriber::fmt()
|
tracing_subscriber::fmt()
|
||||||
.with_max_level(tracing::Level::DEBUG)
|
.with_max_level(tracing::Level::DEBUG)
|
||||||
.init();
|
.init();
|
||||||
|
@ -31,20 +46,20 @@ fn main() {
|
||||||
ClientStatus.update_config(ica_config.clone());
|
ClientStatus.update_config(ica_config.clone());
|
||||||
}
|
}
|
||||||
py::init_py(&ica_config);
|
py::init_py(&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_config.host.clone())
|
||||||
.transport_type(rust_socketio::TransportType::Websocket)
|
.transport_type(TransportType::Websocket)
|
||||||
.on_any(events::any_event)
|
.on_any(wrap_any_callback!(events::any_event))
|
||||||
.on("requireAuth", move |a, b| ica_singer.sign_callback(a, b))
|
.on("requireAuth", wrap_callback!(client::sign_callback))
|
||||||
.on("message", events::connect_callback)
|
.on("message", wrap_callback!(events::connect_callback))
|
||||||
.on("authSucceed", events::connect_callback)
|
.on("authSucceed", wrap_callback!(events::connect_callback))
|
||||||
.on("authFailed", events::connect_callback)
|
.on("authFailed", wrap_callback!(events::connect_callback))
|
||||||
.on("onlineData", events::get_online_data)
|
.on("onlineData", wrap_callback!(events::get_online_data))
|
||||||
.on("setAllRooms", events::update_all_room)
|
.on("setAllRooms", wrap_callback!(events::update_all_room))
|
||||||
.on("addMessage", events::add_message)
|
.on("addMessage", wrap_callback!(events::add_message))
|
||||||
.on("deleteMessage", events::delete_message)
|
.on("deleteMessage", wrap_callback!(events::delete_message))
|
||||||
.connect()
|
.connect()
|
||||||
|
.await
|
||||||
.expect("Connection failed");
|
.expect("Connection failed");
|
||||||
|
|
||||||
info!("Connected");
|
info!("Connected");
|
||||||
|
@ -58,7 +73,10 @@ fn main() {
|
||||||
);
|
);
|
||||||
std::thread::sleep(Duration::from_secs(1));
|
std::thread::sleep(Duration::from_secs(1));
|
||||||
info!("发送启动消息到房间: {}", room);
|
info!("发送启动消息到房间: {}", room);
|
||||||
if let Err(e) = socket.emit("sendMessage", serde_json::to_value(startup_msg).unwrap()) {
|
if let Err(e) = socket
|
||||||
|
.emit("sendMessage", serde_json::to_value(startup_msg).unwrap())
|
||||||
|
.await
|
||||||
|
{
|
||||||
info!("启动信息发送失败 房间:{}|e:{}", room, e);
|
info!("启动信息发送失败 房间:{}|e:{}", room, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,6 +87,7 @@ fn main() {
|
||||||
info!("Press any key to exit");
|
info!("Press any key to exit");
|
||||||
let mut input = String::new();
|
let mut input = String::new();
|
||||||
std::io::stdin().read_line(&mut input).unwrap();
|
std::io::stdin().read_line(&mut input).unwrap();
|
||||||
socket.disconnect().expect("Disconnect failed");
|
|
||||||
|
socket.disconnect().await.expect("Disconnect failed");
|
||||||
info!("Disconnected");
|
info!("Disconnected");
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,9 @@ pub mod class;
|
||||||
|
|
||||||
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 tracing::{debug, info, warn};
|
use tracing::{debug, info, warn};
|
||||||
use blake3::Hasher;
|
|
||||||
|
|
||||||
use crate::config::IcaConfig;
|
use crate::config::IcaConfig;
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ impl PyStatus {
|
||||||
debug!("No files in py status");
|
debug!("No files in py status");
|
||||||
PYSTATUS.files = Some(HashMap::new());
|
PYSTATUS.files = Some(HashMap::new());
|
||||||
PYSTATUS.files.as_ref().unwrap()
|
PYSTATUS.files.as_ref().unwrap()
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,12 +32,12 @@ impl PyStatus {
|
||||||
match PYSTATUS.files.as_mut() {
|
match PYSTATUS.files.as_mut() {
|
||||||
Some(files) => {
|
Some(files) => {
|
||||||
files.insert(path, (content, hash));
|
files.insert(path, (content, hash));
|
||||||
},
|
}
|
||||||
None => {
|
None => {
|
||||||
let mut files = HashMap::new();
|
let mut files = HashMap::new();
|
||||||
files.insert(path, (content, hash));
|
files.insert(path, (content, hash));
|
||||||
PYSTATUS.files = Some(files);
|
PYSTATUS.files = Some(files);
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,11 +45,9 @@ impl PyStatus {
|
||||||
pub fn verify_file(path: &PathBuf, hash: &String) -> bool {
|
pub fn verify_file(path: &PathBuf, hash: &String) -> bool {
|
||||||
unsafe {
|
unsafe {
|
||||||
match PYSTATUS.files.as_ref() {
|
match PYSTATUS.files.as_ref() {
|
||||||
Some(files) => {
|
Some(files) => match files.get(path) {
|
||||||
match files.get(path) {
|
Some((_, file_hash)) => file_hash == hash,
|
||||||
Some((_, file_hash)) => file_hash == hash,
|
None => false,
|
||||||
None => false,
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
None => false,
|
None => false,
|
||||||
}
|
}
|
||||||
|
@ -65,7 +63,12 @@ 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("from pathlib import Path\nprint(Path.cwd())\nprint(state)", None, Some(locals)).unwrap();
|
py.run(
|
||||||
|
"from pathlib import Path\nprint(Path.cwd())\nprint(state)",
|
||||||
|
None,
|
||||||
|
Some(locals),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,9 +97,7 @@ 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" {}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user