feat(channels): add QQ Official channel via Tencent Bot SDK
Implement QQ Official messaging channel using OAuth2 authentication with Discord-like WebSocket gateway protocol for events. - Add QQChannel with send/listen/health_check support - Add QQConfig (app_id, app_secret, allowed_users) - OAuth2 token refresh and WebSocket heartbeat management - Message deduplication with capacity-based eviction - Support both C2C (private) and group AT messages - Integrate with onboard wizard, integrations registry, and channel list/doctor commands - Include unit tests for user allowlist, deduplication, and config
This commit is contained in:
parent
d94d7baa14
commit
ed71bce447
5 changed files with 659 additions and 5 deletions
|
|
@ -7,6 +7,7 @@ pub mod irc;
|
|||
pub mod lark;
|
||||
pub mod matrix;
|
||||
pub mod signal;
|
||||
pub mod qq;
|
||||
pub mod slack;
|
||||
pub mod telegram;
|
||||
pub mod traits;
|
||||
|
|
@ -21,6 +22,7 @@ pub use irc::IrcChannel;
|
|||
pub use lark::LarkChannel;
|
||||
pub use matrix::MatrixChannel;
|
||||
pub use signal::SignalChannel;
|
||||
pub use qq::QQChannel;
|
||||
pub use slack::SlackChannel;
|
||||
pub use telegram::TelegramChannel;
|
||||
pub use traits::Channel;
|
||||
|
|
@ -719,6 +721,7 @@ pub fn handle_command(command: crate::ChannelCommands, config: &Config) -> Resul
|
|||
("IRC", config.channels_config.irc.is_some()),
|
||||
("Lark", config.channels_config.lark.is_some()),
|
||||
("DingTalk", config.channels_config.dingtalk.is_some()),
|
||||
("QQ", config.channels_config.qq.is_some()),
|
||||
] {
|
||||
println!(" {} {name}", if configured { "✅" } else { "❌" });
|
||||
}
|
||||
|
|
@ -881,6 +884,17 @@ pub async fn doctor_channels(config: Config) -> Result<()> {
|
|||
));
|
||||
}
|
||||
|
||||
if let Some(ref qq) = config.channels_config.qq {
|
||||
channels.push((
|
||||
"QQ",
|
||||
Arc::new(QQChannel::new(
|
||||
qq.app_id.clone(),
|
||||
qq.app_secret.clone(),
|
||||
qq.allowed_users.clone(),
|
||||
)),
|
||||
));
|
||||
}
|
||||
|
||||
if channels.is_empty() {
|
||||
println!("No real-time channels configured. Run `zeroclaw onboard` first.");
|
||||
return Ok(());
|
||||
|
|
@ -1160,6 +1174,14 @@ pub async fn start_channels(config: Config) -> Result<()> {
|
|||
)));
|
||||
}
|
||||
|
||||
if let Some(ref qq) = config.channels_config.qq {
|
||||
channels.push(Arc::new(QQChannel::new(
|
||||
qq.app_id.clone(),
|
||||
qq.app_secret.clone(),
|
||||
qq.allowed_users.clone(),
|
||||
)));
|
||||
}
|
||||
|
||||
if channels.is_empty() {
|
||||
println!("No channels configured. Run `zeroclaw onboard` to set up channels.");
|
||||
return Ok(());
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue