BotRS - Rust QQ Guild Bot Framework
Author: YinMo19

BotRS 是一个用 Rust 实现的 QQ 频道机器人框架,基于 QQ 频道机器人 API。它提供了类型安全、高性能、易于使用的接口来开发 QQ 频道机器人。
✨ v0.2.0 重大更新:全新消息参数 API
我们完全重构了消息发送 API,告别了多个 None 参数的混乱,引入了结构化参数系统,带来更清洁的开发体验!
🚀 问题解决
旧版 API(已弃用):
api.post_message(
token, "channel_id", Some("Hello!"),
None, None, None, None, None, None, None, None, None
).await?;
新版 API(推荐):
use botrs::models::message::MessageParams;
let params = MessageParams::new_text("Hello!");
api.post_message_with_params(token, "channel_id", params).await?;
🎯 新 API 方法(推荐)
- [
post_message_with_params] - 发送频道消息(使用 [MessageParams])
- [
post_group_message_with_params] - 发送群消息(使用 [GroupMessageParams])
- [
post_c2c_message_with_params] - 发送私聊消息(使用 [C2CMessageParams])
- [
post_dms_with_params] - 发送私信(使用 [DirectMessageParams])
⚠️ 旧版 API 方法(已弃用)
post_message → 请使用 post_message_with_params
post_group_message → 请使用 post_group_message_with_params
post_c2c_message → 请使用 post_c2c_message_with_params
post_dms → 请使用 post_dms_with_params
🌟 主要优势
- ✨ 更清洁的代码:使用
..Default::default() 替代多个 None 参数
- 📖 更好的可读性:命名字段而非位置参数
- 🛡️ 类型安全:结构化参数防止参数顺序错误
- 🔧 构建器模式:便捷的
.with_reply() 和 .with_file_image() 方法
- 🚀 易于扩展:添加新字段而不破坏现有代码
- 🔄 向后兼容:基于官方 Python botpy API 结构
特性
- ✨ 类型安全 - 完全类型化的 API,编译时捕获错误
- 🚀 高性能 - 基于 Tokio 的异步运行时,支持高并发
- 🔧 易于使用 - 简单直观的 API 设计,快速上手
- 🛡️ 内存安全 - Rust 的所有权系统保证内存安全
- 🔄 事件驱动 - 基于事件的架构,响应各种 QQ 频道事件
- 📝 丰富的文档 - 完整的 API 文档和示例代码
- ⚡ WebSocket 支持 - 实时接收和处理事件
- 🎯 Intent 系统 - 精确控制接收的事件类型
- 🏗️ 结构化 API - 新的参数结构系统,告别多
None 参数
快速开始
安装
将以下内容添加到你的 Cargo.toml:
[dependencies]
botrs = "0.2.0"
tokio = { version = "1.0", features = ["full"] }
tracing = "0.1"
tracing-subscriber = "0.3"
async-trait = "0.1"
基础示例
use botrs::{Client, Context, EventHandler, Intents, Token, Message};
use botrs::models::gateway::Ready;
use botrs::models::message::MessageParams;
use tracing::info;
struct MyBot;
#[async_trait::async_trait]
impl EventHandler for MyBot {
async fn ready(&self, _ctx: Context, ready: Ready) {
info!("Bot {} is ready!", ready.user.username);
}
async fn message_create(&self, ctx: Context, message: Message) {
if message.is_from_bot() {
return;
}
if let Some(content) = &message.content {
if content.trim() == "!ping" {
info!("Received ping command from message ID: {:?}", message.id);
let params = MessageParams::new_text("Pong! 🏓");
if let Some(channel_id) = &message.channel_id {
if let Err(e) = ctx.api.post_message_with_params(&ctx.token, channel_id, params).await {
eprintln!("Failed to reply: {}", e);
}
}
}
}
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt::init();
let token = Token::new("your_app_id", "your_secret");
let intents = Intents::default();
let mut client = Client::new(token, intents, MyBot)?;
client.start().await?;
Ok(())
}
📋 新消息 API 迁移指南
简单文本消息
use botrs::models::message::MessageParams;
let params = MessageParams::new_text("Hello World! 🌍");
api.post_message_with_params(token, "channel_id", params).await?;
带嵌入内容的消息
use botrs::models::message::{MessageParams, Embed};
let embed = Embed {
title: Some("标题".to_string()),
description: Some("这是一个嵌入消息示例".to_string()),
color: Some(0x00ff00),
..Default::default()
};
let params = MessageParams {
content: Some("查看这个嵌入内容!".to_string()),
embed: Some(embed),
..Default::default()
};
api.post_message_with_params(token, "channel_id", params).await?;
回复消息并附带文件
let file_data = std::fs::read("image.png")?;
let params = MessageParams::new_text("这是你要的文件!")
.with_file_image(&file_data)
.with_reply("reply_to_message_id");
api.post_message_with_params(token, "channel_id", params).await?;
群消息发送
use botrs::models::message::GroupMessageParams;
let params = GroupMessageParams::new_text("群里好!")
.with_reply("reply_to_message_id");
api.post_group_message_with_params(token, "group_openid", params).await?;
私聊消息发送
use botrs::models::message::C2CMessageParams;
let params = C2CMessageParams::new_text("私聊消息");
api.post_c2c_message_with_params(token, "user_openid", params).await?;
私信发送
use botrs::models::message::DirectMessageParams;
let params = DirectMessageParams::new_text("私信内容")
.with_reply("reply_to_message_id");
api.post_dms_with_params(token, "guild_id", params).await?;
更详细和更具体的内容可以在 https://docs.rs/botrs 阅读,另有 https://deepwiki.com/YinMo19/botrs 作为 AI 文档可以参照阅读代码结构。
环境变量配置
你可以使用环境变量来配置机器人凭据:
export QQ_BOT_APP_ID="your_app_id"
export QQ_BOT_SECRET="your_secret"
然后在代码中使用:
let token = Token::from_env()?;
事件处理
BotRS 支持多种事件类型:
消息事件
use botrs::{Message, DirectMessage, GroupMessage, C2CMessage};
use botrs::models::message::{MessageParams, GroupMessageParams, C2CMessageParams, DirectMessageParams};
#[async_trait::async_trait]
impl EventHandler for MyBot {
async fn message_create(&self, ctx: Context, message: Message) {
if let Some(content) = &message.content {
println!("Received message: {}", content);
let params = MessageParams::new_text("收到您的消息了!");
if let Some(channel_id) = &message.channel_id {
let _ = ctx.api.post_message_with_params(&ctx.token, channel_id, params).await;
}
}
}
async fn direct_message_create(&self, ctx: Context, message: DirectMessage) {
if let Some(content) = &message.content {
println!("Received DM: {}", content);
let params = DirectMessageParams::new_text("收到您的私信了!");
if let Some(guild_id) = &message.guild_id {
let _ = ctx.api.post_dms_with_params(&ctx.token, guild_id, params).await;
}
}
}
async fn group_message_create(&self, ctx: Context, message: GroupMessage) {
if let Some(content) = &message.content {
println!("Received group message: {}", content);
let params = GroupMessageParams::new_text("群里好!");
let _ = ctx.api.post_group_message_with_params(&ctx.token, &message.group_openid, params).await;
}
}
async fn c2c_message_create(&self, ctx: Context, message: C2CMessage) {
if let Some(content) = &message.content {
println!("Received C2C message: {}", content);
let params = C2CMessageParams::new_text("收到您的私聊消息了!");
if let Some(user_openid) = &message.author.user_openid {
let _ = ctx.api.post_c2c_message_with_params(&ctx.token, user_openid, params).await;
}
}
}
}
频道事件
use botrs::Guild;
#[async_trait::async_trait]
impl EventHandler for MyBot {
async fn guild_create(&self, _ctx: Context, guild: Guild) {
if let Some(name) = &guild.name {
println!("Joined guild: {}", name);
}
}
async fn guild_update(&self, _ctx: Context, guild: Guild) {
if let Some(name) = &guild.name {
println!("Guild updated: {}", name);
}
}
async fn guild_delete(&self, _ctx: Context, guild: Guild) {
if let Some(name) = &guild.name {
println!("Left guild: {}", name);
}
}
}
成员事件
use botrs::Member;
#[async_trait::async_trait]
impl EventHandler for MyBot {
async fn guild_member_add(&self, _ctx: Context, member: Member) {
println!("Member joined: {}", member.user.username);
}
async fn guild_member_update(&self, _ctx: Context, member: Member) {
println!("Member updated: {}", member.user.username);
}
async fn guild_member_remove(&self, _ctx: Context, member: Member) {
println!("Member left: {}", member.user.username);
}
}
Intent 系统
Intent 系统允许你精确控制机器人接收的事件类型:
use botrs::Intents;
let intents = Intents::default();
let intents = Intents::none()
.with_guilds() .with_guild_members() .with_guild_messages() .with_direct_message() .with_public_messages();
let intents = Intents::all();
if intents.is_privileged() {
println!("Contains privileged intents");
}
特权 Intent
某些 Intent 需要特殊权限,可通过 is_privileged() 方法检查:
let intents = Intents::none()
.with_guild_members() .with_guild_messages();
if intents.is_privileged() {
println!("需要申请特殊权限");
}
API 客户端
BotRS 提供了完整的 API 客户端来与 QQ 频道 API 交互:
use botrs::{BotApi, HttpClient, Token};
use botrs::models::message::MessageParams;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let token = Token::new("app_id", "secret");
let http = HttpClient::new(30, false)?; let api = BotApi::new(http);
let bot_info = api.get_bot_info(&token).await?;
println!("Bot: {}", bot_info.username);
let gateway = api.get_gateway(&token).await?;
println!("Gateway URL: {}", gateway.url);
let params = MessageParams::new_text("Hello from BotRS! 🤖");
api.post_message_with_params(&token, "channel_id", params).await?;
Ok(())
}
错误处理
BotRS 提供了统一的错误处理:
use botrs::{BotError, Result};
async fn handle_api_call() -> Result<()> {
match api.get_bot_info(&token).await {
Ok(info) => {
println!("Bot: {}", info.username);
}
Err(BotError::Api { code, message }) => {
eprintln!("API error {}: {}", code, message);
}
Err(BotError::RateLimit { retry_after }) => {
eprintln!("Rate limited, retry after {} seconds", retry_after);
}
Err(e) => {
eprintln!("Other error: {}", e);
}
}
Ok(())
}
配置选项
HTTP 客户端配置
use botrs::HttpClient;
let http = HttpClient::new(60, true)?;
客户端配置
use botrs::Client;
let client = Client::new(token, intents, handler)?;
let http = HttpClient::new(60, true)?; let api = BotApi::new(http);
运行示例
项目包含多个完整的示例机器人,展示新 API 的使用:
export QQ_BOT_APP_ID="your_app_id"
export QQ_BOT_SECRET="your_secret"
cargo run --example simple_bot --features examples
cargo run --example demo_new_message_api --features examples
cargo run --example demo_at_reply_embed --features examples
cargo run --example demo_at_reply_file_data --features examples
cargo run --example demo_at_reply_keyboard --features examples
cargo run --example demo_at_reply_markdown --features examples
cargo run --example demo_group_reply_text --features examples
cargo run --example demo_c2c_reply_text --features examples
cargo run --example demo_dms_reply --features examples
或者传递参数:
cargo run --example demo_new_message_api --features examples -- your_app_id your_secret
开发状态
✅ 已完成功能
- ✅ 基础 HTTP 客户端和 API 封装
- ✅ WebSocket 网关连接和事件处理
- ✅ 完整的 Intent 系统实现
- ✅ 类型安全的错误处理
- ✅ 完整的消息模型 (Message, DirectMessage, GroupMessage, C2CMessage, MessageAudit)
- ✅ 频道、成员、用户、机器人数据模型
- ✅ Token 认证和验证系统
- ✅ 基于 Tokio 的异步支持
- ✅ 与 Python botpy 完全兼容的接口设计
- ✅ 完整的单元测试和文档测试覆盖
- ✅ 详细的 API 文档和使用示例
- ✅ 新的结构化消息参数 API(v0.2.0)
- ✅ 完整的消息发送 API 实现
- ✅ 多种消息类型支持(文本、嵌入、Markdown、键盘、文件)
🔄 计划功能
- 🔄 WebSocket 分片支持
- 🔄 中间件和插件系统
- 🔄 内置命令框架
- 🔄 更多实用示例和教程
- 🔄 性能优化和内存使用优化
- 🔄 更多 QQ 频道 API 功能支持
⚠️ 已知问题
目前代码是从 Python 版本重写来的,测试相对较少。作者自己的 bot 并没有申请很多权限,因此关于 Ark、企业级功能等都没有进行充分测试。不过基础的回复、群聊消息等 API 已经经过测试。
从目前的情况来看,Python 版本中也用到了一些不太准确的地方,可能改动了 API。但是 Python 本身的校验机制是很松的,不像这里使用的 serde 库,在 parse 的时候一个字段对不上直接失败。因此如果有一些消息返回失败,或者哪里很明显的 parse 失败了,请在 issue 中告诉我们。如果你能解决,非常欢迎 PR。
与 Python botpy 的对比
BotRS 的设计灵感来自 Python 的 botpy 库,但提供了以下优势:
| 特性 |
Python botpy |
BotRS |
| 类型安全 |
❌ |
✅ |
| 性能 |
中等 |
高 |
| 内存安全 |
❌ |
✅ |
| 并发模型 |
asyncio |
Tokio |
| 包大小 |
较大 |
较小 |
| 部署 |
需要Python环境 |
单一可执行文件 |
| API 设计 |
多 None 参数 |
结构化参数 |
| 代码可读性 |
一般 |
优秀 |
版本历史
v0.2.0 (最新)
- 🚀 重大更新:引入结构化消息参数 API
- ✨ 新增
MessageParams、GroupMessageParams、C2CMessageParams、DirectMessageParams
- 🔧 新增
post_*_with_params 系列方法
- 📚 完善示例和文档
- ⚠️ 弃用旧的多参数 API(仍可使用,但推荐迁移)
v0.1.3
- 🛠️ 基础功能实现
- 🔄 多参数消息发送 API
- 📖 基础文档和示例
许可证
本项目采用 MIT 许可证。详情请参阅 LICENSE 文件。
贡献
欢迎贡献代码!我的个人 git commit 提交风格是:
[type] simple message
- detail message 1: detailed description.
- detail message 2: detailed description.
- detail message 3: detailed description.
- detail message 4: detailed description.
- etc.
例如:
[feature] add structured message parameters API
- `models/message.rs`: add MessageParams, GroupMessageParams, C2CMessageParams, DirectMessageParams structs.
- `api.rs`: add post_*_with_params methods for structured parameter sending.
- `examples/`: add demo_new_message_api.rs showing the new API usage.
- deprecate old multi-parameter API methods but keep backward compatibility.
支持
架构特点
与 Python botpy 的完全兼容
BotRS 在设计时严格参照 Python botpy 的接口设计,确保:
- 相同的消息模型结构
- 一致的事件处理接口
- 兼容的数据类型定义
- 相同的 Intent 系统
- 更优雅的参数传递方式
类型安全保证
- 编译时类型检查
- Rust 所有权系统保证内存安全
- 详细的错误类型定义
- 可靠的异步处理
- 结构化参数防止运行时错误
相关链接