Files
qqbotsdk/docs/api/core.md
T
snowy-yang 7e8794bf5f feat: intents 掩码直传——Bot(intents=) 参数与 INTENTS 环境变量,优先于 intents.toml
Intent 枚举(IntFlag)提升到顶层导出可直接 OR;掩码含未收录位仅告警不拦截。
2026-10-03 20:07:56 +08:00

6.8 KiB
Raw Blame History

核心框架 API

Bot 门面、分发层(EventEmitter)、事件封装(Event)与错误体系。 上手流程见快速开始,分层与装配见架构设计。

顶层导出

from qqbotsdk import (
    Bot,                     # 门面:on/run/start/call_api/api/services
    EventEmitter, EventQueue,   # 分发层
    Intent,                  # 订阅分组位掩码(IntFlag,可 OR 出掩码传 Bot(intents=…))
    BaseProtocol,            # 协议处理器接口(自定义接入方式时继承)
    Config, Connecter,       # 配置与连接器接口
)
名称 说明
Bot(config=None) 门面类,见下节
EventEmitter(queue=None) 分发主体,Bot 内部持有;queue 不传自动创建
EventQueue() 业务事件通道(连接层 → 分发层,单向);需多处共享时手动传入(bot.queue 取实例)
Config frozen dataclass,环境变量一次性读齐(字段表见配置与订阅)
Connecter 连接适配器接口(typing.Protocol),按 CONNECTER 自动选择实现
BaseProtocol 协议处理器接口(protocol.py),自定义接入方式时实现 on_frame(payload)

子包按需导入:

from qqbotsdk.api import BotApi, ApiError
from qqbotsdk.payloads import GroupAtMessage, EVENT_TYPES, parse_event
from qqbotsdk.events import Event

Bot

bot = Bot()                        # 构造即读 .env 校验配置(fail fast)

@bot.on("GROUP_AT_MESSAGE_CREATE") # 注册 handler,语义与 EventEmitter.on 一致
async def handler(msg, api): ...

bot.run()                          # 同步入口:阻塞运行,Ctrl+C 优雅退出
成员 说明
Bot(config=None, *, intents=None) 不传 config 时 Config.load() 读环境变量;缺 APPID/APPSECRET 构造即抛 ValueError。intents 直传订阅掩码(可用 Intent 枚举 OR 出来),优先级 intents 参数 > INTENTS 环境变量 > intents.toml,详见配置与订阅
bot.on(event, fn=None, *, background=False) 注册 handler;event 为事件 t 名或 Opcode,装饰器/直传皆可
bot.run() 同步入口:asyncio.run(start()),KeyboardInterrupt 记日志退出
await bot.start() 异步入口:装配组件并常驻运行,供嵌入外部 asyncio 应用
bot.call_api(method, path, **kwargs) 通用 REST 入口:带鉴权头、429 退避重试、401 刷新 token 重试;kwargs 透传 aiohttp(json=/params= 等)
bot.api 类型化 API 门面(BotApi,97 个方法),启动(run/start)后可用,之前抛 RuntimeError
bot.services dict[type, Any] 组件登记表;SDK 启动登记 8 项内置组件,也可登记自定义类型(见事件处理)
bot.queue 事件队列实例
bot.config Config 实例

EventEmitter

Bot 内部的分发主体(bot._emitter),独立导入用于测试或自定义装配:

ee = EventEmitter()

@ee.on("GROUP_AT_MESSAGE_CREATE")     # 业务事件用 t 名(仅 op=0 会分发到这里)
async def handler(...): ...

@ee.on("GROUP_AT_MESSAGE_CREATE", background=True)   # 后台并发执行,不阻塞事件流
async def slow(...): ...
  • 只分发业务事件:EventEmitter 只处理 op=0(DISPATCH)事件,按 payload 的 t 名路由。协议帧(HELLO/READY/INVALID_SESSION/op=13 等)由各接入方式的协议处理器(WebsocketProtocol/WebhookProtocol)在连接器内就地处理,不进事件队列、也不会触达你的 handler。
  • 注册与顺序:同一函数对同一事件重复注册只生效一次;handler 按注册顺序串行执行(background=True 的除外)。
  • 异常隔离:handler 异常就地记录(loguru),不影响同事件其他 handler 与主循环。
  • 后台并发:background=True 的 handler 进后台任务,emit 不等它;同一事件内失去先后保证,仅用于业务 handler。bot.run() 退出时统一取消在飞后台任务。
  • 业务 handler 的返回值不回流;回复消息请在 handler 里显式调 BotApi。

handler 参数注入约定表见事件处理。

Event

from qqbotsdk.events import Event,业务事件推送信封(op/t/d/id)的轻量封装,只封装信封语义、不做字段名映射;事件体字段请标注对应 payload dataclass(见事件 payload)获取解析结果:

属性 说明
.raw 完整线上 payload(含 op/t/d)
.data d 的 dict 拷贝
.typed d 的 dataclass 解析结果(未知事件类型为 dict)
.type 事件 t 名
.event_id 推送信封顶层的事件 id(与 op/t/d 平级,形如 INTERACTION_CREATE:uuid);非消息事件(INTERACTION_CREATE/GROUP_ADD_ROBOT 等)的被动回复凭据只有这里能拿到,事件体里的裸 UUID 不行(官方点名的常见坑);消息事件的被动回复凭据是事件体的 d.id(payload 的 .id 字段,即 msg_id),不用这里

错误体系

ApiError(RuntimeError),重试后仍失败(HTTP ≥400)时抛出:

属性 说明
.status HTTP 状态码
.code 官方业务 code(响应体中的 code)
.message 官方错误描述

鉴权阶段(换取 access_token)的失败抛 TokenError(from qqbotsdk.token import TokenError),与 ApiError 同构(RuntimeError 子类,同样携带 .status/.code/.message)——appid/secret 配置错误在这里暴露 QQ 返回的真实原因。

BotApi 的请求内核(api/core.py):自动附带 Authorization: QQBot <token> 鉴权头并刷新 token;429 限流自动重试(最多 3 次,优先 Retry-After,退避封顶 30s);401 强制刷新 token 后重试一次。bot.call_api 与全部类型化方法共享该内核。

内部模块索引

维护者视角的分层与装配见架构设计:

模块 职责
bot.py Bot 门面:组件装配、run/start 生命周期
connecter.py WebsocketConnecter / WebhookConnecter:接入归一为业务事件流入、出站帧流出
protocol.py BaseProtocol 协议处理器接口(on_frame,由连接适配器逐帧调用)
ws_protocol.py IDENTIFY/RESUME 鉴权、会话语义与 s 序列号(心跳在 connecter 内)
webhook_protocol.py op=13 验证应答
queue.py / session.py / token.py / crypto.py 业务事件通道、ws 会话状态、token 缓存、Ed25519 签名
model.py Opcode、payload 类型、Intent 位掩码