tailchat p3
This commit is contained in:
parent
2f535cc960
commit
b3e2da9df6
@ -2,16 +2,30 @@
|
|||||||
|
|
||||||
from typing import Callable, Tuple
|
from typing import Callable, Tuple
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
ica.rs
|
||||||
pub type RoomId = i64;
|
pub type RoomId = i64;
|
||||||
pub type UserId = i64;
|
pub type UserId = i64;
|
||||||
pub type MessageId = String;
|
pub type MessageId = String;
|
||||||
"""
|
"""
|
||||||
|
class IcaType:
|
||||||
RoomId = int
|
RoomId = int
|
||||||
UserId = int
|
UserId = int
|
||||||
MessageId = str
|
MessageId = str
|
||||||
|
|
||||||
|
"""
|
||||||
|
tailchat.rs
|
||||||
|
pub type GroupId = String;
|
||||||
|
pub type ConverseId = String;
|
||||||
|
pub type UserId = String;
|
||||||
|
pub type MessageId = String;
|
||||||
|
"""
|
||||||
|
class TailchatType:
|
||||||
|
GroupId = str
|
||||||
|
ConverseId = str
|
||||||
|
UserId = str
|
||||||
|
MessageId = str
|
||||||
|
|
||||||
class IcaStatus:
|
class IcaStatus:
|
||||||
"""
|
"""
|
||||||
@ -25,7 +39,7 @@ class IcaStatus:
|
|||||||
def online(self) -> bool:
|
def online(self) -> bool:
|
||||||
...
|
...
|
||||||
@property
|
@property
|
||||||
def self_id(self) -> UserId:
|
def self_id(self) -> IcaType.UserId:
|
||||||
...
|
...
|
||||||
@property
|
@property
|
||||||
def nick_name(self) -> str:
|
def nick_name(self) -> str:
|
||||||
@ -82,13 +96,13 @@ class IcaNewMessage:
|
|||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
...
|
...
|
||||||
@property
|
@property
|
||||||
def id(self) -> MessageId:
|
def id(self) -> IcaType.MessageId:
|
||||||
...
|
...
|
||||||
@property
|
@property
|
||||||
def content(self) -> str:
|
def content(self) -> str:
|
||||||
...
|
...
|
||||||
@property
|
@property
|
||||||
def sender_id(self) -> UserId:
|
def sender_id(self) -> IcaType.UserId:
|
||||||
...
|
...
|
||||||
@property
|
@property
|
||||||
def is_from_self(self) -> bool:
|
def is_from_self(self) -> bool:
|
||||||
@ -103,7 +117,7 @@ class IcaNewMessage:
|
|||||||
def is_chat_msg(self) -> bool:
|
def is_chat_msg(self) -> bool:
|
||||||
"""是否是私聊消息"""
|
"""是否是私聊消息"""
|
||||||
@property
|
@property
|
||||||
def room_id(self) -> RoomId:
|
def room_id(self) -> IcaType.RoomId:
|
||||||
"""
|
"""
|
||||||
如果是群聊消息, 返回 (-群号)
|
如果是群聊消息, 返回 (-群号)
|
||||||
如果是私聊消息, 返回 对面qq
|
如果是私聊消息, 返回 对面qq
|
||||||
@ -148,11 +162,18 @@ class IcaClient:
|
|||||||
"""向日志中输出警告信息"""
|
"""向日志中输出警告信息"""
|
||||||
|
|
||||||
|
|
||||||
class MatrixClient:
|
class TailchatClient:
|
||||||
"""
|
"""
|
||||||
Matrix 的客户端
|
Tailchat 的客户端
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def debug(self, message: str) -> None:
|
||||||
|
"""向日志中输出调试信息"""
|
||||||
|
def info(self, message: str) -> None:
|
||||||
|
"""向日志中输出信息"""
|
||||||
|
def warn(self, message: str) -> None:
|
||||||
|
"""向日志中输出警告信息"""
|
||||||
|
|
||||||
|
|
||||||
class ConfigData:
|
class ConfigData:
|
||||||
def __getitem__(self, key: str):
|
def __getitem__(self, key: str):
|
||||||
@ -169,12 +190,12 @@ on_ica_message = Callable[[IcaNewMessage, IcaClient], None]
|
|||||||
# def on_message(msg: NewMessage, client: IcaClient) -> None:
|
# def on_message(msg: NewMessage, client: IcaClient) -> None:
|
||||||
# ...
|
# ...
|
||||||
|
|
||||||
on_ica_delete_message = Callable[[MessageId, IcaClient], None]
|
on_ica_delete_message = Callable[[IcaType.MessageId, IcaClient], None]
|
||||||
# def on_delete_message(msg_id: MessageId, client: IcaClient) -> None:
|
# def on_delete_message(msg_id: MessageId, client: IcaClient) -> None:
|
||||||
# ...
|
# ...
|
||||||
|
|
||||||
# TODO: Matrix adapter
|
# TODO: Tailchat adapter
|
||||||
on_matrix_message = Callable[[], None]
|
on_tailchat_message = Callable[[], None]
|
||||||
|
|
||||||
on_config = Callable[[None], Tuple[str, str]]
|
on_config = Callable[[None], Tuple[str, str]]
|
||||||
|
|
||||||
|
@ -5,6 +5,8 @@ use serde::Deserialize;
|
|||||||
use toml::from_str;
|
use toml::from_str;
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
|
|
||||||
|
use crate::data_struct::{ica, tailchat};
|
||||||
|
|
||||||
/// Icalingua bot 的配置
|
/// Icalingua bot 的配置
|
||||||
#[derive(Debug, Clone, Deserialize)]
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
pub struct IcaConfig {
|
pub struct IcaConfig {
|
||||||
@ -13,15 +15,33 @@ pub struct IcaConfig {
|
|||||||
/// icalingua 服务器地址
|
/// icalingua 服务器地址
|
||||||
pub host: String,
|
pub host: String,
|
||||||
/// bot 的 qq
|
/// bot 的 qq
|
||||||
pub self_id: u64,
|
pub self_id: ica::UserId,
|
||||||
/// 提醒的房间
|
/// 提醒的房间
|
||||||
pub notice_room: Vec<i64>,
|
pub notice_room: Vec<ica::RoomId>,
|
||||||
/// 是否提醒
|
/// 是否提醒
|
||||||
pub notice_start: bool,
|
pub notice_start: bool,
|
||||||
/// 管理员列表
|
/// 管理员列表
|
||||||
pub admin_list: Vec<i64>,
|
pub admin_list: Vec<ica::UserId>,
|
||||||
/// 过滤列表
|
/// 过滤列表
|
||||||
pub filter_list: Vec<i64>,
|
pub filter_list: Vec<ica::UserId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
|
pub struct TailchatConfig {
|
||||||
|
/// 服务器地址
|
||||||
|
pub host: String,
|
||||||
|
/// 机器人 App ID
|
||||||
|
pub app_id: String,
|
||||||
|
/// 机器人 App Secret
|
||||||
|
pub app_secret: String,
|
||||||
|
/// 提醒的房间
|
||||||
|
pub notice_room: Vec<(tailchat::GroupId, tailchat::ConverseId)>,
|
||||||
|
/// 是否提醒
|
||||||
|
pub notice_start: bool,
|
||||||
|
/// 管理员列表
|
||||||
|
pub admin_list: Vec<tailchat::UserId>,
|
||||||
|
/// 过滤列表
|
||||||
|
pub filter_list: Vec<tailchat::UserId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize)]
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
@ -40,6 +60,11 @@ pub struct BotConfig {
|
|||||||
/// Ica 配置
|
/// Ica 配置
|
||||||
pub ica: Option<IcaConfig>,
|
pub ica: Option<IcaConfig>,
|
||||||
|
|
||||||
|
/// 是否启用 Tailchat
|
||||||
|
pub enable_tailchat: Option<bool>,
|
||||||
|
/// Tailchat 配置
|
||||||
|
pub tailchat: Option<TailchatConfig>,
|
||||||
|
|
||||||
/// 是否启用 Python 插件
|
/// 是否启用 Python 插件
|
||||||
pub enable_py: Option<bool>,
|
pub enable_py: Option<bool>,
|
||||||
/// Python 插件配置
|
/// Python 插件配置
|
||||||
|
@ -12,6 +12,8 @@ pub enum IcaError {
|
|||||||
pub enum TailchatError {
|
pub enum TailchatError {
|
||||||
/// Socket IO 链接错误
|
/// Socket IO 链接错误
|
||||||
SocketIoError(rust_socketio::error::Error),
|
SocketIoError(rust_socketio::error::Error),
|
||||||
|
/// reqwest 相关错误
|
||||||
|
ReqwestError(reqwest::Error),
|
||||||
/// 登录失败
|
/// 登录失败
|
||||||
LoginFailed(String),
|
LoginFailed(String),
|
||||||
}
|
}
|
||||||
@ -35,6 +37,14 @@ impl From<rust_socketio::Error> for IcaError {
|
|||||||
fn from(e: rust_socketio::Error) -> Self { IcaError::SocketIoError(e) }
|
fn from(e: rust_socketio::Error) -> Self { IcaError::SocketIoError(e) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<rust_socketio::Error> for TailchatError {
|
||||||
|
fn from(e: rust_socketio::Error) -> Self { TailchatError::SocketIoError(e) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<reqwest::Error> for TailchatError {
|
||||||
|
fn from(e: reqwest::Error) -> Self { TailchatError::ReqwestError(e) }
|
||||||
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for IcaError {
|
impl std::fmt::Display for IcaError {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
@ -48,6 +58,7 @@ impl std::fmt::Display for TailchatError {
|
|||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
TailchatError::SocketIoError(e) => write!(f, "Socket IO 链接错误: {}", e),
|
TailchatError::SocketIoError(e) => write!(f, "Socket IO 链接错误: {}", e),
|
||||||
|
TailchatError::ReqwestError(e) => write!(f, "Reqwest 错误: {}", e),
|
||||||
TailchatError::LoginFailed(e) => write!(f, "登录失败: {}", e),
|
TailchatError::LoginFailed(e) => write!(f, "登录失败: {}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,6 +96,7 @@ impl std::error::Error for TailchatError {
|
|||||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
match self {
|
match self {
|
||||||
TailchatError::SocketIoError(e) => Some(e),
|
TailchatError::SocketIoError(e) => Some(e),
|
||||||
|
TailchatError::ReqwestError(e) => Some(e),
|
||||||
TailchatError::LoginFailed(_) => None,
|
TailchatError::LoginFailed(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,8 +96,21 @@ pub const ICA_DELETE_MESSAGE_FUNC: &str = "on_ica_delete_message";
|
|||||||
pub const TAILCHAT_NEW_MESSAGE_FUNC: &str = "on_tailchat_message";
|
pub const TAILCHAT_NEW_MESSAGE_FUNC: &str = "on_tailchat_message";
|
||||||
|
|
||||||
macro_rules! call_py_func {
|
macro_rules! call_py_func {
|
||||||
($args:expr, $func_name:expr, $client:expr) => {
|
($args:expr, $plugin:expr, $plugin_path:expr, $func_name:expr, $client:expr) => {
|
||||||
|
tokio::spawn(async move {
|
||||||
|
Python::with_gil(|py| {
|
||||||
|
if let Ok(py_func) = get_func($plugin.py_module.bind(py), $func_name) {
|
||||||
|
if let Err(e) = py_func.call1($args) {
|
||||||
|
let e = PyPluginError::FuncCallError(
|
||||||
|
e,
|
||||||
|
$func_name.to_string(),
|
||||||
|
$plugin_path.to_string_lossy().to_string(),
|
||||||
|
);
|
||||||
|
warn!("failed to call function<{}>: {:?}", $func_name, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,20 +125,21 @@ pub async fn ica_new_message_py(message: &ica::messages::NewMessage, client: &Cl
|
|||||||
let client = class::ica::IcaClientPy::new(client);
|
let client = class::ica::IcaClientPy::new(client);
|
||||||
let args = (msg, client);
|
let args = (msg, client);
|
||||||
// 甚至实际上压根不需要await这个spawn, 直接让他自己跑就好了(离谱)
|
// 甚至实际上压根不需要await这个spawn, 直接让他自己跑就好了(离谱)
|
||||||
tokio::spawn(async move {
|
call_py_func!(args, plugin, path, ICA_NEW_MESSAGE_FUNC, client);
|
||||||
Python::with_gil(|py| {
|
// tokio::spawn(async move {
|
||||||
if let Ok(py_func) = get_func(plugin.py_module.bind(py), ICA_NEW_MESSAGE_FUNC) {
|
// Python::with_gil(|py| {
|
||||||
if let Err(e) = py_func.call1(args) {
|
// if let Ok(py_func) = get_func(plugin.py_module.bind(py), ICA_NEW_MESSAGE_FUNC) {
|
||||||
let e = PyPluginError::FuncCallError(
|
// if let Err(e) = py_func.call1(args) {
|
||||||
e,
|
// let e = PyPluginError::FuncCallError(
|
||||||
ICA_NEW_MESSAGE_FUNC.to_string(),
|
// e,
|
||||||
path.to_string_lossy().to_string(),
|
// ICA_NEW_MESSAGE_FUNC.to_string(),
|
||||||
);
|
// path.to_string_lossy().to_string(),
|
||||||
warn!("failed to call function<{}>: {:?}", ICA_NEW_MESSAGE_FUNC, e);
|
// );
|
||||||
}
|
// warn!("failed to call function<{}>: {:?}", ICA_NEW_MESSAGE_FUNC, e);
|
||||||
}
|
// }
|
||||||
})
|
// }
|
||||||
});
|
// })
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,23 +151,31 @@ pub async fn ica_delete_message_py(msg_id: ica::MessageId, client: &Client) {
|
|||||||
let msg_id = msg_id.clone();
|
let msg_id = msg_id.clone();
|
||||||
let client = class::ica::IcaClientPy::new(client);
|
let client = class::ica::IcaClientPy::new(client);
|
||||||
let args = (msg_id.clone(), client);
|
let args = (msg_id.clone(), client);
|
||||||
tokio::spawn(async move {
|
call_py_func!(args, plugin, path, ICA_DELETE_MESSAGE_FUNC, client);
|
||||||
Python::with_gil(|py| {
|
// tokio::spawn(async move {
|
||||||
if let Ok(py_func) = get_func(plugin.py_module.bind(py), ICA_DELETE_MESSAGE_FUNC) {
|
// Python::with_gil(|py| {
|
||||||
if let Err(e) = py_func.call1(args) {
|
// if let Ok(py_func) = get_func(plugin.py_module.bind(py), ICA_DELETE_MESSAGE_FUNC) {
|
||||||
let e = PyPluginError::FuncCallError(
|
// if let Err(e) = py_func.call1(args) {
|
||||||
e,
|
// let e = PyPluginError::FuncCallError(
|
||||||
ICA_DELETE_MESSAGE_FUNC.to_string(),
|
// e,
|
||||||
path.to_string_lossy().to_string(),
|
// ICA_DELETE_MESSAGE_FUNC.to_string(),
|
||||||
);
|
// path.to_string_lossy().to_string(),
|
||||||
warn!("failed to call function<{}>: {:?}", ICA_DELETE_MESSAGE_FUNC, e);
|
// );
|
||||||
}
|
// warn!("failed to call function<{}>: {:?}", ICA_DELETE_MESSAGE_FUNC, e);
|
||||||
}
|
// }
|
||||||
})
|
// }
|
||||||
});
|
// })
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn tailchat_new_message_py(message: tailchat::messages::ReciveMessage, client: &Client) {
|
pub async fn tailchat_new_message_py(message: tailchat::messages::ReciveMessage, client: &Client) {
|
||||||
|
verify_plugins();
|
||||||
|
|
||||||
|
let plugins = PyStatus::get_files();
|
||||||
|
for (path, plugin) in plugins.iter() {
|
||||||
|
// let msg = class::tailchat::
|
||||||
|
let args = ();
|
||||||
|
call_py_func!(args, plugin, path, TAILCHAT_NEW_MESSAGE_FUNC, client);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,8 @@ impl TryFrom<RawPyPlugin> for PyPlugin {
|
|||||||
};
|
};
|
||||||
match config_value {
|
match config_value {
|
||||||
Ok(config) => {
|
Ok(config) => {
|
||||||
let py_config = Bound::new(py, class::ConfigDataPy::new(config)).unwrap();
|
let py_config =
|
||||||
|
Bound::new(py, class::ConfigDataPy::new(config)).unwrap();
|
||||||
module.setattr("CONFIG_DATA", py_config).unwrap();
|
module.setattr("CONFIG_DATA", py_config).unwrap();
|
||||||
Ok(PyPlugin {
|
Ok(PyPlugin {
|
||||||
file_path: path,
|
file_path: path,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
pub mod events;
|
pub mod events;
|
||||||
|
|
||||||
use futures_util::FutureExt;
|
use futures_util::FutureExt;
|
||||||
|
use reqwest::ClientBuilder as reqwest_ClientBuilder;
|
||||||
use rust_socketio::asynchronous::{Client, ClientBuilder};
|
use rust_socketio::asynchronous::{Client, ClientBuilder};
|
||||||
use rust_socketio::{Event, Payload, TransportType};
|
use rust_socketio::{Event, Payload, TransportType};
|
||||||
use tracing::{event, span, Level};
|
use tracing::{event, span, Level};
|
||||||
@ -14,10 +15,13 @@ pub async fn start_tailchat() -> ClientResult<(), TailchatError> {
|
|||||||
|
|
||||||
event!(Level::INFO, "tailchat-async-rs v{} initing", crate::TAILCHAT_VERSION);
|
event!(Level::INFO, "tailchat-async-rs v{} initing", crate::TAILCHAT_VERSION);
|
||||||
|
|
||||||
|
let tailchat_req = reqwest_ClientBuilder::new().build()?;
|
||||||
|
|
||||||
|
// tailchat_req.get("http://localhost:8080").send().await?;
|
||||||
|
|
||||||
// let socket = match ClientBuilder::new() {
|
// let socket = match ClientBuilder::new() {
|
||||||
|
|
||||||
// };
|
// };
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
|
Loading…
Reference in New Issue
Block a user