# QimenBot **Repository Path**: lvyunqi/QimenBot ## Basic Information - **Project Name**: QimenBot - **Description**: 基于Rust的QQ机器人快速开发框架 - **Primary Language**: Rust - **License**: MIT - **Default Branch**: main - **Homepage**: https://lvyunqi.github.io/QimenBot/ - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-05-04 - **Last Updated**: 2026-07-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README
QimenBot Logo # QimenBot _基于 Rust 的多协议 Bot 框架_ [![License](https://img.shields.io/github/license/lvyunqi/QimenBot?style=flat-square)](https://github.com/lvyunqi/QimenBot/blob/main/LICENSE) [![Rust](https://img.shields.io/badge/Rust-2024_Edition-orange?style=flat-square&logo=rust)](https://www.rust-lang.org/) [![OneBot 11](https://img.shields.io/badge/OneBot-11-black?style=flat-square)](https://github.com/botuniverse/onebot-11) [![QQ Official](https://img.shields.io/badge/QQ_Official-Bot-blue?style=flat-square)](docs/guide/qq-official-quickstart.md) **QQ 交流群:835684778** · [点击加入群聊【QimenBot】](https://qun.qq.com/universal-share/share?ac=1&authKey=0sFE1a6DbXGo70vp3VpylxRQ8AmXY%2BgpIAbrB4Cgf9qjT634oSVcrHDWptDNP3%2Fq&busi_data=eyJncm91cENvZGUiOiI4MzU2ODQ3NzgiLCJ0b2tlbiI6IitmMTBOWS96UXQ2Tk9nakgrOWZFMElPL0VXcFJnNmp0c0NSS0tpK25wY24xNEpGV2MvdjY1c2VBL3ArM09TQngiLCJ1aW4iOiI0MzQ2NTgxOTgifQ%3D%3D&data=EJZhsrc7rxEPVPxGeDybFi7TfocR3lNIFijyePfdpsQTTzNNnqoiMvuahA0t8HoN8DVZR9aKBCKcTxDKmOb8IQ&svctype=4&tempid=h5_group_info) **简体中文** | [English](README_EN.md) | [日本語](README_JA.md)
--- QimenBot 是一个用 Rust 编写的模块化、可扩展的聊天机器人框架。它将**可复用的框架层**与**参考 Host 实现**分离,既可以直接部署官方 Host,也可以基于框架层构建自己的 Bot 平台。 ## 特性 - **多协议支持** — OneBot 11(生产就绪)、官方 QQ Bot(预览)、OneBot 12 / Satori(预留扩展点) - **多传输模式** — 正向 WebSocket、反向 WebSocket、HTTP API、HTTP POST、官方 Gateway + OpenAPI - **声明式插件开发** — `#[module]` / `#[commands]` / `#[notice]` 宏生成注册与路由代码 - **拦截器链** — `pre_handle` / `after_completion`,支持黑名单、权限校验、快捷指令改写等 - **命令系统** — 别名、示例、分类、权限等级、消息过滤器,自动生成 `/help` - **系统事件路由** — 群通知、好友请求和 Meta 事件通过注解路由分发 - **运行时保护** — 令牌桶限流、消息去重、群事件过滤、插件 ACL - **动态插件** — `#[dynamic_plugin]` 宏声明式开发,`dlopen` 热重载,ABI 稳定 - **请求自动化** — 好友/群邀请的自动审批,基于白名单、黑名单、关键词过滤 - **完善的 OneBot 11 API** — 消息、群管理、文件、频道、表情回应等 40+ 操作封装 - **官方 QQ Bot 接入** — 支持 QQ 群 @、QQ 单聊 C2C、频道 @、频道私信和 Markdown / Keyboard 等消息能力 ## 架构 ``` ┌─────────────────────────────────────────────────────┐ │ 应用层 (apps/) │ │ qimenbotd (守护进程) qimenctl (CLI) │ ├─────────────────────────────────────────────────────┤ │ Official Host 层 │ │ qimen-official-host · qimen-config · observability │ ├─────────────────────────────────────────────────────┤ │ Framework 层 (可复用) │ │ runtime · plugin-api · plugin-host · message │ │ protocol-core · transport-core · command-registry │ ├─────────────────────────────────────────────────────┤ │ 适配器 & 传输 │ │ adapter-onebot11 · adapter-qqbot │ │ transport-ws · transport-http · transport-qqbot │ ├─────────────────────────────────────────────────────┤ │ 内置模块 │ │ mod-command · mod-admin · mod-scheduler · mod-bridge │ └─────────────────────────────────────────────────────┘ ``` ## 快速开始 ### 环境要求 - Rust 1.89+(2024 Edition) - 一个 OneBot 11 实现(如 [Lagrange.OneBot](https://github.com/LagrangeDev/Lagrange.Core)、[NapCat](https://github.com/NapNeko/NapCatQQ) 等) 如果接入官方 QQ Bot,不需要 OneBot 实现端,请参考 [官方 QQ Bot 接入](docs/guide/qq-official-quickstart.md)。 ### 构建 & 运行 ```bash git clone https://github.com/lvyunqi/QimenBot.git cd QimenBot # 编辑配置(修改 endpoint、owners 等) vim config/base.toml # 运行 cargo run ``` ## 配置详解 框架启动时只读取一个配置文件:**`config/base.toml`**。所有全局设置和 Bot 实例都在这一个文件中定义。 > `config/bots/` 目录下的 `.toml` 文件**不会被框架自动加载**,它们仅作为多 Bot 场景下的管理参考/备份模板。 ### 配置文件结构总览 ``` config/base.toml ← 框架唯一读取的配置文件 │ ├── [runtime] 全局运行时设置 ├── [observability] 日志与监控 ├── [official_host] 模块加载(全局共享) │ ├── [[bots]] Bot 实例 1(每个 Bot 独立配置) ├── [[bots]] Bot 实例 2 └── [[bots]] Bot 实例 3 ... ``` 关键概念:**`[official_host]` 是全局的,`[[bots]]` 是每个 Bot 实例独立的**。 ``` ┌────────────────────────────────────────────────────┐ │ [official_host](全局) │ │ 决定框架加载哪些模块和插件 │ │ 所有 Bot 共享同一套模块代码 │ ├────────────────────────────────────────────────────┤ │ [[bots]] qq-main │ [[bots]] qq-backup │ │ ├─ 连接地址 endpoint │ ├─ 监听地址 bind │ │ ├─ enabled_modules │ ├─ enabled_modules │ │ ├─ owners / admins │ ├─ owners / admins │ │ ├─ 好友请求策略 │ └─ ... │ │ ├─ 群邀请策略 │ │ │ ├─ 戳一戳回复 │ │ │ └─ 限流器 limiter │ │ └────────────────────────────────────────────────────┘ ``` - `[official_host]` 控制"加载哪些模块到内存" - `[[bots]].enabled_modules` 控制"这个 Bot 实际启用哪些模块" - 全局可加载多个模块,各 Bot 通过 `enabled_modules` 选择实际启用的模块 --- ### `[runtime]` — 运行时 ```toml [runtime] env = "dev" # 运行环境:"dev" 或 "prod" shutdown_timeout_secs = 15 # 关闭信号后等待任务完成的超时(秒),超时强制退出 task_grace_secs = 5 # 后台任务(定时器、重连等)的优雅退出等待(秒) ``` ### `[observability]` — 日志与监控 ```toml [observability] level = "info" # 日志级别:trace / debug / info / warn / error json_logs = false # true = JSON 格式输出(适合 ELK/Loki 采集) metrics_bind = "127.0.0.1:9090" # Metrics 暴露地址(预留) ``` ### `[official_host]` — 全局模块加载 这个区块决定框架启动时**加载哪些模块到内存**。它是全局的,所有 Bot 共享。 ```toml [official_host] # 内置模块(框架自带的核心功能) # 可选值: # "command" — 命令系统(/ping、/echo、/help 等) # "admin" — 管理模块(权限管理、插件管理) # "scheduler" — 定时任务调度器 # "bridge" — 消息桥接(跨群/跨bot转发) builtin_modules = ["command", "admin", "scheduler", "bridge"] # 第三方插件模块(填写 #[module(id = "xxx")] 中的 id) # 示例插件可用 id: # "example-plugin" — 基础命令(向后兼容别名) # "example-basic" — 基础命令(ping、echo、whoami、ban、stop) # "example-message" — 消息构建(rich、parse、card、keyboard) # "example-events" — 事件处理(戳一戳、入群欢迎、好友请求) plugin_modules = ["example-plugin"] # 插件启用/禁用状态的持久化文件 # 用 /plugins 命令修改的状态会保存在这里,重启后恢复 plugin_state_path = "config/plugin-state.toml" # 动态插件(.so/.dll/.dylib)的扫描目录 plugin_bin_dir = "plugins/bin" ``` ### `[[bots]]` — Bot 实例配置 每个 `[[bots]]` 块定义一个独立的 Bot 实例。可以配置多个。每个 Bot 有自己的连接地址、权限、审批策略等——**互不影响**。 #### 连接与身份 ```toml [[bots]] id = "qq-main" # Bot 唯一标识(不可重复) protocol = "onebot11" # 通信协议:onebot11 / onebot12 / satori transport = "ws-forward" # 传输方式(见下表) endpoint = "ws://127.0.0.1:3001" # ws-forward 时填连接地址 # bind = "0.0.0.0:6701" # ws-reverse 时填监听地址 # path = "/onebot/reverse" # ws-reverse 时填路径 # access_token = "${QQ_TOKEN}" # 连接鉴权 Token(支持环境变量) enabled = true # 是否启用(false 则跳过) ``` **传输方式说明:** | transport | 方向 | 必填字段 | 说明 | |-----------|------|---------|------| | `ws-forward` | 框架 → OneBot | `endpoint` | 框架主动连接 OneBot 实现端的 WebSocket | | `ws-reverse` | OneBot → 框架 | `bind` + `path` | 框架监听,OneBot 实现端主动连接过来 | | `http` | 双向 HTTP | `endpoint` | HTTP API + HTTP POST | #### 模块与权限 ```toml # 此 Bot 启用的模块(从 official_host 已加载的模块中选择) # 留空 = 使用 builtin_modules 全部 enabled_modules = ["command", "admin", "scheduler"] # 所有者 ID 列表(最高权限:重启、插件管理、所有命令) owners = ["123456"] # 管理员 ID 列表(管理权限:禁言、踢人等 role = "admin" 的命令) admins = ["789012"] ``` > `[official_host].builtin_modules` 和 `[[bots]].enabled_modules` 的关系: > - `builtin_modules` 决定"框架加载哪些模块代码"(全局) > - `enabled_modules` 决定"这个 Bot 实际使用哪些模块"(每 Bot 独立) > - `enabled_modules` 里的模块必须在 `builtin_modules` 或 `plugin_modules` 中已声明 #### 好友请求自动审批 ```toml # 总开关:是否自动同意所有好友请求 auto_approve_friend_requests = false # 用户白名单:这些用户的请求始终自动同意(不受总开关影响) auto_approve_friend_request_user_whitelist = ["111111", "222222"] # 用户黑名单:这些用户的请求始终自动拒绝(优先级高于白名单) auto_approve_friend_request_user_blacklist = [] # 验证消息关键词白名单:验证消息中包含这些关键词则自动同意 auto_approve_friend_request_comment_keywords = ["来自群"] # 验证消息关键词黑名单:验证消息中包含这些关键词则自动拒绝 auto_reject_friend_request_comment_keywords = ["广告"] # 自动同意时设置的好友备注 auto_approve_friend_request_remark = "" ``` #### 群邀请自动审批 ```toml # 总开关:是否自动同意所有群邀请 auto_approve_group_invites = false # 邀请者用户白名单 auto_approve_group_invite_user_whitelist = [] # 邀请者用户黑名单 auto_approve_group_invite_user_blacklist = [] # 群号白名单:被邀请加入这些群时自动同意 auto_approve_group_invite_group_whitelist = ["12345678"] # 群号黑名单:被邀请加入这些群时自动拒绝 auto_approve_group_invite_group_blacklist = [] # 邀请验证消息关键词白名单 auto_approve_group_invite_comment_keywords = [] # 邀请验证消息关键词黑名单 auto_reject_group_invite_comment_keywords = [] # 自动拒绝时的拒绝理由 auto_reject_group_invite_reason = "" ``` #### 戳一戳自动回复 ```toml # 是否启用戳一戳自动回复(被戳时自动回复一条消息) auto_reply_poke_enabled = true # 回复内容 auto_reply_poke_message = "别戳了,我在忙。" ``` #### 令牌桶限流器 ```toml # 针对此 Bot 的消息限流(防止刷屏) [bots.limiter] enable = false # 是否启用限流 rate = 5.0 # 每秒恢复的令牌数(默认 5.0) capacity = 10 # 令牌桶容量(默认 10,即最多突发处理 10 条) timeout_secs = 0 # 等待令牌的超时(0 = 不等待,直接丢弃) ``` --- ### 环境变量 配置值支持 `${ENV_VAR}` 格式的环境变量占位符,框架启动时自动替换: ```toml access_token = "${QQ_TOKEN}" # 从环境变量 QQ_TOKEN 读取 endpoint = "${ONEBOT_WS_ENDPOINT}" # 从环境变量读取连接地址 ``` 如果环境变量不存在,会被替换为空字符串。 ### 环境覆盖文件 `config/dev.toml` 和 `config/prod.toml` 是预设的环境差异化配置参考。当前框架只读取 `config/base.toml`,这两个文件用于手动切换不同环境时参考或复制。 ### 完整配置示例 ```toml [runtime] env = "dev" shutdown_timeout_secs = 15 task_grace_secs = 5 [observability] level = "info" json_logs = false metrics_bind = "127.0.0.1:9090" [official_host] builtin_modules = ["command", "admin", "scheduler"] plugin_modules = ["example-plugin"] [[bots]] id = "qq-main" protocol = "onebot11" transport = "ws-forward" endpoint = "ws://127.0.0.1:3001" enabled = true owners = ["123456"] auto_reply_poke_enabled = true auto_reply_poke_message = "别戳了,我在忙。" ``` ## 插件开发 QimenBot 通过过程宏将插件开发降至最简。完整示例见 [`plugins/qimen-plugin-example/`](plugins/qimen-plugin-example/)。 ### 最小示例 ```rust use qimen_plugin_api::prelude::*; #[module(id = "my-plugin", version = "0.1.0")] #[commands] impl MyPlugin { #[command("Say hello")] async fn hello(&self) -> &str { "Hello from QimenBot!" } } ``` 以上代码构成一个可用插件。各宏的作用如下。 ### `#[module]` — 声明模块 标记在 `impl` 块上方,用于声明插件模块。宏自动创建 `struct MyPlugin;` 结构体并生成 `Module` trait 实现。 ```rust #[module( id = "my-plugin", // 必填,模块唯一标识 version = "0.1.0", // 可选,默认 "0.1.0" name = "My Plugin", // 可选,默认取结构体名 description = "...", // 可选 interceptors = [MyInterceptor] // 可选,拦截器列表 )] ``` ### `#[commands]` — 扫描命令和事件 紧跟在 `#[module]` 下面。扫描 `impl` 块里所有带 `#[command]`/`#[notice]`/`#[request]`/`#[meta]` 的方法,自动生成 `CommandPlugin` 和 `SystemPlugin` 实现。 ### `#[command]` — 定义聊天命令 ```rust #[command( "Echo back the given text", // 必填,命令描述 aliases = ["e"], // 可选,别名列表 examples = ["/echo hello"], // 可选,使用示例 category = "examples", // 可选,默认 "general" role = "admin", // 可选,"admin" 或 "owner" hidden, // 可选,隐藏命令 )] async fn echo(&self, args: Vec) -> Message { ... } ``` **命令名自动推导**:未指定 `name = "xxx"` 时,宏使用**函数名**作为命令名,并将下划线 `_` 替换为连字符 `-`: | 函数名 | 推导出的命令名 | 用户输入 | |--------|---------------|---------| | `ping` | `"ping"` | `/ping` | | `echo` | `"echo"` | `/echo hello` | | `group_info` | `"group-info"` | `/group-info` | **可用的方法签名**:宏根据参数类型注入相应数据: ```rust // 无参数 — 最简单 async fn ping(&self) -> Message { ... } // 仅参数 — 框架自动按空格拆分命令后的文字 async fn echo(&self, args: Vec) -> Message { ... } // 仅上下文 — 获取发送者、群号等信息 async fn whoami(&self, ctx: &CommandPluginContext<'_>) -> CommandPluginSignal { ... } // 上下文 + 参数(ctx 必须在前) async fn ban(&self, ctx: &CommandPluginContext<'_>, args: Vec) -> CommandPluginSignal { ... } ``` ### `#[notice]` / `#[request]` / `#[meta]` — 系统事件路由 ```rust // 通知事件(可同时监听多个类型) #[notice(GroupPoke, PrivatePoke)] async fn on_poke(&self) -> Message { ... } // 请求事件 #[request(Friend)] async fn on_friend(&self, ctx: &SystemPluginContext<'_>) -> SystemPluginSignal { ... } // 元事件 #[meta(Heartbeat)] async fn on_heartbeat(&self) -> SystemPluginSignal { ... } ``` ### 返回值自动包装 方法可以返回以下任意类型,框架自动转换为信号: | 返回类型 | 行为 | |---------|------| | `Message` | 回复该消息 | | `String` / `&str` | 回复文本消息 | | `CommandPluginSignal` | 完全控制(Reply / Continue / Block / Ignore) | | `Result` | Ok → 正常处理,Err → 回复 `"Error: {e}"` | ### 拦截器 在事件到达插件之前/之后进行预处理: ```rust pub struct MyInterceptor; #[async_trait] impl MessageEventInterceptor for MyInterceptor { async fn pre_handle(&self, _bot_id: &str, event: &NormalizedEvent) -> bool { // 返回 false 拦截事件,true 放行 true } async fn after_completion(&self, _bot_id: &str, _event: &NormalizedEvent) { // 所有插件处理完毕后执行(逆序) } } // 在 #[module] 中注册拦截器 #[module(id = "my-plugin", interceptors = [MyInterceptor])] #[commands] impl MyPlugin { /* ... */ } ``` ### 宏的完整文档 宏系统的详细原理说明(包括宏展开后的完整代码对比)请参阅[示例插件文档](plugins/qimen-plugin-example/README.md#宏系统详解)。 ### 事件处理流程 ``` 收到事件 → 系统事件分发(notice / request / meta) → 消息去重 → 群事件过滤 → 令牌桶限流 → 拦截器链 pre_handle → 权限解析 → 命令匹配 & 插件分发 → 拦截器链 after_completion ``` ## 动态插件开发 除了与框架一同编译的**静态插件**(`#[module]` 宏),QimenBot 还支持**动态插件**——编译为 `.so`(Linux)/ `.dll`(Windows)/ `.dylib`(macOS)的独立库,运行时通过 `dlopen` 加载。 ### 两种插件模式对比 | 特性 | 静态插件 | 动态插件 | |------|---------|---------| | 编译方式 | 与框架一同编译 | 独立编译为动态库 | | 声明方式 | `#[module]` + `#[commands]` 宏 | `#[dynamic_plugin]` 宏 | | API 访问 | 完整(async、OneBotActionClient 等) | 同步 FFI(宏自动生成导出代码) | | 消息构建 | `MessageBuilder` 链式 | `CommandResponse::builder()` / `SendBuilder` | | 拦截器 | `MessageEventInterceptor` trait | `#[pre_handle]` / `#[after_completion]` | | HTTP Webhook | 由应用自行挂载 HTTP 服务 | API 0.5 `#[webhook]`,由框架统一提供网关 | | 生命周期 | 随框架启停 | `#[init]` / `#[shutdown]` 钩子 | | 热重载 | 需要重启进程 | `/plugins reload` 即可 | | 适用场景 | 核心功能、需要异步 API | 第三方扩展、快速迭代 | ### 在主仓库外独立开发 动态插件不需要加入 QimenBot 主 workspace。下面使用包含稳定账号选择接口的 crates.io `0.1.12` 版本: ```toml [package] name = "qimen-dynamic-plugin-myplugin" version = "0.1.0" edition = "2024" rust-version = "1.89" [lib] crate-type = ["cdylib"] [dependencies] abi-stable-host-api = "0.1.12" qimen-dynamic-plugin-derive = "0.1.12" abi_stable = "0.11" ``` [`abi-stable-host-api`](https://crates.io/crates/abi-stable-host-api) 和 [`qimen-dynamic-plugin-derive`](https://crates.io/crates/qimen-dynamic-plugin-derive) `0.1.12` 支持动态插件 API `0.1` 至 `0.5`,并提供 `BotApi::for_account` 与 `SendBuilder::bot_account`。crate 发布版本与插件描述符中的 ABI API 相互独立。API `0.5` 包含 API `0.4` 的实时主动发送能力和 Webhook Gateway,新建插件应显式声明 `api = "0.5"`。`api = "0.4"` 用于兼容不需要 Webhook 的已有插件;未声明 `api` 时,过程宏生成兼容旧宿主的 API `0.3` 插件。 仓库外的插件不需要 `[workspace]`。只有把独立插件放在 QimenBot 仓库目录内、但不加入主 workspace 时,才需要在插件 `Cargo.toml` 中添加空的 `[workspace]` 表。 ### 最小动态插件 使用 `#[dynamic_plugin]` 过程宏,无需手写 FFI 导出代码: ```rust use abi_stable_host_api::*; use qimen_dynamic_plugin_derive::dynamic_plugin; #[dynamic_plugin(id = "my-plugin", version = "0.1.0")] mod my_plugin { use super::*; #[command(name = "hello", description = "Say hello")] fn hello(req: &CommandRequest) -> CommandResponse { CommandResponse::text(&format!("Hello, {}!", req.sender_id)) } } ``` 宏自动生成 `qimen_plugin_descriptor()` 和所有 `extern "C" fn` 导出,插件代码负责实现业务逻辑。 ### API 0.4+ 实时主动推送 实时主动发送从 API `0.4` 开始提供,API `0.5` 完整包含该能力。新建插件应显式声明 API `0.5`,并为每次发送指定稳定的 Bot 账号或运行时实例别名。OneBot 部署应在 `[[bots]]` 中把 QQ / `self_id` 配置为 `account_id`: ```toml [[bots]] id = "qq-reverse" account_id = "2733944636" protocol = "onebot11" transport = "ws-reverse" ``` ```rust use abi_stable_host_api::{BotApi, SendEnqueueStatus}; use qimen_dynamic_plugin_derive::dynamic_plugin; #[dynamic_plugin(id = "push-example", version = "0.1.0", api = "0.5")] mod push_example { use super::*; fn push_now() { match BotApi::for_account("2733944636") .send_group_msg("123456", "后台实时通知") { SendEnqueueStatus::Accepted => {} status => eprintln!("主动发送未被宿主接受: {status:?}"), } } } ``` `BotApi::for_bot("qq-main")` 和 `.bot("qq-main")` 仍然可用,适合必须精确选择某个部署实例的场景;一般业务插件优先使用稳定账号,这样部署侧修改 `id` 后无需重新编译插件。 `Accepted` 仅表示宿主已复制请求并接受入队,不表示网络发送已经成功。`try_send()` 还可能返回 `HostUnavailable`、`InvalidRequest`、`BotNotFound`、`BotDisabled`、`QueueFull` 或 `HostShuttingDown`。实时接口支持私聊、群聊、频道和频道私信;OneBot 频道目标通过 `SendBuilder::guild_id(...)` 补充 `guild_id`。 宿主默认给每个启用 Bot 建立容量为 `256` 的独立队列,离线请求最多等待 `60` 秒: ```toml [official_host.proactive_send] queue_capacity = 256 offline_ttl_secs = 60 ``` API 0.4/0.5 的 Host API 都会在插件 `init` 前绑定,因此后台线程不需要等待命令、事件或 Heartbeat。插件必须在 `shutdown` 中停止并 `join` 自己创建的线程,然后宿主才会解绑 Host API 和卸载动态库。完整目标映射、状态码和线程示例见 [API 0.4+ 实时主动推送](docs/advanced/dynamic-proactive-send-v04.md)。 ### API 0.5 Webhook Gateway API `0.5` 动态插件可以声明同步 HTTP Webhook,由框架统一监听、鉴权、限制请求大小和并发量,并把请求精确路由到插件: ```rust use abi_stable_host_api::{WebhookRequest, WebhookResponse}; use qimen_dynamic_plugin_derive::dynamic_plugin; #[dynamic_plugin(id = "webhook-example", version = "0.1.0", api = "0.5")] mod webhook_example { use super::*; #[webhook(method = "POST", path = "/events")] fn receive_event(request: &WebhookRequest) -> WebhookResponse { WebhookResponse::text(200, format!("received {} bytes", request.body.len())) } } ``` 启用网关后,该处理器的完整地址是 `/webhooks/webhook-example/events`: ```toml [official_host.webhook] enabled = true bind = "127.0.0.1:8088" base_path = "/webhooks" max_body_bytes = 1048576 request_timeout_ms = 5000 max_in_flight = 64 access_token = "" ``` 网关默认关闭且只监听回环地址。生产部署建议配置 Bearer token、在反向代理处启用 TLS,并由插件按第三方协议验证 HMAC 签名和时间戳。Webhook 回调中如需主动发送消息,必须通过 `BotApi::for_account(...)` / `BotApi::for_bot(...)` 或 `.bot_account(...)` / `.bot(...).try_send()` 明确选择 Bot。完整配置、状态码、热重载和安全边界见 [API 0.5 动态插件 Webhook Gateway](docs/advanced/dynamic-webhook-v05.md)。 ### 构建 & 部署 ```bash # 1. 在任意目录创建独立 crate cargo new --lib qimen-dynamic-plugin-myplugin # Cargo.toml 中设置 crate-type = ["cdylib"] 并添加上述 crates.io 依赖 # 2. 编译 cd qimen-dynamic-plugin-myplugin cargo build --release # 3. 部署:复制或上传动态库到 QimenBot 的 plugin_bin_dir scp target/release/libqimen_dynamic_plugin_myplugin.so user@bot-host:/opt/qimenbot/plugins/bin/ # Windows: Copy-Item target/release/qimen_dynamic_plugin_myplugin.dll C:\qimenbot\plugins\bin\ # 4. 在 Bot 中执行 /plugins reload 热重载 ``` 动态库必须针对 QimenBot 宿主的操作系统和 CPU 架构构建。完整流程见[动态插件开发文档](docs/plugin/dynamic.md)。 ### 宏属性一览 ```rust #[dynamic_plugin(id = "my-plugin", version = "0.1.0")] mod my_plugin { // 生命周期 #[init] fn on_init(config: PluginInitConfig) -> PluginInitResult { ... } #[shutdown] fn on_shutdown() { ... } // 命令(支持 name, description, aliases, category, role, scope) #[command(name = "greet", description = "打招呼", aliases = "hi,hello", role = "admin", scope = "group")] fn greet(req: &CommandRequest) -> CommandResponse { ... } // 拦截器 #[pre_handle] fn on_pre_handle(req: &InterceptorRequest) -> InterceptorResponse { ... } // 系统事件路由 #[route(kind = "notice", events = "GroupPoke,PrivatePoke")] fn on_poke(req: &NoticeRequest) -> NoticeResponse { ... } } ``` ### 响应构建 ```rust // 纯文本快捷回复 CommandResponse::text("hello") // 链式构建富媒体回复(引用原消息 + @发送者 + 文本 + 表情) CommandResponse::builder() .reply(msg_id) .at(sender_id) .text(" 你好!") .face(1) .build() // 兼容 API 0.1-0.3:在当前 FFI 回调返回后由宿主 flush BotApi::send_group_msg(group_id, "通知内容"); SendBuilder::private(user_id).text("私聊消息").send(); // API 0.4:按稳定账号选择 Bot,立即提交到对应实例的实时队列 let status = BotApi::for_account("2733944636") .send_group_msg(group_id, "实时通知"); let status = SendBuilder::channel(channel_id) .guild_id(guild_id) .bot_account("2733944636") .text("频道通知") .try_send(); ``` ### 运行时管理 | 命令 | 说明 | |------|------| | `/plugins reload` | 热重载:重新扫描 plugin_bin_dir,卸载旧库,加载新库 | | `/plugins enable ` | 启用插件(动态/静态均可) | | `/plugins disable ` | 禁用插件(持久化到 plugin-state.toml) | | `/dynamic-errors` | 查看动态插件健康状态(熔断器、错误历史) | | `/dynamic-errors clear` | 清除错误计数,解除隔离 | ### 熔断器机制 动态插件内置熔断器保护: - 连续 3 次失败 → 插件自动隔离 60 秒 - 隔离期间所有请求直接返回错误 - 成功执行后自动重置失败计数 - `/dynamic-errors clear` 手动重置 完整示例见 [`plugins/qimen-dynamic-plugin-example/`](plugins/qimen-dynamic-plugin-example/)。 ## 内置命令 | 命令 | 说明 | |------|------| | `ping` / `/ping` | 返回 pong | | `echo ` / `/echo ` | 回显文本 | | `status` / `/status` | 运行时状态 | | `help` / `/help` | 自动生成的帮助信息 | | `plugins` / `/plugins` | 已加载插件列表 | | `plugins reload` | 热重载动态插件 | | `dynamic-errors` | 动态插件健康状态 | 命令触发方式:私聊直发、`/前缀`、`@bot 提及`、回复触发。 ## 项目结构 ``` QimenBot/ ├── apps/ │ ├── qimenbotd/ # Bot 守护进程 │ └── qimenctl/ # CLI 管理工具 ├── crates/ │ ├── qimen-plugin-api/ # 插件 API(CommandPlugin, SystemPlugin, Module) │ ├── qimen-plugin-derive/ # 过程宏(#[module], #[commands], #[command]...) │ ├── qimen-runtime/ # 事件分发、插件编排、拦截器 │ ├── qimen-message/ # 消息模型(Segment, MessageBuilder) │ ├── qimen-adapter-onebot11/ # OneBot 11 适配器 │ ├── qimen-adapter-qqbot/ # 官方 QQ Bot 协议适配器 │ ├── qimen-transport-ws/ # WebSocket 传输(TLS、自动重连) │ ├── qimen-transport-http/# HTTP 传输 │ ├── qimen-transport-qqbot/# 官方 QQ Bot Gateway/OpenAPI │ ├── qimen-mod-command/ # 命令检测与匹配 │ ├── qimen-mod-admin/ # 权限管理 │ ├── qimen-mod-scheduler/ # Cron 定时任务 │ └── ... # 更多核心 crate ├── plugins/ │ ├── qimen-plugin-example/ # 静态插件示例(含详细文档) │ └── qimen-dynamic-plugin-example/# 动态插件示例(独立编译) └── config/ ├── base.toml # 主配置(框架唯一读取的文件) ├── dev.toml # 开发环境参考配置 ├── prod.toml # 生产环境参考配置 ├── plugin-state.toml # 插件启用/禁用状态(自动管理) └── bots/ # Bot 独立配置参考(不会被自动加载) ├── qq-main.toml ├── qq-backup.toml └── qq-official.toml ``` ## 协议支持 | 协议 | 状态 | 传输模式 | |------|------|---------| | OneBot 11 | ✅ 生产就绪 | WS 正向、WS 反向、HTTP API、HTTP POST | | 官方 QQ Bot | 🧪 预览 | Gateway + OpenAPI | | OneBot 12 | 🔲 计划中 | — | | Satori | 🔲 计划中 | — | ## 致谢 QimenBot 的设计参考了以下优秀项目: - [Shiro](https://github.com/MisakaTAT/Shiro) — 基于 Java 的 OneBot 框架,拦截器与插件模型的灵感来源 - [Kovi](https://github.com/ThriceCola/Kovi) — Rust OneBot 框架,简洁 API 设计的参考 ## 许可证 [MIT](LICENSE)