|
| 1 | +# 消息 API 破坏性变更通知(v0.6.5) |
| 2 | + |
| 3 | +> **回复方**: ClawNet 团队 |
| 4 | +> **接收方**: TelAgent 项目组 |
| 5 | +> **日期**: 2026-03-10 |
| 6 | +> **涉及包**: `@claw-network/core@0.6.5`, `@claw-network/protocol@0.6.5`, `@claw-network/node@0.6.5`, `@claw-network/sdk@0.6.5` |
| 7 | +> **npm 状态**: ✅ 已发布 |
| 8 | +> **关联文档**: `issues/clawnet-p2p-binary-transport-reply.md` |
| 9 | +
|
| 10 | +--- |
| 11 | + |
| 12 | +## 概述 |
| 13 | + |
| 14 | +`v0.6.5` 对消息系统进行了 **破坏性重构**,核心变更: |
| 15 | + |
| 16 | +1. **全面移除 base64** — 整个消息链路不再使用 base64 编码 |
| 17 | +2. **文本与二进制接口分离** — REST API 和 SDK 拆分为独立的文本/二进制接口 |
| 18 | +3. **存储层 TEXT → BLOB** — SQLite payload 列从 TEXT 改为 BLOB,旧数据库不兼容 |
| 19 | +4. **移除 `payloadEncoding` 字段** — 不再存在编码声明,二进制就是二进制 |
| 20 | + |
| 21 | +> ⚠️ **这是破坏性变更**。升级后旧消息数据库不兼容,需要重新初始化。所有向后兼容和迁移代码已移除。 |
| 22 | +
|
| 23 | +--- |
| 24 | + |
| 25 | +## 一、REST API 变更 |
| 26 | + |
| 27 | +### 已移除 |
| 28 | + |
| 29 | +| 变更 | 说明 | |
| 30 | +|------|------| |
| 31 | +| `payloadEncoding` 字段 | 发送和收件箱响应中不再存在此字段 | |
| 32 | +| `POST /send` 中的 base64 payload | 不再接受 base64 编码的 payload | |
| 33 | + |
| 34 | +### 发送消息(新接口) |
| 35 | + |
| 36 | +**文本消息** — `POST /api/v1/messaging/send`(JSON body,仅支持字符串 payload) |
| 37 | + |
| 38 | +```bash |
| 39 | +curl -X POST http://localhost:9528/api/v1/messaging/send \ |
| 40 | + -H "Content-Type: application/json" \ |
| 41 | + -H "X-Api-Key: YOUR_KEY" \ |
| 42 | + -d '{ |
| 43 | + "targetDid": "did:claw:zBob...", |
| 44 | + "topic": "my-app/text", |
| 45 | + "payload": "Hello, World!" |
| 46 | + }' |
| 47 | +``` |
| 48 | + |
| 49 | +`payload` 字段类型为 `string`,不再接受 base64 编码的二进制。 |
| 50 | + |
| 51 | +**二进制消息** — `POST /api/v1/messaging/send-binary`(🆕 新增端点) |
| 52 | + |
| 53 | +```bash |
| 54 | +curl -X POST http://localhost:9528/api/v1/messaging/send-binary \ |
| 55 | + -H "Content-Type: application/octet-stream" \ |
| 56 | + -H "X-Api-Key: YOUR_KEY" \ |
| 57 | + -H "X-Target-Did: did:claw:zBob..." \ |
| 58 | + -H "X-Topic: my-app/binary-data" \ |
| 59 | + -H "X-Compress: true" \ |
| 60 | + --data-binary @my-file.bin |
| 61 | +``` |
| 62 | + |
| 63 | +元数据通过 HTTP headers 传递,body 是原始二进制字节: |
| 64 | + |
| 65 | +| Header | 必填 | 说明 | |
| 66 | +|--------|------|------| |
| 67 | +| `X-Target-Did` | ✅ | 目标 DID | |
| 68 | +| `X-Topic` | ✅ | 消息 topic | |
| 69 | +| `X-Compress` | 可选 | 是否 gzip 压缩(`true`/`false`) | |
| 70 | +| `X-Encrypt` | 可选 | 是否 E2E 加密(`true`/`false`) | |
| 71 | +| `X-Priority` | 可选 | 优先级(整数) | |
| 72 | +| `X-Ttl` | 可选 | 过期秒数 | |
| 73 | + |
| 74 | +**批量发送** — 两个端点: |
| 75 | + |
| 76 | +- `POST /api/v1/messaging/send/batch` — 文本批量发送(JSON body) |
| 77 | +- `POST /api/v1/messaging/send-binary/batch` — 二进制批量发送(`X-Target-Dids` header,逗号分隔) |
| 78 | + |
| 79 | +### 收件箱变更 |
| 80 | + |
| 81 | +**`GET /api/v1/messaging/inbox` 响应格式变更**: |
| 82 | + |
| 83 | +```json |
| 84 | +{ |
| 85 | + "messages": [{ |
| 86 | + "messageId": "msg_abc123", |
| 87 | + "sourceDid": "did:claw:zAlice...", |
| 88 | + "topic": "my-app/text", |
| 89 | + "payload": "Hello, World!", |
| 90 | + "payloadSize": 13, |
| 91 | + "compressed": false, |
| 92 | + "encrypted": false, |
| 93 | + "receivedAtMs": 1710000000000, |
| 94 | + "priority": 1, |
| 95 | + "seq": 42 |
| 96 | + }] |
| 97 | +} |
| 98 | +``` |
| 99 | + |
| 100 | +| 字段变更 | 说明 | |
| 101 | +|----------|------| |
| 102 | +| `payloadEncoding` | ❌ 已移除 | |
| 103 | +| `payload` | 仅在 `compressed: false` 且 `encrypted: false` 时存在(UTF-8 文本) | |
| 104 | +| `payloadSize` | 🆕 始终存在,表示原始 payload 字节数 | |
| 105 | +| `compressed` | 🆕 是否已 gzip 压缩 | |
| 106 | +| `encrypted` | 🆕 是否已 E2E 加密 | |
| 107 | + |
| 108 | +**重要**:已压缩或已加密的消息,`payload` 字段 **不存在**。需通过独立端点下载原始字节。 |
| 109 | + |
| 110 | +**`GET /api/v1/messaging/inbox/:messageId/payload`**(🆕 新增端点) |
| 111 | + |
| 112 | +下载单条消息的原始二进制 payload: |
| 113 | + |
| 114 | +```bash |
| 115 | +curl -s http://localhost:9528/api/v1/messaging/inbox/msg_abc123/payload \ |
| 116 | + -H "X-Api-Key: YOUR_KEY" \ |
| 117 | + -o output.bin |
| 118 | +``` |
| 119 | + |
| 120 | +响应: |
| 121 | +- `Content-Type: application/octet-stream` |
| 122 | +- `Content-Length` — 字节数 |
| 123 | +- `X-Compressed: 1` — 如果已压缩 |
| 124 | +- `X-Encrypted: 1` — 如果已加密 |
| 125 | + |
| 126 | +--- |
| 127 | + |
| 128 | +## 二、SDK 变更 |
| 129 | + |
| 130 | +### 已移除 |
| 131 | + |
| 132 | +- `send()` 不再接受 `payloadEncoding` 参数 |
| 133 | +- `send()` 的 `payload` 不再接受 `Uint8Array`,仅接受 `string` |
| 134 | + |
| 135 | +### 新增方法 |
| 136 | + |
| 137 | +```typescript |
| 138 | +import { ClawNetClient } from '@claw-network/sdk'; |
| 139 | + |
| 140 | +const client = new ClawNetClient({ |
| 141 | + baseUrl: 'http://localhost:9528', |
| 142 | + apiKey: 'YOUR_KEY', |
| 143 | +}); |
| 144 | + |
| 145 | +// ✅ 发送文本(与旧版 send 类似,但 payload 仅 string) |
| 146 | +await client.messaging.send({ |
| 147 | + targetDid: 'did:claw:zBob...', |
| 148 | + topic: 'my-app/text', |
| 149 | + payload: 'Hello, World!', |
| 150 | +}); |
| 151 | + |
| 152 | +// ✅ 发送二进制(🆕) |
| 153 | +await client.messaging.sendBinary({ |
| 154 | + targetDid: 'did:claw:zBob...', |
| 155 | + topic: 'my-app/binary-data', |
| 156 | + payload: new Uint8Array([0xDE, 0xAD, 0xBE, 0xEF]), |
| 157 | + compress: true, |
| 158 | +}); |
| 159 | + |
| 160 | +// ✅ 批量发送文本 |
| 161 | +await client.messaging.sendBatch({ |
| 162 | + targetDids: ['did:claw:zBob...', 'did:claw:zCharlie...'], |
| 163 | + topic: 'broadcast', |
| 164 | + payload: 'Hello everyone!', |
| 165 | +}); |
| 166 | + |
| 167 | +// ✅ 批量发送二进制(🆕) |
| 168 | +await client.messaging.sendBinaryBatch({ |
| 169 | + targetDids: ['did:claw:zBob...', 'did:claw:zCharlie...'], |
| 170 | + topic: 'binary-broadcast', |
| 171 | + payload: new Uint8Array([0x01, 0x02, 0x03]), |
| 172 | +}); |
| 173 | + |
| 174 | +// ✅ 下载原始 payload(🆕,返回 ArrayBuffer) |
| 175 | +const rawBytes = await client.messaging.downloadPayload('msg_abc123'); |
| 176 | +``` |
| 177 | + |
| 178 | +### InboxMessage 类型变更 |
| 179 | + |
| 180 | +```typescript |
| 181 | +// v0.6.4 及之前 |
| 182 | +interface InboxMessage { |
| 183 | + messageId: string; |
| 184 | + payload: string; // 可能是 base64 |
| 185 | + payloadEncoding?: string; // "base64" | "utf-8" |
| 186 | + // ... |
| 187 | +} |
| 188 | + |
| 189 | +// v0.6.5(当前) |
| 190 | +interface InboxMessage { |
| 191 | + messageId: string; |
| 192 | + payload?: string; // 仅纯文本消息存在 |
| 193 | + payloadSize: number; // 始终存在 |
| 194 | + compressed: boolean; // 是否已压缩 |
| 195 | + encrypted: boolean; // 是否已加密 |
| 196 | + // ... |
| 197 | +} |
| 198 | +``` |
| 199 | + |
| 200 | +--- |
| 201 | + |
| 202 | +## 三、存储层变更 |
| 203 | + |
| 204 | +| 变更项 | 旧版 | 新版 | |
| 205 | +|--------|------|------| |
| 206 | +| payload 列类型 | `TEXT`(base64 或 UTF-8) | `BLOB`(原始字节) | |
| 207 | +| 编码标记 | `payloadEncoding` 列 | `compressed` + `encrypted` 标志列 | |
| 208 | +| 向后兼容 | 自动迁移旧格式 | ❌ 无迁移,旧数据库不兼容 | |
| 209 | + |
| 210 | +> ⚠️ **升级后需删除旧消息数据库并重新初始化**。所有迁移代码已移除。 |
| 211 | +
|
| 212 | +--- |
| 213 | + |
| 214 | +## 四、迁移指南 |
| 215 | + |
| 216 | +### 1. 升级依赖 |
| 217 | + |
| 218 | +```bash |
| 219 | +pnpm add @claw-network/sdk@0.6.5 |
| 220 | +# 或 |
| 221 | +npm install @claw-network/sdk@0.6.5 |
| 222 | +``` |
| 223 | + |
| 224 | +如果直接运行节点: |
| 225 | + |
| 226 | +```bash |
| 227 | +pnpm add @claw-network/node@0.6.5 |
| 228 | +``` |
| 229 | + |
| 230 | +### 2. 代码迁移 |
| 231 | + |
| 232 | +**发送文本消息** — 无需改动(如果之前用的就是纯文本 payload): |
| 233 | + |
| 234 | +```typescript |
| 235 | +// 之前和现在都一样 |
| 236 | +await client.messaging.send({ |
| 237 | + targetDid: 'did:claw:zBob...', |
| 238 | + topic: 'chat', |
| 239 | + payload: '你好', |
| 240 | +}); |
| 241 | +``` |
| 242 | + |
| 243 | +**发送二进制数据** — 从 `send()` + base64 迁移到 `sendBinary()`: |
| 244 | + |
| 245 | +```typescript |
| 246 | +// ❌ 旧版(base64) |
| 247 | +await client.messaging.send({ |
| 248 | + targetDid: 'did:claw:zBob...', |
| 249 | + payload: Buffer.from(binaryData).toString('base64'), |
| 250 | + payloadEncoding: 'base64', |
| 251 | +}); |
| 252 | + |
| 253 | +// ✅ 新版(原始二进制) |
| 254 | +await client.messaging.sendBinary({ |
| 255 | + targetDid: 'did:claw:zBob...', |
| 256 | + topic: 'binary-data', |
| 257 | + payload: binaryData, // Uint8Array |
| 258 | +}); |
| 259 | +``` |
| 260 | + |
| 261 | +**读取收件箱** — 处理新字段: |
| 262 | + |
| 263 | +```typescript |
| 264 | +const { messages } = await client.messaging.inbox({ topic: 'my-app/*' }); |
| 265 | + |
| 266 | +for (const msg of messages) { |
| 267 | + if (msg.payload !== undefined) { |
| 268 | + // 纯文本消息,直接使用 |
| 269 | + console.log('Text:', msg.payload); |
| 270 | + } else { |
| 271 | + // 二进制/压缩/加密消息,需下载原始 payload |
| 272 | + const raw = await client.messaging.downloadPayload(msg.messageId); |
| 273 | + console.log('Binary payload size:', raw.byteLength); |
| 274 | + } |
| 275 | +} |
| 276 | +``` |
| 277 | + |
| 278 | +### 3. REST API 直接调用 |
| 279 | + |
| 280 | +如果 TelAgent 直接调用 REST API(非 SDK): |
| 281 | + |
| 282 | +| 旧调用 | 新调用 | |
| 283 | +|--------|--------| |
| 284 | +| `POST /send` + base64 payload + `payloadEncoding` | `POST /send-binary` + octet-stream body + metadata headers | |
| 285 | +| 收件箱中读取 base64 再解码 | `GET /inbox/:messageId/payload` 直接下载原始字节 | |
| 286 | +| 通过 `payloadEncoding` 判断类型 | 通过 `compressed`/`encrypted` 字段 + `payload` 是否存在判断 | |
| 287 | + |
| 288 | +### 4. 数据库重建 |
| 289 | + |
| 290 | +升级节点后,删除旧消息数据库: |
| 291 | + |
| 292 | +```bash |
| 293 | +# 停止节点 |
| 294 | +systemctl stop clawnetd |
| 295 | + |
| 296 | +# 备份旧数据(如需要) |
| 297 | +cp ~/.clawnet/data/messages.db ~/.clawnet/data/messages.db.bak |
| 298 | + |
| 299 | +# 删除旧数据库(节点重启时自动重建) |
| 300 | +rm ~/.clawnet/data/messages.db |
| 301 | + |
| 302 | +# 重启节点 |
| 303 | +systemctl start clawnetd |
| 304 | +``` |
| 305 | + |
| 306 | +--- |
| 307 | + |
| 308 | +## 五、WebSocket 推送变更 |
| 309 | + |
| 310 | +WebSocket 收件箱推送(`ws://localhost:9528/api/v1/messaging/subscribe`)同步变更: |
| 311 | + |
| 312 | +- JSON 帧中 `payload` 字段仅在 `compressed: false` 且 `encrypted: false` 时包含文本 |
| 313 | +- 不再包含 `payloadEncoding` 字段 |
| 314 | +- 新增 `payloadSize`、`compressed`、`encrypted` 字段 |
| 315 | +- 二进制/压缩/加密消息需通过 REST API 的 `GET /inbox/:messageId/payload` 下载原始字节 |
| 316 | + |
| 317 | +--- |
| 318 | + |
| 319 | +## 六、变更影响范围汇总 |
| 320 | + |
| 321 | +| 模块 | 影响 | 迁移复杂度 | |
| 322 | +|------|------|:---:| |
| 323 | +| `send()` 纯文本 | 无影响(接口不变) | 无 | |
| 324 | +| `send()` 发送二进制 | 改用 `sendBinary()` | 低 | |
| 325 | +| 收件箱读取 | 新增字段判断 + `downloadPayload()` | 中 | |
| 326 | +| WebSocket 推送 | 新字段适配 | 低 | |
| 327 | +| REST API 直接调用 | 新端点 + header 传元数据 | 中 | |
| 328 | +| 数据库 | 需重建 | 一次性操作 | |
| 329 | + |
| 330 | +--- |
| 331 | + |
| 332 | +## 七、后续沟通 |
| 333 | + |
| 334 | +如有升级或迁移问题,请随时联系我们。可以安排联调时间或提供更详细的代码示例。 |
0 commit comments