1db287d8ccb723a2eae22ba3474a5fc96e5368d3
The c2c file send path was wrong on three independent axes — every
c2c file the bot tried to deliver was getting rejected by the QQ-NT
server. Aligned to `dev/Lagrange.Core` (V2 branch) which is the only
direct-protocol reference for c2c files; NapCat goes through QQ-NT
IPC and never builds this packet itself.
Three wire-shape fixes:
1. **Routing**: `routingHead.c2c { uin, uid }` → `routingHead.trans0x211
{ ccCmd: 4, uid }`. RoutingHead field 15 is the c2c-file scene's
slot. `MessagePacker.BuildPacketBase` makes this conditional on
`chain.HasTypeOf<FileEntity>()`: when a file is present, C2C goes
nil and Trans0X211 carries the routing.
2. **File payload location**: `messageBody.richText.notOnlineFile {...}`
→ `messageBody.msgContent = serialize(FileExtra{file: NotOnlineFile})`.
The server doesn't read c2c file metadata from `richText` at all —
`MessageBody.cs:12` even has the comment "Offline file is now put
here(?". Confirmed by `FileEntity.PackElement()` returning empty
and `PackMessageContent()` returning the FileExtra wrapper.
3. **contentHead.c2cCmd**: `11` → `0` (default/omitted). `11` was a
stale go-cqhttp value the QQ-NT server doesn't recognise on the
c2c-file dispatcher. Lagrange leaves it at the C# default (0).
Schema fixes (proton + legacy, both directions):
- `RoutingHead` gains `trans0x211?: pb<15, RoutingTrans0x211>`. The
new message has `toUin@1`, `ccCmd@2`, `uid@8`.
- `SendMessageBody` gains `msgContent?: pb<2, bytes>` (the receive-side
`MessageBody` already had it).
- `FileExtraInfo` deleted — was wrong on every tag (fileSize=1,
fileName=2, fileMd5=3, fileUuid=4, fileHash=5, none of which match
the wire). `FileExtra { file: pb<1, NotOnlineFile> }` now wraps the
same `NotOnlineFile` used on the receive path. This is why c2c file
PUSHES were also silently failing the four-field truthy check in
`extractMsgContent` — the schema couldn't decode anything.
- `NotOnlineFile` gains the three intake-validator fields the server
requires on send: `subcmd@9 = 1`, `dangerEvel@50 = 0`, `expireTime@55`
= now+7d.
Receive side (`rich-body-decoder.ts::extractMsgContent`): drop the
"all four fields must be truthy" guard (it was a workaround for the
broken schema) and accept any payload that decodes a fileUuid.
Tests:
- `bridge-private-routing.test.ts`: new regression that round-trips
`sendC2cFileMessage` through `protoDecode` and asserts trans0x211
routing, msgContent FileExtra wrapper, NotOnlineFile field tags,
c2cCmd=0. Catches each of the three wire-shape regressions
independently.
- `send-private-c2c-file.test.ts`: vi.fn arg signatures explicit for
CI typecheck.
647/647 tests pass.
❄️ SnowLuma
Next Remote Protocol Framework.
Releases · Issues · QQ 群 · Telegram
简介
SnowLuma 在 QQ 客户端与生态侧之间承担协议转换工作,向上以 OneBot v11 标准协议暴露能力。Bridge 层负责会话与事件枢纽,再通过 WebSocket / HTTP / WebUI 等多种适配器对外提供接入。
项目持续迭代中,稳定版本通过 Releases 发布。
特性
- OneBot v11 兼容 —— 涵盖文本、图片、视频、语音、合并转发、戳一戳、Markdown、JSON、XML 等常用消息段。
- 多账号并行 —— 同一进程可同时托管多个 QQ 账号,会话彼此独立。
- 多种适配器 —— WebSocket Server / WebSocket Client / HTTP Server / HTTP Post,HTTP 服务端同时支持
application/json与application/x-www-form-urlencoded。 - WebUI 管理面板 —— 浏览器登录、密码强度校验、登录限流、SSE 实时日志、配置热更新。
- TypeScript 全链路 —— Bridge / OneBot / SDK / UI 均使用 TypeScript,发布到 npm 的
@snowluma/sdk与@snowluma/ui可直接供下游应用消费。 - 数据持久化 —— 好友、群、群成员等关系数据落 SQLite,跨重启可用。
快速开始
下载预构建发布包:
# 从 Releases 下载 zip,解压到任意目录
./launcher.bat # Windows
或从源码开发:
git clone https://github.com/SnowLuma/SnowLuma.git
cd SnowLuma
pnpm install
pnpm build
pnpm start
WebUI 默认监听 5099 端口。首次启动会在控制台打印 initial credentials: user=admin password=<...>,登录后请立即修改。
若未完成首次改密就关闭进程,下次启动会自动重新生成一个新的随机密码。
工作区
本仓库使用 pnpm monorepo 管理,各包职责如下:
| 包 | 说明 |
|---|---|
@snowluma/core |
核心:协议层 / Bridge / OneBot / WebUI 全部在此。 |
@snowluma/sdk |
OneBot HTTP & WebSocket TypeScript SDK,发布到 npm。 |
@snowluma/ui |
Tailwind 4 共享组件库(shadcn 风格),发布到 npm。 |
@snowluma/websocket |
OneBot WebSocket 适配器底层。 |
@snowluma/proton |
编译期 protobuf 编/解码器生成器:TS interface 标注 pb<N, T>,Vite 插件在构建时把 protobuf_encode<T> / protobuf_decode<T> 替换为内联 codec,零运行时反射。 |
@snowluma/runtime |
运行时清单与发布包资源。 |
webui |
Web 管理面板前端。 |
架构
flowchart TD
A([QQ 客户端])
B["协议层<br/><sub>packet pipeline · cmd 分派</sub>"]
C["Bridge 层<br/><sub>会话调度 · 花名册缓存 · 消息发送</sub>"]
D["OneBot 层<br/><sub>Event Converter · Action Handler</sub>"]
E([WS / HTTP / WebUI])
A --> B --> C --> D --> E
文档
开发命令
pnpm dev # 启动 core dev server
pnpm dev:web # 启动 webui dev server
pnpm test # 运行 core 测试
pnpm typecheck # 全仓库 type check
pnpm build:all # 构建 core + sdk + webui
鸣谢
- LagrangeV2 —— Proto 定义参考。
- NapCatQQ —— Scanner 与 Packet 处理实现参考。
贡献者
感谢每一位为 SnowLuma 提交过代码的伙伴。
Star 趋势
社区
- QQ 群:SnowLuma-QQ
- Telegram:SnowLuma-TG
- 问题反馈:GitHub Issues
Languages
TypeScript
98.9%
CSS
0.5%
JavaScript
0.5%