@ywfe/openclaw-plugin-caryscloud-im 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/INTEGRATION.md ADDED
@@ -0,0 +1,544 @@
1
+ # OpenClaw WebSocket 频道插件接入指南
2
+
3
+ 本文档详细说明如何将 WebSocket 频道插件接入到 OpenClaw 系统中。
4
+
5
+ ## 目录
6
+
7
+ 1. [前置要求](#前置要求)
8
+ 2. [安装插件](#安装插件)
9
+ 3. [配置 OpenClaw](#配置-openclaw)
10
+ 4. [启动和验证](#启动和验证)
11
+ 5. [WebSocket 服务器要求](#websocket-服务器要求)
12
+ 6. [常见问题](#常见问题)
13
+
14
+ ---
15
+
16
+ ## 前置要求
17
+
18
+ ### 系统要求
19
+
20
+ - Node.js >= 18.0.0
21
+ - pnpm >= 8.0.0 (或 npm/yarn)
22
+ - OpenClaw 已安装并正常运行
23
+
24
+ ### WebSocket 服务器要求
25
+
26
+ - 支持 WebSocket 协议 (wss:// 或 ws://)
27
+ - 支持 JSON 格式消息
28
+
29
+ ---
30
+
31
+ ## 安装插件
32
+
33
+ ### 方式一:从源码构建
34
+
35
+ ```bash
36
+ # 1. 进入插件目录
37
+ cd /caryscloud-plugin
38
+
39
+ # 2. 安装依赖
40
+ pnpm install
41
+
42
+ # 3. 构建插件
43
+ pnpm build
44
+
45
+ # 4. 链接到 OpenClaw(如果需要)
46
+ # 方式 A: 使用 pnpm link
47
+ pnpm link --global
48
+ cd /path/to/openclaw
49
+ pnpm link --global @ywfe/openclaw-plugin-caryscloud-im
50
+
51
+ # 方式 B: 直接在 OpenClaw 的 package.json 中引用本地路径
52
+ # 在 OpenClaw 的 package.json 中添加:
53
+ # "dependencies": {
54
+ # "@ywfe/openclaw-plugin-caryscloud-im": "file:/openclaw/caryscloud-plugin"
55
+ # }
56
+ ```
57
+
58
+ ### 方式二:通过 npm/pnpm 安装(如果已发布)
59
+
60
+ ```bash
61
+ cd /path/to/openclaw
62
+ pnpm add @ywfe/openclaw-plugin-caryscloud-im
63
+ ```
64
+
65
+ ---
66
+
67
+ ## 配置 OpenClaw
68
+
69
+ ### 1. 找到 OpenClaw 配置文件
70
+
71
+ OpenClaw 的配置文件通常位于:
72
+ - `~/.openclaw/config.json`
73
+ - 或项目根目录的 `openclaw.config.json`
74
+
75
+ ### 2. 添加 WebSocket 频道配置
76
+
77
+ 在配置文件中添加 `channels.websocket` 配置:
78
+
79
+ ```json
80
+ {
81
+ "channels": {
82
+ "caryscloud-im": {
83
+ "accounts": {
84
+ "default": {
85
+ "targetUserId": "your-target-user-id",
86
+ "wsUrl": "wss://your-websocket-server.com/ws",
87
+ "uuid": "openclaw-instance-001",
88
+ "name": "我的 OpenClaw 助手",
89
+ "avatarUrl": "https://example.com/avatar.png",
90
+ "authToken": "your-auth-token-here",
91
+ "enabled": true
92
+ }
93
+ }
94
+ }
95
+ }
96
+ }
97
+ ```
98
+
99
+ ### 3. 配置参数说明
100
+
101
+ #### 必填参数
102
+
103
+ | 参数 | 类型 | 说明 | 示例 |
104
+ |------|------|------|------|
105
+ | `targetUserId` | string | 消息接收方的用户 ID | `"user123"` |
106
+ | `wsUrl` | string | WebSocket 服务器地址 | `"wss://api.example.com/ws"` |
107
+
108
+ #### 可选参数
109
+
110
+ | 参数 | 类型 | 默认值 | 说明 |
111
+ |------|------|--------|------|
112
+ | `uuid` | string | 自动生成 | 当前 OpenClaw 实例的唯一标识,留空则从 deviceId 自动生成 |
113
+ | `name` | string | `openclaw_${uuid}` | 显示名称 |
114
+ | `avatarUrl` | string | 默认头像 | 头像 URL |
115
+ | `authToken` | string | - | WebSocket 连接的认证令牌 |
116
+ | `enabled` | boolean | `true` | 是否启用此账号 |
117
+
118
+ ### 4. 多账号配置示例
119
+
120
+ ```json
121
+ {
122
+ "channels": {
123
+ "caryscloud-im": {
124
+ "accounts": {
125
+ "production": {
126
+ "targetUserId": "prod-user-001",
127
+ "wsUrl": "wss://prod.example.com/ws",
128
+ "authToken": "prod-token-xxx",
129
+ "enabled": true
130
+ },
131
+ "staging": {
132
+ "targetUserId": "staging-user-001",
133
+ "wsUrl": "wss://staging.example.com/ws",
134
+ "authToken": "staging-token-yyy",
135
+ "enabled": false
136
+ },
137
+ "development": {
138
+ "targetUserId": "dev-user-001",
139
+ "wsUrl": "ws://localhost:8080/ws",
140
+ "enabled": true
141
+ }
142
+ }
143
+ }
144
+ }
145
+ }
146
+ ```
147
+
148
+ ---
149
+
150
+ ## 启动和验证
151
+
152
+ ### 1. 启动 OpenClaw
153
+
154
+ ```bash
155
+ # 启动 OpenClaw
156
+ openclaw start
157
+
158
+ # 或者如果是开发模式
159
+ openclaw dev
160
+ ```
161
+
162
+ ### 2. 验证插件加载
163
+
164
+ 查看 OpenClaw 日志,应该看到类似输出:
165
+
166
+ ```
167
+ [WebSocket] Plugin register() called
168
+ [WebSocket] ✅ Channel registered with OpenClaw
169
+ [WebSocket] Plugin registration complete. Accounts will be initialized by OpenClaw lifecycle.
170
+ [WebSocket] onAccountStart called for account: default
171
+ [WebSocket] Config: uuid=openclaw-instance-001, wsUrl=wss://your-server.com/ws
172
+ [WebSocket] Initializing WebSocket client...
173
+ [WebSocket] Connecting to wss://your-server.com/ws...
174
+ [WebSocket] WebSocket connected
175
+ [WebSocket] Auth message sent
176
+ [WebSocket] Authentication successful
177
+ [WebSocket] Client stored for account default
178
+ [WebSocket] ✅ Account default started successfully
179
+ [WebSocket] Message handlers registered for account default
180
+ ```
181
+
182
+ ### 3. 测试消息发送
183
+
184
+ 通过 OpenClaw CLI 或 API 发送测试消息:
185
+
186
+ ```bash
187
+ # 使用 OpenClaw CLI 发送消息
188
+ openclaw send --channel websocket --account default --to user123 --text "Hello, WebSocket!"
189
+ ```
190
+
191
+ ### 4. 验证连接状态
192
+
193
+ ```bash
194
+ # 查看频道状态
195
+ openclaw status --channel websocket
196
+
197
+ # 应该显示:
198
+ # Channel: websocket
199
+ # Account: default
200
+ # Status: ✅ Connected
201
+ # UUID: openclaw-instance-001
202
+ # Target: user123
203
+ ```
204
+
205
+ ---
206
+
207
+ ## WebSocket 服务器要求
208
+
209
+ ### 消息协议
210
+
211
+ WebSocket 服务器必须支持以下 JSON 格式的消息协议:
212
+
213
+ #### 1. 客户端 → 服务器消息
214
+
215
+ **认证消息(如果配置了 authToken):**
216
+ ```json
217
+ {
218
+ "type": "auth",
219
+ "payload": {
220
+ "token": "your-auth-token",
221
+ "uuid": "openclaw-instance-001"
222
+ }
223
+ }
224
+ ```
225
+
226
+ **文本消息:**
227
+ ```json
228
+ {
229
+ "type": "text",
230
+ "from": "openclaw-instance-001",
231
+ "to": "user123",
232
+ "text": "你好,世界!",
233
+ "messageId": "msg_1234567890_abc123",
234
+ "timestamp": 1234567890000
235
+ }
236
+ ```
237
+
238
+ **图片消息:**
239
+ ```json
240
+ {
241
+ "type": "image",
242
+ "from": "openclaw-instance-001",
243
+ "to": "user123",
244
+ "payload": {
245
+ "base64": "data:image/png;base64,iVBORw0KGgoAAAANS...",
246
+ "filename": "screenshot.png",
247
+ "size": 12345
248
+ },
249
+ "messageId": "msg_1234567890_abc124",
250
+ "timestamp": 1234567890000
251
+ }
252
+ ```
253
+
254
+ **文件消息:**
255
+ ```json
256
+ {
257
+ "type": "file",
258
+ "from": "openclaw-instance-001",
259
+ "to": "user123",
260
+ "payload": {
261
+ "base64": "data:application/pdf;base64,JVBERi0xLjQK...",
262
+ "filename": "document.pdf",
263
+ "size": 54321
264
+ },
265
+ "messageId": "msg_1234567890_abc125",
266
+ "timestamp": 1234567890000
267
+ }
268
+ ```
269
+
270
+ #### 2. 服务器 → 客户端消息
271
+
272
+ **认证响应:**
273
+ ```json
274
+ {
275
+ "type": "auth_response",
276
+ "success": true
277
+ }
278
+ ```
279
+
280
+ **文本消息:**
281
+ ```json
282
+ {
283
+ "type": "text",
284
+ "from": "user123",
285
+ "to": "openclaw-instance-001",
286
+ "text": "收到你的消息!",
287
+ "messageId": "msg_server_001",
288
+ "timestamp": 1234567890000
289
+ }
290
+ ```
291
+
292
+ **图片/文件消息:**
293
+ ```json
294
+ {
295
+ "type": "image",
296
+ "from": "user123",
297
+ "to": "openclaw-instance-001",
298
+ "mediaUrl": "https://example.com/images/photo.jpg",
299
+ "messageId": "msg_server_002",
300
+ "timestamp": 1234567890000
301
+ }
302
+ ```
303
+
304
+ **冲突通知(UUID 重复):**
305
+ ```json
306
+ {
307
+ "type": "conflict",
308
+ "reason": "UUID openclaw-instance-001 已在其他设备上使用"
309
+ }
310
+ ```
311
+
312
+ **Pong 响应(心跳):**
313
+ ```json
314
+ {
315
+ "type": "pong",
316
+ "timestamp": 1234567890000
317
+ }
318
+ ```
319
+
320
+ ### 服务器实现要点
321
+
322
+ 1. **WebSocket 连接处理**
323
+ - 接受 wss:// 或 ws:// 连接
324
+ - 支持 WebSocket ping/pong 帧(用于心跳检测)
325
+
326
+ 2. **认证处理**
327
+ - 如果客户端发送 `auth` 消息,验证 token
328
+ - 返回 `auth_response` 消息表示认证结果
329
+
330
+ 3. **消息路由**
331
+ - 根据 `to` 字段将消息路由到目标用户
332
+ - 保存 `messageId` 用于消息去重和追踪
333
+
334
+ 4. **UUID 冲突检测**
335
+ - 检测同一 UUID 的多个连接
336
+ - 向新连接发送 `conflict` 消息
337
+ - 可选:断开旧连接或拒绝新连接
338
+
339
+ 5. **心跳处理**
340
+ - 响应 WebSocket ping 帧
341
+ - 或响应 JSON 格式的 ping 消息
342
+
343
+ ### 服务器示例(Node.js + ws)
344
+
345
+ ```javascript
346
+ const WebSocket = require('ws');
347
+ const wss = new WebSocket.Server({ port: 8080 });
348
+
349
+ const clients = new Map(); // uuid -> WebSocket
350
+
351
+ wss.on('connection', (ws) => {
352
+ let clientUuid = null;
353
+
354
+ ws.on('message', (data) => {
355
+ try {
356
+ const message = JSON.parse(data);
357
+
358
+ switch (message.type) {
359
+ case 'auth':
360
+ // 验证 token
361
+ if (validateToken(message.payload.token)) {
362
+ clientUuid = message.payload.uuid;
363
+
364
+ // 检查 UUID 冲突
365
+ if (clients.has(clientUuid)) {
366
+ ws.send(JSON.stringify({
367
+ type: 'conflict',
368
+ reason: `UUID ${clientUuid} 已在其他设备上使用`
369
+ }));
370
+ ws.close();
371
+ return;
372
+ }
373
+
374
+ clients.set(clientUuid, ws);
375
+ ws.send(JSON.stringify({
376
+ type: 'auth_response',
377
+ success: true
378
+ }));
379
+ } else {
380
+ ws.send(JSON.stringify({
381
+ type: 'auth_response',
382
+ success: false
383
+ }));
384
+ ws.close();
385
+ }
386
+ break;
387
+
388
+ case 'text':
389
+ case 'image':
390
+ case 'file':
391
+ // 路由消息到目标用户
392
+ const targetWs = clients.get(message.to);
393
+ if (targetWs && targetWs.readyState === WebSocket.OPEN) {
394
+ targetWs.send(JSON.stringify(message));
395
+ }
396
+ break;
397
+
398
+ case 'ping':
399
+ ws.send(JSON.stringify({
400
+ type: 'pong',
401
+ timestamp: Date.now()
402
+ }));
403
+ break;
404
+ }
405
+ } catch (error) {
406
+ console.error('消息处理错误:', error);
407
+ }
408
+ });
409
+
410
+ ws.on('close', () => {
411
+ if (clientUuid) {
412
+ clients.delete(clientUuid);
413
+ }
414
+ });
415
+
416
+ // 响应 WebSocket ping 帧
417
+ ws.on('ping', () => {
418
+ ws.pong();
419
+ });
420
+ });
421
+
422
+ function validateToken(token) {
423
+ // 实现你的 token 验证逻辑
424
+ return token === 'valid-token';
425
+ }
426
+ ```
427
+
428
+ ---
429
+
430
+ ## 常见问题
431
+
432
+ ### 1. 连接失败
433
+
434
+ **问题:** 插件无法连接到 WebSocket 服务器
435
+
436
+ **解决方案:**
437
+ - 检查 `wsUrl` 是否正确
438
+ - 确认服务器正在运行并监听正确的端口
439
+ - 检查防火墙设置
440
+ - 验证 SSL 证书(如果使用 wss://)
441
+ - 查看 OpenClaw 日志中的详细错误信息
442
+
443
+ ### 2. 认证失败
444
+
445
+ **问题:** 收到 "Authentication failed" 错误
446
+
447
+ **解决方案:**
448
+ - 验证 `authToken` 是否正确
449
+ - 检查服务器端的 token 验证逻辑
450
+ - 确认 token 未过期
451
+ - 查看服务器日志中的认证错误
452
+
453
+ ### 3. UUID 冲突
454
+
455
+ **问题:** 收到 "UUID conflict" 错误
456
+
457
+ **解决方案:**
458
+ - 确保每个 OpenClaw 实例使用唯一的 `uuid`
459
+ - 停止使用相同 UUID 的其他实例
460
+ - 或在配置中为每个实例设置不同的 `uuid`
461
+
462
+ ### 4. 消息未送达
463
+
464
+ **问题:** 发送的消息对方未收到
465
+
466
+ **解决方案:**
467
+ - 检查 WebSocket 连接状态(`openclaw status`)
468
+ - 验证 `targetUserId` 是否正确
469
+ - 确认目标用户已连接到服务器
470
+ - 检查服务器的消息路由逻辑
471
+ - 查看服务器日志中的消息处理记录
472
+
473
+ ### 5. 频繁断线重连
474
+
475
+ **问题:** WebSocket 连接频繁断开并重连
476
+
477
+ **解决方案:**
478
+ - 检查网络稳定性
479
+ - 增加心跳间隔(修改 `DEFAULT_HEARTBEAT_INTERVAL`)
480
+ - 检查服务器是否主动关闭连接
481
+ - 查看服务器负载情况
482
+ - 检查是否有防火墙或代理干扰
483
+
484
+ ### 6. 消息队列溢出
485
+
486
+ **问题:** 日志显示 "Message queue full, dropping oldest message"
487
+
488
+ **解决方案:**
489
+ - 检查 WebSocket 连接状态
490
+ - 减少消息发送频率
491
+ - 增加消息队列大小(修改 `DEFAULT_MESSAGE_QUEUE_MAX_SIZE`)
492
+ - 优化网络连接稳定性
493
+
494
+ ---
495
+
496
+ ## 高级配置
497
+
498
+ ### 自定义超时和重连参数
499
+
500
+ 如果需要自定义超时和重连参数,可以修改 `src/shared/constants.ts`:
501
+
502
+ ```typescript
503
+ export const DEFAULT_HEARTBEAT_INTERVAL = 30000; // 心跳间隔(毫秒)
504
+ export const DEFAULT_CONNECTION_TIMEOUT = 10000; // 连接超时(毫秒)
505
+ export const DEFAULT_RECONNECT_MAX_ATTEMPTS = 5; // 最大重连次数
506
+ export const DEFAULT_RECONNECT_BASE_DELAY = 1000; // 重连基础延迟(毫秒)
507
+ export const DEFAULT_RECONNECT_MAX_DELAY = 30000; // 重连最大延迟(毫秒)
508
+ export const DEFAULT_MESSAGE_QUEUE_MAX_SIZE = 100; // 消息队列最大大小
509
+ export const DEFAULT_PONG_TIMEOUT = 15000; // Pong 超时(毫秒)
510
+ ```
511
+
512
+ 修改后需要重新构建:
513
+
514
+ ```bash
515
+ pnpm build
516
+ ```
517
+
518
+ ### 日志级别调整
519
+
520
+ 在 OpenClaw 配置中调整日志级别:
521
+
522
+ ```json
523
+ {
524
+ "logging": {
525
+ "level": "debug" // 可选: error, warn, info, debug
526
+ }
527
+ }
528
+ ```
529
+
530
+ ---
531
+
532
+ ## 技术支持
533
+
534
+ 如有问题,请:
535
+ 1. 查看 [README.md](./README.md) 了解基本使用
536
+ 2. 检查 OpenClaw 日志文件
537
+ 3. 查看 WebSocket 服务器日志
538
+ 4. 提交 Issue 到项目仓库
539
+
540
+ ---
541
+
542
+ ## 许可证
543
+
544
+ MIT