adp-openclaw 0.0.2
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/DESIGN.md +733 -0
- package/README.md +70 -0
- package/USAGE.md +910 -0
- package/WEBSOCKET_PROTOCOL.md +506 -0
- package/index.ts +17 -0
- package/openclaw.plugin.json +22 -0
- package/package.json +26 -0
- package/server/.claude/settings.local.json +16 -0
- package/server/go.mod +5 -0
- package/server/main.go +786 -0
- package/src/channel.ts +245 -0
- package/src/config-schema.ts +8 -0
- package/src/monitor.ts +325 -0
- package/src/runtime.ts +15 -0
package/DESIGN.md
ADDED
|
@@ -0,0 +1,733 @@
|
|
|
1
|
+
# Simple Go Channel Plugin - 设计文档
|
|
2
|
+
|
|
3
|
+
## 1. 系统架构
|
|
4
|
+
|
|
5
|
+
```mermaid
|
|
6
|
+
graph TB
|
|
7
|
+
subgraph "OpenClaw Gateway"
|
|
8
|
+
PR[Plugin Registry]
|
|
9
|
+
TG[Telegram Plugin]
|
|
10
|
+
MX[Matrix Plugin]
|
|
11
|
+
SG[Simple Go Plugin]
|
|
12
|
+
RT[OpenClaw Runtime]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
subgraph "Go HTTP Server :9876"
|
|
16
|
+
AUTH[Auth Middleware]
|
|
17
|
+
POLL["/poll"]
|
|
18
|
+
SEND["/send"]
|
|
19
|
+
INB["/inbound"]
|
|
20
|
+
CONV[Conversations]
|
|
21
|
+
CLIENTS[Clients Registry]
|
|
22
|
+
INQ[Inbound Queues]
|
|
23
|
+
OUTQ[Outbound Queue]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
subgraph "External"
|
|
27
|
+
USER1[User 1]
|
|
28
|
+
USER2[User 2]
|
|
29
|
+
OC1[OpenClaw Client 1]
|
|
30
|
+
OC2[OpenClaw Client 2]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
PR --> TG
|
|
34
|
+
PR --> MX
|
|
35
|
+
PR --> SG
|
|
36
|
+
SG --> RT
|
|
37
|
+
|
|
38
|
+
OC1 -->|Bearer Token| AUTH
|
|
39
|
+
OC2 -->|Bearer Token| AUTH
|
|
40
|
+
AUTH --> POLL
|
|
41
|
+
AUTH --> SEND
|
|
42
|
+
|
|
43
|
+
USER1 --> INB
|
|
44
|
+
USER2 --> INB
|
|
45
|
+
INB --> CONV
|
|
46
|
+
CONV --> INQ
|
|
47
|
+
|
|
48
|
+
POLL --> INQ
|
|
49
|
+
SEND --> OUTQ
|
|
50
|
+
SEND --> CONV
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 2. 数据结构
|
|
54
|
+
|
|
55
|
+
### 2.1 Go 服务端结构体
|
|
56
|
+
|
|
57
|
+
```mermaid
|
|
58
|
+
classDiagram
|
|
59
|
+
class Message {
|
|
60
|
+
+string ID
|
|
61
|
+
+string ConversationID
|
|
62
|
+
+string ClientID
|
|
63
|
+
+string From
|
|
64
|
+
+string To
|
|
65
|
+
+string Text
|
|
66
|
+
+int64 Timestamp
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
class Conversation {
|
|
70
|
+
+string ID
|
|
71
|
+
+string UserID
|
|
72
|
+
+string ClientID
|
|
73
|
+
+[]Message Messages
|
|
74
|
+
+int64 CreatedAt
|
|
75
|
+
+int64 UpdatedAt
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
class Client {
|
|
79
|
+
+string ID
|
|
80
|
+
+string Token
|
|
81
|
+
+string Name
|
|
82
|
+
+int64 LastSeenAt
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
class Server {
|
|
86
|
+
+map~string,Client~ clients
|
|
87
|
+
+map~string,string~ tokens
|
|
88
|
+
+map~string,Conversation~ conversations
|
|
89
|
+
+map~string,[]Message~ inbound
|
|
90
|
+
+[]Message outbound
|
|
91
|
+
+string adminToken
|
|
92
|
+
+authMiddleware()
|
|
93
|
+
+adminAuth()
|
|
94
|
+
+handlePoll()
|
|
95
|
+
+handleSend()
|
|
96
|
+
+handleInbound()
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
Server "1" *-- "*" Client : manages
|
|
100
|
+
Server "1" *-- "*" Conversation : manages
|
|
101
|
+
Conversation "1" *-- "*" Message : contains
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 2.2 TypeScript 插件结构体
|
|
105
|
+
|
|
106
|
+
```mermaid
|
|
107
|
+
classDiagram
|
|
108
|
+
class SimpleGoConfig {
|
|
109
|
+
+channels.simplego.enabled: boolean
|
|
110
|
+
+channels.simplego.serverUrl: string
|
|
111
|
+
+channels.simplego.apiToken: string
|
|
112
|
+
+channels.simplego.pollIntervalMs: number
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
class ResolvedSimpleGoAccount {
|
|
116
|
+
+string accountId
|
|
117
|
+
+string name
|
|
118
|
+
+boolean enabled
|
|
119
|
+
+boolean configured
|
|
120
|
+
+string serverUrl
|
|
121
|
+
+string apiToken
|
|
122
|
+
+number pollIntervalMs
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
class MonitorParams {
|
|
126
|
+
+string serverUrl
|
|
127
|
+
+string apiToken
|
|
128
|
+
+number pollIntervalMs
|
|
129
|
+
+PluginRuntime runtime
|
|
130
|
+
+AbortSignal abortSignal
|
|
131
|
+
+PluginLogger log
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
class InboundMessage {
|
|
135
|
+
+string id
|
|
136
|
+
+string conversationId
|
|
137
|
+
+string from
|
|
138
|
+
+string text
|
|
139
|
+
+number timestamp
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
SimpleGoConfig --> ResolvedSimpleGoAccount : resolves to
|
|
143
|
+
ResolvedSimpleGoAccount --> MonitorParams : configures
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## 3. HTTP API
|
|
147
|
+
|
|
148
|
+
### 3.1 认证模型
|
|
149
|
+
|
|
150
|
+
```mermaid
|
|
151
|
+
flowchart LR
|
|
152
|
+
subgraph "Token Types"
|
|
153
|
+
AT[Admin Token]
|
|
154
|
+
CT[Client Token]
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
subgraph "Admin Endpoints"
|
|
158
|
+
RC["POST /clients"]
|
|
159
|
+
LC["GET /clients"]
|
|
160
|
+
LCV["GET /conversations"]
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
subgraph "Client Endpoints"
|
|
164
|
+
POLL["GET /poll"]
|
|
165
|
+
SEND["POST /send"]
|
|
166
|
+
GCV["GET /conversations/:id"]
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
subgraph "Public Endpoints"
|
|
170
|
+
INB["POST /inbound"]
|
|
171
|
+
OUT["GET /outbox"]
|
|
172
|
+
HLT["GET /health"]
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
AT -->|Bearer| RC
|
|
176
|
+
AT -->|Bearer| LC
|
|
177
|
+
AT -->|Bearer| LCV
|
|
178
|
+
|
|
179
|
+
CT -->|Bearer| POLL
|
|
180
|
+
CT -->|Bearer| SEND
|
|
181
|
+
CT -->|Bearer| GCV
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### 3.2 API 请求/响应
|
|
185
|
+
|
|
186
|
+
| Endpoint | Method | Auth | Request | Response |
|
|
187
|
+
|----------|--------|------|---------|----------|
|
|
188
|
+
| `/health` | GET | - | - | `{ok, server, clients, conversations}` |
|
|
189
|
+
| `/clients` | POST | Admin | `{name}` | `{clientId, token, name}` |
|
|
190
|
+
| `/clients` | GET | Admin | - | `{clients: [...]}` |
|
|
191
|
+
| `/conversations` | GET | Admin | - | `{conversations: [...]}` |
|
|
192
|
+
| `/poll` | GET | Client | - | `{messages: [...]}` |
|
|
193
|
+
| `/send` | POST | Client | `{to, text, conversationId}` | `{ok, message}` |
|
|
194
|
+
| `/conversations/:id` | GET | Client | - | `Conversation` |
|
|
195
|
+
| `/inbound` | POST | - | `{from, text}` | `Message` |
|
|
196
|
+
| `/outbox` | GET | - | - | `{messages: [...]}` |
|
|
197
|
+
|
|
198
|
+
## 4. 时序图
|
|
199
|
+
|
|
200
|
+
### 4.1 客户端注册流程
|
|
201
|
+
|
|
202
|
+
```mermaid
|
|
203
|
+
sequenceDiagram
|
|
204
|
+
participant Admin
|
|
205
|
+
participant Server as Go Server
|
|
206
|
+
participant DB as Server State
|
|
207
|
+
|
|
208
|
+
Admin->>Server: POST /clients {name: "client-1"}
|
|
209
|
+
Note over Admin,Server: Authorization: Bearer <admin-token>
|
|
210
|
+
|
|
211
|
+
Server->>DB: Generate clientID + token
|
|
212
|
+
Server->>DB: Store client info
|
|
213
|
+
Server->>DB: Create inbound queue
|
|
214
|
+
|
|
215
|
+
Server-->>Admin: {clientId, token, name}
|
|
216
|
+
|
|
217
|
+
Note over Admin: Save token for OpenClaw config
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### 4.2 插件启动流程
|
|
221
|
+
|
|
222
|
+
```mermaid
|
|
223
|
+
sequenceDiagram
|
|
224
|
+
participant GW as Gateway
|
|
225
|
+
participant Plugin as SimpleGo Plugin
|
|
226
|
+
participant Monitor
|
|
227
|
+
participant Server as Go Server
|
|
228
|
+
|
|
229
|
+
GW->>Plugin: loadPlugins()
|
|
230
|
+
Plugin->>GW: registerChannel()
|
|
231
|
+
|
|
232
|
+
GW->>Plugin: startAccount(ctx)
|
|
233
|
+
Plugin->>Plugin: resolveAccount(cfg)
|
|
234
|
+
|
|
235
|
+
Plugin->>Monitor: monitorSimpleGo(params)
|
|
236
|
+
|
|
237
|
+
loop Poll Loop
|
|
238
|
+
Monitor->>Server: GET /poll
|
|
239
|
+
Note over Monitor,Server: Authorization: Bearer <client-token>
|
|
240
|
+
Server-->>Monitor: {messages: [...]}
|
|
241
|
+
|
|
242
|
+
alt Has Messages
|
|
243
|
+
Monitor->>GW: runtime.handleInbound()
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
Monitor->>Monitor: sleep(pollIntervalMs)
|
|
247
|
+
end
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### 4.3 多轮对话流程
|
|
251
|
+
|
|
252
|
+
```mermaid
|
|
253
|
+
sequenceDiagram
|
|
254
|
+
participant User
|
|
255
|
+
participant Server as Go Server
|
|
256
|
+
participant OC1 as OpenClaw 1
|
|
257
|
+
participant OC2 as OpenClaw 2
|
|
258
|
+
participant AI
|
|
259
|
+
|
|
260
|
+
Note over Server: Load balancing: OC1 has 0 pending, OC2 has 2 pending
|
|
261
|
+
|
|
262
|
+
User->>Server: POST /inbound {from: "alice", text: "Hello"}
|
|
263
|
+
Server->>Server: getOrCreateConversation("alice")
|
|
264
|
+
Note over Server: Create conv-001, assign to OC1 (least busy)
|
|
265
|
+
Server->>Server: Queue message for OC1
|
|
266
|
+
Server-->>User: {id, conversationId: "conv-001"}
|
|
267
|
+
|
|
268
|
+
OC1->>Server: GET /poll
|
|
269
|
+
Server-->>OC1: {messages: [{...conversationId: "conv-001"}]}
|
|
270
|
+
|
|
271
|
+
OC1->>AI: Process message
|
|
272
|
+
AI-->>OC1: "Hi Alice!"
|
|
273
|
+
|
|
274
|
+
OC1->>Server: POST /send {to: "alice", text: "Hi!", conversationId: "conv-001"}
|
|
275
|
+
Server->>Server: Append to conv-001 history
|
|
276
|
+
Server-->>OC1: {ok: true}
|
|
277
|
+
|
|
278
|
+
Note over User,AI: === Second turn (same conversation) ===
|
|
279
|
+
|
|
280
|
+
User->>Server: POST /inbound {from: "alice", text: "How are you?"}
|
|
281
|
+
Server->>Server: Find existing conv-001 for alice
|
|
282
|
+
Note over Server: Reuse conv-001, still assigned to OC1
|
|
283
|
+
Server->>Server: Queue message for OC1
|
|
284
|
+
|
|
285
|
+
OC1->>Server: GET /poll
|
|
286
|
+
Server-->>OC1: {messages: [{...conversationId: "conv-001"}]}
|
|
287
|
+
|
|
288
|
+
OC1->>Server: GET /conversations/conv-001
|
|
289
|
+
Server-->>OC1: {messages: [msg1, msg2, msg3, ...]}
|
|
290
|
+
Note over OC1: Full conversation history available
|
|
291
|
+
|
|
292
|
+
OC1->>AI: Process with context
|
|
293
|
+
AI-->>OC1: "I'm doing great!"
|
|
294
|
+
|
|
295
|
+
OC1->>Server: POST /send {...conversationId: "conv-001"}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### 4.4 多客户端负载均衡
|
|
299
|
+
|
|
300
|
+
```mermaid
|
|
301
|
+
sequenceDiagram
|
|
302
|
+
participant U1 as User Alice
|
|
303
|
+
participant U2 as User Bob
|
|
304
|
+
participant U3 as User Carol
|
|
305
|
+
participant Server as Go Server
|
|
306
|
+
participant OC1 as OpenClaw 1
|
|
307
|
+
participant OC2 as OpenClaw 2
|
|
308
|
+
|
|
309
|
+
Note over Server: Initial state: OC1=0, OC2=0 pending
|
|
310
|
+
|
|
311
|
+
U1->>Server: POST /inbound {from: "alice"}
|
|
312
|
+
Server->>Server: Assign alice → OC1 (random tie-break)
|
|
313
|
+
|
|
314
|
+
U2->>Server: POST /inbound {from: "bob"}
|
|
315
|
+
Server->>Server: OC1=1, OC2=0 → Assign bob → OC2
|
|
316
|
+
|
|
317
|
+
U3->>Server: POST /inbound {from: "carol"}
|
|
318
|
+
Server->>Server: OC1=1, OC2=1 → Assign carol → OC1
|
|
319
|
+
|
|
320
|
+
par Parallel polling
|
|
321
|
+
OC1->>Server: GET /poll
|
|
322
|
+
Server-->>OC1: [alice msg, carol msg]
|
|
323
|
+
and
|
|
324
|
+
OC2->>Server: GET /poll
|
|
325
|
+
Server-->>OC2: [bob msg]
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
Note over OC1,OC2: Each client handles its assigned users
|
|
329
|
+
|
|
330
|
+
U1->>Server: POST /inbound {from: "alice", text: "follow-up"}
|
|
331
|
+
Note over Server: alice already assigned to OC1
|
|
332
|
+
Server->>Server: Queue for OC1 (sticky session)
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
## 5. 状态机
|
|
336
|
+
|
|
337
|
+
### 5.1 对话生命周期
|
|
338
|
+
|
|
339
|
+
```mermaid
|
|
340
|
+
stateDiagram-v2
|
|
341
|
+
[*] --> Created: User sends first message
|
|
342
|
+
Created --> Active: Client polls message
|
|
343
|
+
Active --> Active: User/Bot exchange messages
|
|
344
|
+
Active --> Idle: No activity for N minutes
|
|
345
|
+
Idle --> Active: New message received
|
|
346
|
+
Idle --> Expired: TTL exceeded
|
|
347
|
+
Expired --> [*]: Cleanup
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### 5.2 客户端状态
|
|
351
|
+
|
|
352
|
+
```mermaid
|
|
353
|
+
stateDiagram-v2
|
|
354
|
+
[*] --> Registered: Admin creates client
|
|
355
|
+
Registered --> Connected: First poll received
|
|
356
|
+
Connected --> Connected: Regular polling
|
|
357
|
+
Connected --> Stale: No poll for 30s
|
|
358
|
+
Stale --> Connected: Poll received
|
|
359
|
+
Stale --> Disconnected: No poll for 5min
|
|
360
|
+
Disconnected --> Connected: Poll received
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
## 6. 组件职责
|
|
364
|
+
|
|
365
|
+
| 组件 | 文件 | 职责 |
|
|
366
|
+
|------|------|------|
|
|
367
|
+
| **Go Server** | `server/main.go` | HTTP API, 认证, 消息路由, 会话管理 |
|
|
368
|
+
| **Plugin Entry** | `index.ts` | 插件注册入口 |
|
|
369
|
+
| **Channel Plugin** | `src/channel.ts` | ChannelPlugin 接口实现 |
|
|
370
|
+
| **Monitor** | `src/monitor.ts` | 轮询循环, Token认证, 消息转发 |
|
|
371
|
+
|
|
372
|
+
## 7. 配置示例
|
|
373
|
+
|
|
374
|
+
```yaml
|
|
375
|
+
# ~/.openclaw/config.yaml
|
|
376
|
+
channels:
|
|
377
|
+
simplego:
|
|
378
|
+
enabled: true
|
|
379
|
+
serverUrl: "http://localhost:9876"
|
|
380
|
+
apiToken: "your-client-token-here" # 从 POST /clients 获取
|
|
381
|
+
pollIntervalMs: 1000
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
## 8. 使用流程
|
|
385
|
+
|
|
386
|
+
```mermaid
|
|
387
|
+
flowchart TD
|
|
388
|
+
A[启动 Go Server] --> B[获取 Admin Token]
|
|
389
|
+
B --> C[注册 OpenClaw Client]
|
|
390
|
+
C --> D[获取 Client Token]
|
|
391
|
+
D --> E[配置 OpenClaw]
|
|
392
|
+
E --> F[启动 OpenClaw Gateway]
|
|
393
|
+
F --> G[测试发送消息]
|
|
394
|
+
|
|
395
|
+
subgraph "Admin 操作"
|
|
396
|
+
B
|
|
397
|
+
C
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
subgraph "Client 配置"
|
|
401
|
+
D
|
|
402
|
+
E
|
|
403
|
+
F
|
|
404
|
+
end
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### 命令示例
|
|
408
|
+
|
|
409
|
+
```bash
|
|
410
|
+
# 1. 启动服务器 (会打印 admin token)
|
|
411
|
+
cd server && go run main.go
|
|
412
|
+
|
|
413
|
+
# 2. 注册客户端
|
|
414
|
+
curl -X POST http://localhost:9876/clients \
|
|
415
|
+
-H "Authorization: Bearer <admin-token>" \
|
|
416
|
+
-H "Content-Type: application/json" \
|
|
417
|
+
-d '{"name": "my-openclaw"}'
|
|
418
|
+
# 返回: {"clientId": "client-xxx", "token": "xxx", "name": "my-openclaw"}
|
|
419
|
+
|
|
420
|
+
# 3. 配置 OpenClaw
|
|
421
|
+
openclaw config set channels.simplego.enabled true
|
|
422
|
+
openclaw config set channels.simplego.serverUrl "http://localhost:9876"
|
|
423
|
+
openclaw config set channels.simplego.apiToken "<client-token>"
|
|
424
|
+
|
|
425
|
+
# 4. 启动 Gateway
|
|
426
|
+
openclaw gateway run
|
|
427
|
+
|
|
428
|
+
# 5. 测试消息
|
|
429
|
+
curl -X POST http://localhost:9876/inbound \
|
|
430
|
+
-H "Content-Type: application/json" \
|
|
431
|
+
-d '{"from": "test-user", "text": "Hello!"}'
|
|
432
|
+
|
|
433
|
+
# 6. 查看响应
|
|
434
|
+
curl http://localhost:9876/outbox
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
## 9. 部署流程
|
|
438
|
+
|
|
439
|
+
### 9.1 部署架构
|
|
440
|
+
|
|
441
|
+
```mermaid
|
|
442
|
+
flowchart TB
|
|
443
|
+
subgraph "Production Environment"
|
|
444
|
+
subgraph "Server Node"
|
|
445
|
+
GO[Go Server]
|
|
446
|
+
NGINX[Nginx Reverse Proxy]
|
|
447
|
+
SYSTEMD[Systemd Service]
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
subgraph "Client Nodes"
|
|
451
|
+
OC1[OpenClaw Instance 1]
|
|
452
|
+
OC2[OpenClaw Instance 2]
|
|
453
|
+
end
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
subgraph "External"
|
|
457
|
+
USERS[Users / Webhooks]
|
|
458
|
+
DNS[DNS: api.example.com]
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
DNS --> NGINX
|
|
462
|
+
NGINX -->|":9876"| GO
|
|
463
|
+
USERS -->|HTTPS| NGINX
|
|
464
|
+
OC1 -->|HTTPS| NGINX
|
|
465
|
+
OC2 -->|HTTPS| NGINX
|
|
466
|
+
SYSTEMD -.->|manages| GO
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### 9.2 Go 服务端部署
|
|
470
|
+
|
|
471
|
+
#### 方式一:二进制部署
|
|
472
|
+
|
|
473
|
+
```bash
|
|
474
|
+
# 1. 编译
|
|
475
|
+
cd server
|
|
476
|
+
GOOS=linux GOARCH=amd64 go build -o simplego-server main.go
|
|
477
|
+
|
|
478
|
+
# 2. 上传到服务器
|
|
479
|
+
scp simplego-server user@server:/opt/simplego/
|
|
480
|
+
|
|
481
|
+
# 3. 创建 systemd 服务
|
|
482
|
+
cat <<'EOF' | sudo tee /etc/systemd/system/simplego.service
|
|
483
|
+
[Unit]
|
|
484
|
+
Description=Simple Go Channel Server
|
|
485
|
+
After=network.target
|
|
486
|
+
|
|
487
|
+
[Service]
|
|
488
|
+
Type=simple
|
|
489
|
+
User=www-data
|
|
490
|
+
WorkingDirectory=/opt/simplego
|
|
491
|
+
ExecStart=/opt/simplego/simplego-server --port 9876 --admin-token ${ADMIN_TOKEN}
|
|
492
|
+
Restart=always
|
|
493
|
+
RestartSec=5
|
|
494
|
+
Environment=ADMIN_TOKEN=your-secure-admin-token
|
|
495
|
+
|
|
496
|
+
[Install]
|
|
497
|
+
WantedBy=multi-user.target
|
|
498
|
+
EOF
|
|
499
|
+
|
|
500
|
+
# 4. 启动服务
|
|
501
|
+
sudo systemctl daemon-reload
|
|
502
|
+
sudo systemctl enable simplego
|
|
503
|
+
sudo systemctl start simplego
|
|
504
|
+
|
|
505
|
+
# 5. 检查状态
|
|
506
|
+
sudo systemctl status simplego
|
|
507
|
+
journalctl -u simplego -f
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
#### 方式二:Docker 部署
|
|
511
|
+
|
|
512
|
+
```dockerfile
|
|
513
|
+
# Dockerfile
|
|
514
|
+
FROM golang:1.21-alpine AS builder
|
|
515
|
+
WORKDIR /app
|
|
516
|
+
COPY server/ .
|
|
517
|
+
RUN go build -o simplego-server main.go
|
|
518
|
+
|
|
519
|
+
FROM alpine:latest
|
|
520
|
+
RUN apk --no-cache add ca-certificates
|
|
521
|
+
WORKDIR /app
|
|
522
|
+
COPY --from=builder /app/simplego-server .
|
|
523
|
+
EXPOSE 9876
|
|
524
|
+
ENTRYPOINT ["./simplego-server"]
|
|
525
|
+
CMD ["--port", "9876"]
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
```yaml
|
|
529
|
+
# docker-compose.yml
|
|
530
|
+
version: '3.8'
|
|
531
|
+
services:
|
|
532
|
+
simplego:
|
|
533
|
+
build: .
|
|
534
|
+
ports:
|
|
535
|
+
- "9876:9876"
|
|
536
|
+
environment:
|
|
537
|
+
- ADMIN_TOKEN=${ADMIN_TOKEN}
|
|
538
|
+
command: ["--port", "9876", "--admin-token", "${ADMIN_TOKEN}"]
|
|
539
|
+
restart: unless-stopped
|
|
540
|
+
healthcheck:
|
|
541
|
+
test: ["CMD", "wget", "-q", "--spider", "http://localhost:9876/health"]
|
|
542
|
+
interval: 30s
|
|
543
|
+
timeout: 10s
|
|
544
|
+
retries: 3
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
```bash
|
|
548
|
+
# 部署命令
|
|
549
|
+
export ADMIN_TOKEN=$(openssl rand -hex 32)
|
|
550
|
+
echo "Admin Token: $ADMIN_TOKEN"
|
|
551
|
+
docker-compose up -d
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
### 9.3 Nginx 反向代理配置
|
|
555
|
+
|
|
556
|
+
```nginx
|
|
557
|
+
# /etc/nginx/sites-available/simplego
|
|
558
|
+
upstream simple_go {
|
|
559
|
+
server 127.0.0.1:9876;
|
|
560
|
+
keepalive 32;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
server {
|
|
564
|
+
listen 443 ssl http2;
|
|
565
|
+
server_name api.example.com;
|
|
566
|
+
|
|
567
|
+
ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
|
|
568
|
+
ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
|
|
569
|
+
|
|
570
|
+
location / {
|
|
571
|
+
proxy_pass http://simple_go;
|
|
572
|
+
proxy_http_version 1.1;
|
|
573
|
+
proxy_set_header Host $host;
|
|
574
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
575
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
576
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
577
|
+
|
|
578
|
+
# 长轮询支持
|
|
579
|
+
proxy_read_timeout 120s;
|
|
580
|
+
proxy_connect_timeout 10s;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
# 健康检查端点(无需认证)
|
|
584
|
+
location /health {
|
|
585
|
+
proxy_pass http://simple_go/health;
|
|
586
|
+
access_log off;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
server {
|
|
591
|
+
listen 80;
|
|
592
|
+
server_name api.example.com;
|
|
593
|
+
return 301 https://$server_name$request_uri;
|
|
594
|
+
}
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
```bash
|
|
598
|
+
# 启用配置
|
|
599
|
+
sudo ln -s /etc/nginx/sites-available/simplego /etc/nginx/sites-enabled/
|
|
600
|
+
sudo nginx -t
|
|
601
|
+
sudo systemctl reload nginx
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
### 9.4 OpenClaw 客户端部署
|
|
605
|
+
|
|
606
|
+
```mermaid
|
|
607
|
+
sequenceDiagram
|
|
608
|
+
participant Admin
|
|
609
|
+
participant Server as Go Server
|
|
610
|
+
participant OC as OpenClaw Client
|
|
611
|
+
|
|
612
|
+
Admin->>Server: 1. 启动服务器
|
|
613
|
+
Note over Server: 记录 Admin Token
|
|
614
|
+
|
|
615
|
+
Admin->>Server: 2. POST /clients
|
|
616
|
+
Server-->>Admin: {clientId, token}
|
|
617
|
+
|
|
618
|
+
Admin->>OC: 3. 配置 config.yaml
|
|
619
|
+
Note over OC: serverUrl + apiToken
|
|
620
|
+
|
|
621
|
+
Admin->>OC: 4. 启动 Gateway
|
|
622
|
+
OC->>Server: 5. GET /poll (验证连接)
|
|
623
|
+
Server-->>OC: {messages: []}
|
|
624
|
+
|
|
625
|
+
Note over Admin,OC: 部署完成,开始接收消息
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
#### 客户端配置步骤
|
|
629
|
+
|
|
630
|
+
```bash
|
|
631
|
+
# 1. 在服务器上注册客户端
|
|
632
|
+
ADMIN_TOKEN="your-admin-token"
|
|
633
|
+
SERVER_URL="https://api.example.com"
|
|
634
|
+
|
|
635
|
+
CLIENT_RESPONSE=$(curl -s -X POST "$SERVER_URL/clients" \
|
|
636
|
+
-H "Authorization: Bearer $ADMIN_TOKEN" \
|
|
637
|
+
-H "Content-Type: application/json" \
|
|
638
|
+
-d '{"name": "production-client-1"}')
|
|
639
|
+
|
|
640
|
+
CLIENT_TOKEN=$(echo $CLIENT_RESPONSE | jq -r '.token')
|
|
641
|
+
echo "Client Token: $CLIENT_TOKEN"
|
|
642
|
+
|
|
643
|
+
# 2. 在 OpenClaw 机器上配置
|
|
644
|
+
openclaw config set channels.simplego.enabled true
|
|
645
|
+
openclaw config set channels.simplego.serverUrl "$SERVER_URL"
|
|
646
|
+
openclaw config set channels.simplego.apiToken "$CLIENT_TOKEN"
|
|
647
|
+
openclaw config set channels.simplego.pollIntervalMs 1000
|
|
648
|
+
|
|
649
|
+
# 3. 验证配置
|
|
650
|
+
openclaw channels status simplego
|
|
651
|
+
|
|
652
|
+
# 4. 启动 Gateway
|
|
653
|
+
openclaw gateway run
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
### 9.5 多节点部署拓扑
|
|
657
|
+
|
|
658
|
+
```mermaid
|
|
659
|
+
flowchart TB
|
|
660
|
+
subgraph "Load Balancer"
|
|
661
|
+
LB[HAProxy / AWS ALB]
|
|
662
|
+
end
|
|
663
|
+
|
|
664
|
+
subgraph "Go Server Cluster"
|
|
665
|
+
GO1[Go Server 1]
|
|
666
|
+
GO2[Go Server 2]
|
|
667
|
+
REDIS[(Redis)]
|
|
668
|
+
end
|
|
669
|
+
|
|
670
|
+
subgraph "OpenClaw Cluster"
|
|
671
|
+
OC1[OpenClaw 1<br/>Region: US]
|
|
672
|
+
OC2[OpenClaw 2<br/>Region: EU]
|
|
673
|
+
OC3[OpenClaw 3<br/>Region: APAC]
|
|
674
|
+
end
|
|
675
|
+
|
|
676
|
+
LB --> GO1
|
|
677
|
+
LB --> GO2
|
|
678
|
+
GO1 <--> REDIS
|
|
679
|
+
GO2 <--> REDIS
|
|
680
|
+
|
|
681
|
+
OC1 --> LB
|
|
682
|
+
OC2 --> LB
|
|
683
|
+
OC3 --> LB
|
|
684
|
+
|
|
685
|
+
Note1[共享状态存储于 Redis]
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
> **注意**:当前实现使用内存存储,多节点部署需要先实现 Redis 持久化层。
|
|
689
|
+
|
|
690
|
+
### 9.6 部署检查清单
|
|
691
|
+
|
|
692
|
+
```markdown
|
|
693
|
+
## 部署前检查
|
|
694
|
+
|
|
695
|
+
- [ ] Go 服务器编译完成
|
|
696
|
+
- [ ] Admin Token 已安全存储
|
|
697
|
+
- [ ] SSL 证书已配置
|
|
698
|
+
- [ ] 防火墙规则已开放 (443/tcp)
|
|
699
|
+
- [ ] Systemd 服务已启用
|
|
700
|
+
|
|
701
|
+
## 部署后验证
|
|
702
|
+
|
|
703
|
+
- [ ] `curl https://api.example.com/health` 返回 `{"ok": true}`
|
|
704
|
+
- [ ] 成功注册客户端并获取 token
|
|
705
|
+
- [ ] OpenClaw `channels status simplego` 显示 configured=true
|
|
706
|
+
- [ ] 发送测试消息并收到响应
|
|
707
|
+
- [ ] 日志正常无错误
|
|
708
|
+
|
|
709
|
+
## 监控告警
|
|
710
|
+
|
|
711
|
+
- [ ] 配置 /health 端点监控
|
|
712
|
+
- [ ] 配置错误日志告警
|
|
713
|
+
- [ ] 配置 CPU/内存告警阈值
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
### 9.7 环境变量参考
|
|
717
|
+
|
|
718
|
+
| 变量名 | 说明 | 示例 |
|
|
719
|
+
|--------|------|------|
|
|
720
|
+
| `ADMIN_TOKEN` | 管理员认证令牌 | `openssl rand -hex 32` |
|
|
721
|
+
| `PORT` | 服务端口 | `9876` |
|
|
722
|
+
| `LOG_LEVEL` | 日志级别 | `info` / `debug` |
|
|
723
|
+
|
|
724
|
+
## 10. 扩展点
|
|
725
|
+
|
|
726
|
+
| 功能 | 实现建议 |
|
|
727
|
+
|------|---------|
|
|
728
|
+
| **WebSocket** | 替换轮询为双向 WebSocket |
|
|
729
|
+
| **持久化** | 使用 SQLite/PostgreSQL 存储会话 |
|
|
730
|
+
| **媒体支持** | 扩展 Message 结构,添加文件上传端点 |
|
|
731
|
+
| **会话过期** | 添加 TTL 和定时清理 goroutine |
|
|
732
|
+
| **指标监控** | 添加 Prometheus metrics 端点 |
|
|
733
|
+
| **速率限制** | 添加 per-client 请求限流 |
|