mirror of
http://shenjack.top:5100/shenjack/icalingua-python-bot.git
synced 2024-11-23 12:41:05 +08:00
添加Matrix适配器
This commit is contained in:
parent
4656655017
commit
51cc24e347
|
@ -1,4 +1,12 @@
|
|||
|
||||
# python 插件路径
|
||||
py_plugin_path = "/path/to/your/plugin"
|
||||
py_config_path = "/path/to/your/config"
|
||||
|
||||
|
||||
[ica]
|
||||
enable = true
|
||||
|
||||
private_key = "" # 与 icalingua 客户端使用的 private_key 一致
|
||||
host = "" # docker 版 icalingua 服务的地址
|
||||
self_id = 0 # 机器人的 qq 号
|
||||
|
@ -12,7 +20,3 @@ notice_start = true # 是否在启动 bot 后通知
|
|||
admin_list = [0] # 机器人的管理员
|
||||
# 过滤的人
|
||||
filter_list = [0]
|
||||
|
||||
# python 插件路径
|
||||
py_plugin_path = "/path/to/your/plugin"
|
||||
py_config_path = "/path/to/your/config"
|
||||
|
|
|
@ -146,6 +146,9 @@ on_delete_message = Callable[[MessageId, IcaClient], None]
|
|||
# def on_delete_message(msg_id: MessageId, client: IcaClient) -> None:
|
||||
# ...
|
||||
|
||||
# TODO: Matrix adapter
|
||||
# on_matrix_room_message = Callable[[RoomId, NewMessage, IcaClient], None]
|
||||
|
||||
on_config = Callable[[None], Tuple[str, str]]
|
||||
|
||||
CONFIG_DATA: ConfigData = ConfigData()
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use crate::config::IcaConfig;
|
||||
use crate::config::{BotConfig, IcaConfig};
|
||||
use crate::data_struct::all_rooms::Room;
|
||||
use crate::data_struct::messages::{DeleteMessage, SendMessage};
|
||||
use crate::data_struct::online_data::OnlineData;
|
||||
use crate::ClientStatus;
|
||||
use crate::ClientStatus_Global;
|
||||
|
||||
use colored::Colorize;
|
||||
use ed25519_dalek::{Signature, Signer, SigningKey};
|
||||
|
@ -47,73 +47,85 @@ pub async fn delete_message(client: &Client, message: &DeleteMessage) -> bool {
|
|||
// pub async fn fetch_history(client: &Client, roomd_id: RoomId) -> bool { false }
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IcalinguaStatus {
|
||||
pub struct BotStatus {
|
||||
pub login: bool,
|
||||
/// currentLoadedMessagesCount
|
||||
pub current_loaded_messages_count: u64,
|
||||
pub online_data: Option<OnlineData>,
|
||||
pub rooms: Option<Vec<Room>>,
|
||||
pub config: Option<IcaConfig>,
|
||||
pub config: Option<BotConfig>,
|
||||
}
|
||||
|
||||
impl IcalinguaStatus {
|
||||
impl BotStatus {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
login: false,
|
||||
current_loaded_messages_count: 0,
|
||||
online_data: None,
|
||||
rooms: None,
|
||||
config: Some(IcaConfig::new_from_cli()),
|
||||
config: Some(BotConfig::new_from_cli()),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn update_online_data(online_data: OnlineData) {
|
||||
unsafe {
|
||||
ClientStatus.online_data = Some(online_data);
|
||||
ClientStatus_Global.online_data = Some(online_data);
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn update_rooms(rooms: Vec<Room>) {
|
||||
unsafe {
|
||||
ClientStatus.rooms = Some(rooms);
|
||||
ClientStatus_Global.rooms = Some(rooms);
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn update_login_status(login: bool) {
|
||||
unsafe {
|
||||
ClientStatus.login = login;
|
||||
ClientStatus_Global.login = login;
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn update_config(config: IcaConfig) {
|
||||
pub fn update_config(config: BotConfig) {
|
||||
unsafe {
|
||||
ClientStatus.config = Some(config);
|
||||
ClientStatus_Global.config = Some(config);
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn update_loaded_messages_count(count: u64) {
|
||||
unsafe {
|
||||
ClientStatus.current_loaded_messages_count = count;
|
||||
ClientStatus_Global.current_loaded_messages_count = count;
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_login_status() -> bool { unsafe { ClientStatus.login } }
|
||||
pub fn get_login_status() -> bool { unsafe { ClientStatus_Global.login } }
|
||||
#[inline]
|
||||
pub fn get_rooms() -> &'static Vec<Room> {
|
||||
unsafe { ClientStatus.rooms.as_ref().expect("rooms should be set") }
|
||||
unsafe { ClientStatus_Global.rooms.as_ref().expect("rooms should be set") }
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_loaded_messages_count() -> u64 {
|
||||
unsafe { ClientStatus.current_loaded_messages_count }
|
||||
unsafe { ClientStatus_Global.current_loaded_messages_count }
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_online_data() -> &'static OnlineData {
|
||||
unsafe { ClientStatus.online_data.as_ref().expect("online_data should be set") }
|
||||
unsafe { ClientStatus_Global.online_data.as_ref().expect("online_data should be set") }
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_config() -> &'static IcaConfig {
|
||||
unsafe { ClientStatus.config.as_ref().expect("config should be set") }
|
||||
pub fn get_config() -> &'static BotConfig {
|
||||
unsafe { ClientStatus_Global.config.as_ref().expect("config should be set") }
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_ica_config() -> &'static IcaConfig {
|
||||
unsafe {
|
||||
ClientStatus_Global
|
||||
.config
|
||||
.as_ref()
|
||||
.expect("config should be set")
|
||||
.ica
|
||||
.as_ref()
|
||||
.expect("ica should be set")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,7 +146,7 @@ pub async fn sign_callback(payload: Payload, client: Client) {
|
|||
.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 private_key = BotStatus::get_config().ica().private_key.clone();
|
||||
let array_key: [u8; 32] = hex::decode(private_key)
|
||||
.expect("Not a vaild pub key")
|
||||
.try_into()
|
||||
|
|
|
@ -7,6 +7,8 @@ use toml::from_str;
|
|||
/// Icalingua bot 的配置
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct IcaConfig {
|
||||
/// 是否启用 icalingua
|
||||
pub enable: bool,
|
||||
/// icalingua 私钥
|
||||
pub private_key: String,
|
||||
/// icalingua 服务器地址
|
||||
|
@ -21,13 +23,22 @@ pub struct IcaConfig {
|
|||
pub admin_list: Vec<i64>,
|
||||
/// 过滤列表
|
||||
pub filter_list: Vec<i64>,
|
||||
}
|
||||
|
||||
/// 主配置
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct BotConfig {
|
||||
/// Ica 配置
|
||||
pub ica: Option<IcaConfig>,
|
||||
/// Matrix 配置
|
||||
// TODO: MatrixConfig
|
||||
/// Python 插件路径
|
||||
pub py_plugin_path: Option<String>,
|
||||
/// Python 配置文件路径
|
||||
pub py_config_path: Option<String>,
|
||||
}
|
||||
|
||||
impl IcaConfig {
|
||||
impl BotConfig {
|
||||
pub fn new_from_path(config_file_path: String) -> Self {
|
||||
// try read config from file
|
||||
let config = fs::read_to_string(&config_file_path).expect("Failed to read config file");
|
||||
|
@ -39,4 +50,6 @@ impl IcaConfig {
|
|||
let config_file_path = env::args().nth(1).expect("No config path given");
|
||||
Self::new_from_path(config_file_path)
|
||||
}
|
||||
|
||||
pub fn ica(&self) -> IcaConfig { self.ica.clone().expect("No ica config found") }
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use chrono::NaiveDateTime;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
use crate::client::IcalinguaStatus;
|
||||
use crate::client::BotStatus;
|
||||
use crate::data_struct::messages::{At, Message, NewMessage};
|
||||
use crate::data_struct::{MessageId, UserId};
|
||||
|
||||
|
@ -34,7 +34,7 @@ impl<'de> Deserialize<'de> for At {
|
|||
pub trait MessageTrait {
|
||||
fn is_reply(&self) -> bool;
|
||||
fn is_from_self(&self) -> bool {
|
||||
let qq_id = IcalinguaStatus::get_online_data().qqid;
|
||||
let qq_id = BotStatus::get_online_data().qqid;
|
||||
self.sender_id() == qq_id
|
||||
}
|
||||
fn msg_id(&self) -> &MessageId;
|
||||
|
|
|
@ -3,7 +3,7 @@ use rust_socketio::asynchronous::Client;
|
|||
use rust_socketio::{Event, Payload};
|
||||
use tracing::{info, warn};
|
||||
|
||||
use crate::client::{send_message, IcalinguaStatus};
|
||||
use crate::client::{send_message, BotStatus};
|
||||
use crate::data_struct::all_rooms::Room;
|
||||
use crate::data_struct::messages::{Message, MessageTrait, NewMessage};
|
||||
use crate::data_struct::online_data::OnlineData;
|
||||
|
@ -15,7 +15,7 @@ pub async fn get_online_data(payload: Payload, _client: Client) {
|
|||
if let Some(value) = values.first() {
|
||||
let online_data = OnlineData::new_from_json(value);
|
||||
info!("update_online_data {}", format!("{:?}", online_data).cyan());
|
||||
IcalinguaStatus::update_online_data(online_data);
|
||||
BotStatus::update_online_data(online_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ pub async fn add_message(payload: Payload, client: Client) {
|
|||
if let Some(value) = values.first() {
|
||||
let message: NewMessage = serde_json::from_value(value.clone()).unwrap();
|
||||
// 检测是否在过滤列表内
|
||||
if IcalinguaStatus::get_config().filter_list.contains(&message.msg.sender_id) {
|
||||
if BotStatus::get_ica_config().filter_list.contains(&message.msg.sender_id) {
|
||||
return;
|
||||
}
|
||||
info!("add_message {}", message.to_string().cyan());
|
||||
|
@ -76,7 +76,7 @@ pub async fn update_all_room(payload: Payload, _client: Client) {
|
|||
if let Some(raw_rooms) = value.as_array() {
|
||||
let rooms: Vec<Room> =
|
||||
raw_rooms.iter().map(|room| Room::new_from_json(room)).collect();
|
||||
IcalinguaStatus::update_rooms(rooms.clone());
|
||||
BotStatus::update_rooms(rooms.clone());
|
||||
info!("update_all_room {}", rooms.len());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use config::{BotConfig, IcaConfig};
|
||||
use futures_util::FutureExt;
|
||||
use rust_socketio::asynchronous::{Client, ClientBuilder};
|
||||
use rust_socketio::{Event, Payload, TransportType};
|
||||
|
@ -9,10 +10,11 @@ mod client;
|
|||
mod config;
|
||||
mod data_struct;
|
||||
mod events;
|
||||
mod matrix;
|
||||
mod py;
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub static mut ClientStatus: client::IcalinguaStatus = client::IcalinguaStatus {
|
||||
pub static mut ClientStatus_Global: client::BotStatus = client::BotStatus {
|
||||
login: false,
|
||||
current_loaded_messages_count: 0,
|
||||
online_data: None,
|
||||
|
@ -34,18 +36,8 @@ macro_rules! wrap_any_callback {
|
|||
};
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
tracing_subscriber::fmt().with_max_level(tracing::Level::DEBUG).init();
|
||||
info!("ica-async-rs v{}", VERSION);
|
||||
|
||||
// 从命令行获取 host 和 key
|
||||
// 从命令行获取配置文件路径
|
||||
let ica_config = config::IcaConfig::new_from_cli();
|
||||
client::IcalinguaStatus::update_config(ica_config.clone());
|
||||
py::init_py(&ica_config);
|
||||
|
||||
let socket = ClientBuilder::new(ica_config.host.clone())
|
||||
async fn start_ica(config: &IcaConfig, stop_reciver: tokio::sync::oneshot::Receiver<()>) {
|
||||
let socket = ClientBuilder::new(config.host.clone())
|
||||
.transport_type(TransportType::Websocket)
|
||||
.on_any(wrap_any_callback!(events::any_event))
|
||||
.on("requireAuth", wrap_callback!(client::sign_callback))
|
||||
|
@ -65,8 +57,8 @@ async fn main() {
|
|||
|
||||
info!("Connected");
|
||||
|
||||
if ica_config.notice_start {
|
||||
for room in ica_config.notice_room.iter() {
|
||||
if config.notice_start {
|
||||
for room in config.notice_room.iter() {
|
||||
let startup_msg = crate::data_struct::messages::SendMessage::new(
|
||||
format!("ica-async-rs bot v{}", VERSION),
|
||||
room.clone(),
|
||||
|
@ -81,6 +73,33 @@ async fn main() {
|
|||
}
|
||||
}
|
||||
}
|
||||
// 等待停止信号
|
||||
stop_reciver.await.ok();
|
||||
socket.disconnect().await.expect("Disconnect failed");
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
tracing_subscriber::fmt().with_max_level(tracing::Level::DEBUG).init();
|
||||
info!("ica-async-rs v{}", VERSION);
|
||||
|
||||
// 从命令行获取 host 和 key
|
||||
// 从命令行获取配置文件路径
|
||||
let bot_config = config::BotConfig::new_from_cli();
|
||||
client::BotStatus::update_config(bot_config.clone());
|
||||
py::init_py(&bot_config);
|
||||
|
||||
// 准备一个用于停止 socket 的变量
|
||||
let (send, recv) = tokio::sync::oneshot::channel::<()>();
|
||||
if bot_config.ica.is_some() && bot_config.ica().enable {
|
||||
info!("启动 ica");
|
||||
let config = bot_config.ica();
|
||||
tokio::spawn(async move {
|
||||
start_ica(&config, recv).await;
|
||||
});
|
||||
} else {
|
||||
info!("未启用 ica");
|
||||
}
|
||||
|
||||
tokio::time::sleep(Duration::from_secs(2)).await;
|
||||
// 等待一个输入
|
||||
|
@ -88,6 +107,7 @@ async fn main() {
|
|||
let mut input = String::new();
|
||||
std::io::stdin().read_line(&mut input).unwrap();
|
||||
|
||||
socket.disconnect().await.expect("Disconnect failed");
|
||||
// socket.disconnect().await.expect("Disconnect failed");
|
||||
send.send(()).ok();
|
||||
info!("Disconnected");
|
||||
}
|
||||
|
|
1
ica-rs/src/matrix.rs
Normal file
1
ica-rs/src/matrix.rs
Normal file
|
@ -0,0 +1 @@
|
|||
|
|
@ -4,7 +4,7 @@ use pyo3::prelude::*;
|
|||
use rust_socketio::asynchronous::Client;
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
use crate::client::IcalinguaStatus;
|
||||
use crate::client::BotStatus;
|
||||
use crate::data_struct::messages::NewMessage;
|
||||
use crate::data_struct::MessageId;
|
||||
use crate::py::{class, PyPlugin, PyStatus};
|
||||
|
@ -45,7 +45,7 @@ pub fn get_func<'py>(py_module: &'py PyAny, path: &PathBuf, name: &'py str) -> O
|
|||
|
||||
pub fn verify_plugins() {
|
||||
let mut need_reload_files: Vec<PathBuf> = Vec::new();
|
||||
let plugin_path = IcalinguaStatus::get_config().py_plugin_path.as_ref();
|
||||
let plugin_path = BotStatus::get_config().py_plugin_path.as_ref();
|
||||
if let None = plugin_path {
|
||||
warn!("未配置 Python 插件路径");
|
||||
return;
|
||||
|
|
|
@ -4,12 +4,12 @@ use tokio::runtime::Runtime;
|
|||
use toml::Value as TomlValue;
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
use crate::client::{delete_message, send_message, IcalinguaStatus};
|
||||
use crate::client::{delete_message, send_message, BotStatus};
|
||||
use crate::data_struct::messages::{
|
||||
DeleteMessage, MessageTrait, NewMessage, ReplyMessage, SendMessage,
|
||||
};
|
||||
use crate::data_struct::MessageId;
|
||||
use crate::ClientStatus;
|
||||
use crate::ClientStatus_Global;
|
||||
|
||||
#[pyclass]
|
||||
#[pyo3(name = "IcaStatus")]
|
||||
|
@ -20,39 +20,37 @@ impl IcaStatusPy {
|
|||
#[new]
|
||||
pub fn py_new() -> Self { Self {} }
|
||||
#[getter]
|
||||
pub fn get_login(&self) -> bool { unsafe { ClientStatus.login } }
|
||||
pub fn get_login(&self) -> bool { unsafe { ClientStatus_Global.login } }
|
||||
#[getter]
|
||||
pub fn get_online(&self) -> bool { IcalinguaStatus::get_online_data().online }
|
||||
pub fn get_online(&self) -> bool { BotStatus::get_online_data().online }
|
||||
#[getter]
|
||||
pub fn get_self_id(&self) -> i64 { IcalinguaStatus::get_online_data().qqid }
|
||||
pub fn get_self_id(&self) -> i64 { BotStatus::get_online_data().qqid }
|
||||
#[getter]
|
||||
pub fn get_nick_name(&self) -> String { IcalinguaStatus::get_online_data().nick.clone() }
|
||||
pub fn get_nick_name(&self) -> String { BotStatus::get_online_data().nick.clone() }
|
||||
#[getter]
|
||||
pub fn get_loaded_messages_count(&self) -> u64 { IcalinguaStatus::get_loaded_messages_count() }
|
||||
pub fn get_loaded_messages_count(&self) -> u64 { BotStatus::get_loaded_messages_count() }
|
||||
#[getter]
|
||||
pub fn get_ica_version(&self) -> String {
|
||||
IcalinguaStatus::get_online_data().icalingua_info.ica_version.clone()
|
||||
BotStatus::get_online_data().icalingua_info.ica_version.clone()
|
||||
}
|
||||
|
||||
#[getter]
|
||||
pub fn get_os_info(&self) -> String {
|
||||
IcalinguaStatus::get_online_data().icalingua_info.os_info.clone()
|
||||
BotStatus::get_online_data().icalingua_info.os_info.clone()
|
||||
}
|
||||
|
||||
#[getter]
|
||||
pub fn get_resident_set_size(&self) -> String {
|
||||
IcalinguaStatus::get_online_data().icalingua_info.resident_set_size.clone()
|
||||
BotStatus::get_online_data().icalingua_info.resident_set_size.clone()
|
||||
}
|
||||
|
||||
#[getter]
|
||||
pub fn get_heap_used(&self) -> String {
|
||||
IcalinguaStatus::get_online_data().icalingua_info.heap_used.clone()
|
||||
BotStatus::get_online_data().icalingua_info.heap_used.clone()
|
||||
}
|
||||
|
||||
#[getter]
|
||||
pub fn get_load(&self) -> String {
|
||||
IcalinguaStatus::get_online_data().icalingua_info.load.clone()
|
||||
}
|
||||
pub fn get_load(&self) -> String { BotStatus::get_online_data().icalingua_info.load.clone() }
|
||||
}
|
||||
|
||||
impl IcaStatusPy {
|
||||
|
|
|
@ -8,8 +8,8 @@ use pyo3::prelude::*;
|
|||
use pyo3::types::PyTuple;
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
use crate::client::IcalinguaStatus;
|
||||
use crate::config::IcaConfig;
|
||||
use crate::client::BotStatus;
|
||||
use crate::config::{BotConfig, IcaConfig};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PyStatus {
|
||||
|
@ -75,7 +75,7 @@ impl TryFrom<RawPyPlugin> for PyPlugin {
|
|||
if config.is_instance_of::<PyTuple>() {
|
||||
let (config, default) = config.extract::<(String, String)>().unwrap();
|
||||
let base_path =
|
||||
IcalinguaStatus::get_config().py_config_path.as_ref().unwrap();
|
||||
BotStatus::get_config().py_config_path.as_ref().unwrap();
|
||||
|
||||
let mut base_path: PathBuf = PathBuf::from(base_path);
|
||||
|
||||
|
@ -244,7 +244,7 @@ pub fn load_py_file(path: &PathBuf) -> std::io::Result<RawPyPlugin> {
|
|||
Ok((path.clone(), changed_time, content))
|
||||
}
|
||||
|
||||
pub fn init_py(config: &IcaConfig) {
|
||||
pub fn init_py(config: &BotConfig) {
|
||||
debug!("initing python threads");
|
||||
pyo3::prepare_freethreaded_python();
|
||||
if let Some(plugin_path) = &config.py_plugin_path {
|
||||
|
|
Loading…
Reference in New Issue
Block a user