Commit Graph
14 Commits
Author SHA1 Message Date
snowy-yang feb39b11d5 refactor: 删去 intents 组内事件开关的专属校验(dict 本就被布尔校验拦下) 2026-09-24 22:40:29 +08:00
snowy-yang 7e7dcbaa94 refactor!: Event 收敛为推送信封封装,删除字段名兼容属性
删除 Event 的 user_id/group_id/content/message_id 四个属性:它们是
"兼容群(openid)与频道两套字段名"的映射层,其中 user_id 还带着
旧版群消息 payload 顶层 from_user_id 的回退(现行格式发言人标识在
author 里,该回退永远轮不到)。Event 只保留信封语义:
.raw/.data/.typed/.type/.event_id,事件体字段一律标注 payload
dataclass(如 msg: GroupAtMessage)获取解析结果。

破坏性变更:event.group_id → msg.group_openid、event.message_id →
msg.id,以此类推;被动回复凭据分工不变——消息事件用事件体 d.id
(msg_id),其余事件用信封顶层 event_id。

迁移:examples/group_bot 入群欢迎改标注 GroupAddRobot(已确认
MusicBot 未使用被删属性);GUIDE/API 同步删除对应属性行;测试
重写为信封语义断言 + typed 解析断言。

107 测试全绿,ruff/pyright 干净。
2026-09-24 20:18:29 +08:00
snowy-yang 15e1f5e303 feat: OpenAPI 全量对齐——对照新旧两版官方文档补齐全部接口与事件
- 新增 panel 域:指令面板(斜线指令)增删改查/关联对象 + /v2/menu 全局自定义菜单
- 新增 group 域:群信息/成员/机器人群内状态、入群申请列表与审批、群黑名单、
  群禁言状态、入群自动审批策略(增删改查/执行/白名单)
- v2 补充:流式单聊消息、群/单聊大文件分片上传(预上传+分片确认)、分享链接
- guild 补充:子频道增删改、机器人频道列表、身份组 CRUD 与成员授予/收回、
  成员列表/踢出、全员与批量禁言、接口权限、消息频率设置
- channel 补充:子频道用户/身份组权限、频道私信(建会话/发信/撤回)
- 新增 audio 域(播放控制、上/下麦)与 forum 域(帖子增删查)
- 事件补齐 GROUP_MEMBER_ADD/REMOVE、GROUP_JOIN_REQUEST、SUBSCRIBE_MESSAGE_STATUS;
  Intent 与 intents.toml 补 GROUP_MEMBER_EVENT (1<<24) 分组(默认 false)
2026-09-23 17:46:37 +08:00
snowy-yang 13a1d971be feat: 连接寿命到点前主动重连(服务端约 1 小时会无预警断开)
实测 QQ 服务端在一个连接建立约 1 小时后会自己断开。此前只能等它断:
要么被看门狗判成静默超时、要么等读写失败,都算"异常断开",观感与恢复
路径都不理想。现改为临到期前主动收尾重连——是正常断开 + RESUME 续传,
期间消息由网关补发。

实现:receive_helper 记录寿命截止点(_SERVER_LIFETIME - _RECONNECT_MARGIN,
默认 60min - 10min = 50min),收帧超时取"静默阈值"与"寿命余量"两个截止里
的先到者——静默过久仍抛 TimeoutError 交给看门狗,寿命到点则 return 正常
结束本轮连接,run() 见存活超过 _STABLE_SECONDS 便立刻重连(沿用 b37a53f
的"健康断开零等待"路径),RESUME 带上 session_id 续传。

_connect 的存活秒数天然 >= 50min > _STABLE_SECONDS,主动重连必被判定为
健康断开,无需额外标志位。

测试:新增 test_proactive_reconnect_before_server_lifetime(真实 ws 端到端,
把寿命阈值调到 0.5s 让这一刻立即发生);已验证把寿命阈值关掉后该测试会
超时失败,不是空转到通过。另给 tests/test_reconnect.py 补 CHANGELOG 条目
(b37a53f 漏记),并同步 connecter 模块 docstring / ARCHITECTURE / GUIDE。

90 测试全绿,ruff check/format + pyright 干净。
2026-09-21 18:28:53 +08:00
snowy-yang b37a53f6e0 feat: 重连不再等待并精简连接日志,失败才记断开与退避
- 连接曾稳定存活(>= _STABLE_SECONDS)而被服务端要求重连时立刻重连、
  不等待也不记日志:这期间事件由网关按 RESUME 补发,等待只是徒增盲区
- 仅在连接未能稳定存活(握手失败/看门狗超时/限流/抖动)时才记
  "WebSocket 已断开"并按指数退避重试
- 去掉常规的「WebSocket 已连接/已断开」info,只保留「发送 RESUME」等
  有信息量的行,消除每小时一次的日志噪音
- 新增 tests/test_reconnect.py:健康断开零等待零日志、失败退避翻倍、
  限流 60s、抖动不重置退避
2026-09-21 18:25:16 +08:00
snowy-yang 1552c5207b refactor: 工程化收尾——去 pyee、预计算解析计划与派生密钥、命名与接口一致化
以「语义可读、逻辑清晰、减少心智负担」为目标,不追求极致速度:

- **移除 pyee 依赖**:EventEmitter 改为内置的 `事件名 → handler 列表` 注册表
  (on() 追加、emit() 顺序遍历)。SDK 用不到 pyee 的 once/new_listener/错误
  事件机制,去掉后少一个依赖、分发语义一眼可读。注册语义不变(同函数重复
  注册只生效一次),并补测试锁定「重复注册只生效一次」「按注册顺序执行」。
  破坏性:once/remove_listener 等装饰性 API 不再提供。

- **去掉热路径上的重复计算**(纯缓存,不改语义):
  · payloads 按类缓存解析计划(字段名 + 是否嵌套 Author),不再每次事件重跑
    dataclasses.fields 与联合类型解包;未收录字段照旧忽略(新增回归测试,
    线上 payload 会带 author.union_openid 这类字段)。实测 7.5µs → 2.5µs。
  · crypto 按 AppSecret 缓存派生私钥(每个 webhook 请求都要验签,派生一次
    约 40µs);公钥派生只差 3µs,不再多缓存一层。

- **命名与接口一致性**:
  · WebsocketConnecter.reply_helper → send_helper(它从出站缓冲取帧发送,
    原名会让人误以为还有 reply 队列;model.py 的对应注释同步)
  · Connecter 由 typing.Protocol 改为 abc.ABC,与 BaseProtocol 风格统一

- **webhook 去重改摊还清理**:过期判定按当前 id 做(O(1),且 TTL 外重发的
  同一 id 仍按新事件处理——原先的写法在阈值清理下会误判为重复,已由测试
  抓出并修正),整表清过期项只在表长到阈值时执行,不再每请求 O(n) 扫描。

测试 85 全绿(新增未知字段/解析计划缓存/注册语义/去重摊还与 TTL 过期),
ruff check/format + pyright 干净。文档 ARCHITECTURE/API/CHANGELOG 同步。
2026-09-20 22:45:34 +08:00
snowy-yang 4d19db24e1 refactor!: EventQueue 收敛为单向业务事件通道,出站缓冲归 ws 适配器
协议分流后 reply_queue 只剩 WebsocketConnecter 一个使用者(emitter 不再
回流应答、webhook 完全不用),它已不是"连接层与分发层之间的通道",而是
ws 私有的出站缓冲,却仍挂在共享 EventQueue 上——queue.py 的模块注释
"连接层与分发层之间唯一的跨任务通道"对 reply_queue 不再成立。

删除 EventQueue.reply_queue 与 put_reply/get_reply,EventQueue 只承载
业务事件(op=0,单向)。ws 的出站帧改由 WebsocketConnecter 私有
_outbound 队列承载,heartbeat_helper 与协议应答生产者投递、reply_helper
单任务发送——维持 aiohttp ws 单写者不变量,生产者也不会被发送阻塞。

破坏性变更:EventQueue.reply_queue / put_reply / get_reply 不再存在
(这两个方法本就只由 SDK 内部使用,非用户面)。

文档同步 queue.py 注释、ARCHITECTURE(图与心跳/应答路径)、API 的
EventQueue 说明、CHANGELOG;测试 80 全绿,ruff/pyright 干净。
2026-09-20 22:02:07 +08:00
snowy-yang 7accbd1ead refactor!: 协议帧与业务事件分流,各接入方式配专有协议处理器
BaseProtocol 从 emitter.py 移入新模块 protocol.py,接口由 register(emitter)
改为 async on_frame(payload)(返回需回送的响应体);协议处理器不再注册进
emitter,而由 run_loop 注入对应的 connecter,由适配器逐帧调用。

破坏性变更:只有 op=0 的业务事件进事件队列交给 EventEmitter 分发,
HELLO/READY/INVALID_SESSION/op=13 等协议帧在连接器内就地处理——用户 handler
不再收到协议帧(此前 HELLO/INVALID_SESSION 等会路由到 handler)。
EventEmitter.register_protocol()/handle() 与 emitter 持有协议层的机制删除,
协议类不再用 register() 注册 handler。

附带修掉一处时序耦合:INVALID_SESSION 的会话重置此前依赖分发泵在重连前
消费掉该事件(慢 handler 会推迟它,导致带着已死 session_id 去 RESUME),
现在连接器在 break 重连前同步完成重置。

同时做的事件流优化:
- emit() 先取事件名、无 listener 时不构造 Event(未订阅事件省一次对象与拷贝)
- Event.data 改为惰性拷贝(只用 .typed/.raw 的 handler 不再触发 dict(d))
- ws 重连收尾 await 被取消的 reply/heartbeat 任务,避免异常无人取用
- EventQueue.put_event/put_reply 去掉多余的 return await

测试 80 全绿(新增协议帧处理测试组、ws 集成断言协议帧不触达 handler),
ruff/pyright 干净。文档 ARCHITECTURE/API/GUIDE/README/CHANGELOG 同步。
2026-09-20 21:57:57 +08:00
snowy-yang 71cbfdaf5d feat!: intents 只按大类订阅、群消息全量模式与事件流优化
破坏性变更:intents.toml 订阅粒度收敛到 Intents 大类(分组)——
配置从「[分组] 表内逐事件开关」改为「分组名 = true/false」。网关只接受
分组位掩码,组内事件本就无法单独订阅,此前的逐事件开关仅是「组内任一
为 true 即订阅整组」的装饰。旧格式不再兼容,与拼错的分组名、非布尔值
一样在启动时直接抛 ValueError,而非静默少订阅。

新增:
- GROUP_MESSAGE_CREATE 事件接收(群消息全量模式,与 GROUP_AT_MESSAGE_CREATE
  共用 GroupAtMessage);GroupAtMessage 补齐 message_type/message_scene/
  attachments/mentions/ark_data/msg_elements 字段

优化:
- 形参注入缓存化:合并缓存 handler 签名与类型标注解析(此前每条事件都重跑
  inspect.signature/get_type_hints),services 命中改为每条事件实时判定,
  保证「先注册 handler、后登记组件」的既有装配顺序不受影响
- EventQueue.put_event/put_reply 去掉多余的 return await
- model.NoneType 联合成员顺序调整(None 置于末尾)

文档同步 GUIDE/API/README/CHANGELOG 与示例;测试 76 全绿,ruff/pyright 干净。
2026-09-20 21:39:25 +08:00
snowy-yang 3237558128 feat!: api 拆包、心跳迁入传输层、限流重试与后台 handler 2026-09-20 21:26:55 +08:00
snowy-yang 097bc96d8b feat: 按钮快捷构造、event_id 语义修正与 TokenError 2026-09-16 21:42:33 +08:00
snowy-yang cff0c142c2 refactor!: 移除 dishka,改为内置裸标注参数注入
- handler 形参直接标注组件类型(api: BotApi)即注入,解析为 emitter 内同步查表(payload dataclass / Event / services 登记类型 / 回退原始 dict)
2026-09-16 19:18:06 +08:00
snowy-yang 953d44f62e feat: Markdown 与内嵌按钮一等支持
- post_group_message/post_c2c_message 新增 markdown/keyboard 参数,自动置 msg_type=2(与 content 互斥)
2026-09-16 19:17:05 +08:00
snowy-yang 0c364bf803 qqbotsdk: QQ 官方机器人 SDK(协议层/DI/业务 API/测试/文档) 2026-09-11 19:49:17 +08:00