snowy-yang
|
feb39b11d5
|
refactor: 删去 intents 组内事件开关的专属校验(dict 本就被布尔校验拦下)
|
2026-09-24 22:40:29 +08:00 |
|
snowy-yang
|
e66148a75c
|
fix: 文档站子页面左侧目录不加载
docsify 进子目录路由会先请求 <目录>/_sidebar.md,失败(404)才回退根
目录;Cloudflare Pages 无 404.html 时对缺失路径 SPA 回退返回 index.html
且状态 200,docsify 把 HTML 当侧栏 Markdown 解析,左侧目录卡在加载中。
alias 将 docs/、examples/ 的 _sidebar.md 请求映射回根目录 _sidebar.md。
|
2026-09-24 21:51:40 +08:00 |
|
snowy-yang
|
badf5b3571
|
docs: README 瘦身——顶部加在线文档链接,删解释性内容与过时部署/CI 描述
|
2026-09-24 21:51:39 +08:00 |
|
snowy-yang
|
7663ca610d
|
fix: 移除误入的 dist 目录(早期组装演练残留,撤销 gitignore 后被 add -A 收走)
|
2026-09-24 21:20:20 +08:00 |
|
snowy-yang
|
7603db7fd9
|
feat!: 文档部署改为 docs 分支自动同步,移除 Gitea 工作流与 wrangler 脚本
Gitea 已配置为 GitHub 的镜像,主仓库落在 GitHub:
- 删除 .gitea/(runner 已弃用,六轮实跑不稳定)与
scripts/deploy_docs.sh(wrangler Direct Upload 路径随之退役,
CLOUDFLARE_* secrets 不再被 CI 需要)
- deploy-docs.yml 重写:main 的文档文件变更时自动把纯文档组装进
docs 孤儿分支并强推——Cloudflare Pages 直连 GitHub、生产分支选
docs、构建命令留空、输出目录 / 即完成零构建接入
- index.html 仓库链接与 README/GUIDE 安装命令补 GitHub 地址;
CHANGELOG 合并原先两条 CI/部署条目
|
2026-09-24 21:19:15 +08:00 |
|
snowy-yang
|
6897205f6b
|
feat: GitHub Actions——检测与文档部署落地 GitHub 主仓库
Gitea runner 六轮实跑无法稳定(checkout 间歇失败、镜像工具链不明、
secrets 未生效),转 GitHub 为主仓库:.github/workflows 与 .gitea/
并存,检测流水在 GitHub 上补齐 pytest。部署复用 scripts/deploy_docs.sh
(wrangler Direct Upload,secrets 在 GitHub 仓库配置)。
|
2026-09-24 20:56:38 +08:00 |
|
snowy-yang
|
a09d1788cd
|
fix: CI 锁定 python:3.13-slim 容器、走 archive 接口拉源码,每步结果上报 status
五轮实跑证据链:工作流多次 7~26s 即死而 probe(纯 curl)每次成功;
换成 gitea 本地 clone 依旧 8s 即死——默认镜像工具链不明是主因,git/
github 只是其中一环。收缩依赖面:container 固定 python:3.13-slim
(保证 python3.13+pip,免去 uv 下载 CPython);源码经 Gitea archive
接口拉 tarball(curl 已被 probe 证明可用);pyright 的 node 缺失时
apt 兜底。日志匿名不可读,改为每个关键步骤把成败写进 commit status
(远程可读),失败点从此可直接定位。
部署工作流同步换 archive 拉源码;deploy/secrets 探测两轮均报
MISSING,待仓库侧补配 secrets。
|
2026-09-24 20:48:16 +08:00 |
|
snowy-yang
|
b3edd79674
|
probe: runner 环境盘点(python3/pip/uv/git/npx 在场 + clone/装 uv 实测)
|
2026-09-24 20:42:58 +08:00 |
|
snowy-yang
|
98ed680c73
|
fix: 弃用 actions/checkout 改从 Gitea 本体克隆,绕开 github 间歇性不通
deploy/secrets 探测同时证实两个 secrets 均未生效(MISSING),部署
工作流此前死于 wrangler 无凭据。checkout 在四轮检测里三度嫌疑:用
它的任务多次 8~26s 即死,而没有 checkout 步骤的 probe 每次都成功,
github 探测时通时不通——典型间歇性故障。git clone 自家仓库彻底
绕开;CPython 下载仍走 npmmirror 镜像防 github 抖动。
|
2026-09-24 20:38:20 +08:00 |
|
snowy-yang
|
94a37011f0
|
fix: CI 回归直连 pypi(探测证实 runner 在海外、github/pypi/npm 全通),部署加 secrets 在场探测
probe.yml 结果:github/uv-release/pypi/npm/npmmirror 全部 200、CF API
可达(404 为根路径正常返回),仅 tuna 403——tuna 只服务大陆 IP,说明
runner 在海外,上一轮的镜像化是误诊且 pip 走 tuna 被 403 直接打断。
ci.yml 回归最简形态:pip install uv + uv sync,零镜像零 github 依赖。
部署工作流两轮均死于下载完 wrangler 之后、网络与 wrangler 均无嫌疑,
指向 secrets 配置问题;加一步把 CLOUDFLARE_API_TOKEN/ACCOUNT_ID 的
set/MISSING 写进 commit status(不泄露值),下次运行即可确诊。
|
2026-09-24 20:34:07 +08:00 |
|
snowy-yang
|
2916fc5902
|
fix: CI 摆脱 github 依赖(uv 走 pip+tuna、CPython 走 npmmirror),新增网络探测
第二轮实跑:检测工作流 12s 即败于 setup-uv(它从 github.com 拉 uv
二进制),部署工作流却能存活 1 分钟以上——同用 checkout 而死法不
同,判断 checkout 可用、github 拉取是检测链路的堵点。为此:
- ci.yml 弃用 setup-uv:pip(tuna 索引)装 uv;uv sync 的 CPython
下载指向 npmmirror 的 python-build-standalone 镜像,包索引走 tuna;
- 新增 probe.yml:把 runner 对 github/pypi/tuna/npm/npmmirror/CF API
的连通性写进 commit status(匿名可读),补齐无法读日志时的观测。
|
2026-09-24 20:30:05 +08:00 |
|
snowy-yang
|
32bd7c13b5
|
fix: CI 去掉 setup-uv 的 enable-cache,部署工作流更名
首次 CI 实跑两条工作流均失败且匿名读不到日志:检测工作流 26s 即败、
落在早期步骤,优先怀疑 enable-cache 触发的 Actions 缓存服务问题
(Gitea 对该 API 的支持不完善,post 步骤常因此失败)。先摘除该选项
再观察;部署工作流顺带改显示名并借文件变更重新触发。
|
2026-09-24 20:25:50 +08:00 |
|
snowy-yang
|
f45299f92c
|
docs: README/CHANGELOG 同步——方式三改写、CI 与文档站部署说明
README 方式三示例从 event.user_id/group_id/content/message_id 改为
typed payload + 组件注入组合;开发节补 CI 与 Cloudflare Pages 部署
说明;CHANGELOG Unreleased 记录 Event 兼容属性移除(破坏性)、
Gitea Actions CI 与文档站部署三项。
|
2026-09-24 20:18:46 +08:00 |
|
snowy-yang
|
35e501aabb
|
feat: Gitea Actions——ruff/pyright 检测与 Cloudflare Pages 文档自动部署
- .gitea/workflows/ci.yml:push(main)/PR/手动触发,setup-uv 装依赖
后运行与本地一致的 uv run ruff check src tests examples + uv run
pyright;故意未加 ruff format --check(存量 5 文件格式漂移会打红)
- .gitea/workflows/deploy-docs.yml:main 的文档文件变更时自动部署,
经 CLOUDFLARE_API_TOKEN/CLOUDFLARE_ACCOUNT_ID secrets 鉴权
- scripts/deploy_docs.sh:组装纯文档 dist/(不含源码,排除
__pycache__)后 wrangler Direct Upload 上传——CF Pages 的 Git 直连
只支持 GitHub/GitLab,Gitea 仓库只能走 Direct Upload;新版
wrangler 的 pages deploy 不再自动建项目,脚本先幂等 create
站点 https://qqbotsdk-docs.pages.dev 已上线。.wrangler/ 缓存与
dist/ 产物入 .gitignore。
|
2026-09-24 20:18:39 +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
|
32d9438d31
|
refactor: 拆分 receive_helper——心跳联动收进 _Heartbeat,等待与单帧路由各自成方法(圈复杂度 16→7)
|
2026-09-23 21:09:22 +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
|
1a7111973b
|
docs: 修正 README 架构图与 API 模块表(协议分流后残留)
|
2026-09-20 22:16:05 +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
|
750ed81d96
|
docs: 基于 docsify 搭建文档站点
|
2026-09-16 21:42:43 +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
|
7a1b8ac691
|
docs: 补全使用指南、API 参考、可运行示例与更新日志
|
2026-09-14 21:05:50 +08:00 |
|
snowy-yang
|
2ee0184fc1
|
chore: 移除 botpy 参考文件的 gitignore 规则
|
2026-09-11 20:35:19 +08:00 |
|
snowy-yang
|
0c364bf803
|
qqbotsdk: QQ 官方机器人 SDK(协议层/DI/业务 API/测试/文档)
|
2026-09-11 19:49:17 +08:00 |
|