alemonjs 2.1.0-alpha.25 → 2.1.0-alpha.26
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/lib/cbp/config.js +3 -1
- package/lib/cbp/index.js +389 -328
- package/lib/cbp/router.js +4 -3
- package/package.json +1 -1
package/lib/cbp/config.js
CHANGED
package/lib/cbp/index.js
CHANGED
|
@@ -3,371 +3,432 @@ import { WebSocketServer, WebSocket } from 'ws';
|
|
|
3
3
|
import router from './router.js';
|
|
4
4
|
import koaCors from '@koa/cors';
|
|
5
5
|
import { ResultCode } from '../core/code.js';
|
|
6
|
-
import {
|
|
6
|
+
import { platformClient, childrenClient, fullClient, childrenBind, USER_AGENT_HEADER, USER_AGENT_HEADER_VALUE_MAP, DEVICE_ID_HEADER, FULL_RECEIVE_HEADER } from './config.js';
|
|
7
7
|
import { getConfig } from '../core/config.js';
|
|
8
8
|
import * as flattedJSON from 'flatted';
|
|
9
9
|
import { connectionTestOne } from './testone.js';
|
|
10
10
|
|
|
11
|
+
function getReConnectTime() {
|
|
12
|
+
const time = 1000 * 1;
|
|
13
|
+
const curTime = time;
|
|
14
|
+
const mTime = (curTime / 1000 / 60).toFixed(2);
|
|
15
|
+
logger.info({
|
|
16
|
+
code: ResultCode.Fail,
|
|
17
|
+
message: `[ws-discord] 等待 ${mTime} 分钟后重新连接`,
|
|
18
|
+
data: null
|
|
19
|
+
});
|
|
20
|
+
return curTime;
|
|
21
|
+
}
|
|
11
22
|
const cbpServer = (port, listeningListener) => {
|
|
12
23
|
if (global.chatbotServer) {
|
|
13
24
|
delete global.chatbotServer;
|
|
14
25
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
// 设置平台客户端
|
|
45
|
-
platformClient.set(originId, ws);
|
|
46
|
-
// 处理api
|
|
47
|
-
const handleApi = (DeviceId, message) => {
|
|
48
|
-
// 指定的设备 处理消费。终端有记录每个客户端是谁
|
|
49
|
-
if (childrenClient.has(DeviceId)) {
|
|
50
|
-
const clientWs = childrenClient.get(DeviceId);
|
|
51
|
-
if (clientWs && clientWs.readyState === WebSocket.OPEN) {
|
|
52
|
-
// 发送消息到指定的子客户端
|
|
53
|
-
clientWs.send(message);
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
// 如果连接已关闭,删除该客户端
|
|
57
|
-
childrenClient.delete(DeviceId);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
else if (fullClient.has(DeviceId)) {
|
|
61
|
-
const clientWs = fullClient.get(DeviceId);
|
|
62
|
-
if (clientWs && clientWs.readyState === WebSocket.OPEN) {
|
|
63
|
-
// 发送消息到指定的全量客户端
|
|
64
|
-
clientWs.send(message);
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
// 如果连接已关闭,删除该客户端
|
|
68
|
-
fullClient.delete(DeviceId);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
// 处理 action
|
|
73
|
-
const handleAction = (DeviceId, message) => {
|
|
74
|
-
if (childrenClient.has(DeviceId)) {
|
|
75
|
-
const clientWs = childrenClient.get(DeviceId);
|
|
76
|
-
if (clientWs && clientWs.readyState === WebSocket.OPEN) {
|
|
77
|
-
// 发送消息到指定的子客户端
|
|
78
|
-
clientWs.send(message);
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
// 如果连接已关闭,删除该客户端
|
|
82
|
-
childrenClient.delete(DeviceId);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
else if (fullClient.has(DeviceId)) {
|
|
86
|
-
const clientWs = fullClient.get(DeviceId);
|
|
87
|
-
if (clientWs && clientWs.readyState === WebSocket.OPEN) {
|
|
88
|
-
// 发送消息到指定的全量客户端
|
|
89
|
-
clientWs.send(message);
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
// 如果连接已关闭,删除该客户端
|
|
93
|
-
fullClient.delete(DeviceId);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
// 处理事件
|
|
98
|
-
const handleEvent = (message, ID) => {
|
|
99
|
-
// 全量客户端
|
|
100
|
-
fullClient.forEach((clientWs, clientId) => {
|
|
101
|
-
// 检查状态 并检查状态
|
|
102
|
-
if (clientWs.readyState === WebSocket.OPEN) {
|
|
103
|
-
clientWs.send(message);
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
// 如果连接已关闭,删除该客户端
|
|
107
|
-
childrenClient.delete(clientId);
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
// 根据所在群进行分流。
|
|
111
|
-
// 确保同一个频道的消息。都流向同一个客户端。
|
|
112
|
-
if (!ID) {
|
|
113
|
-
logger.error({
|
|
114
|
-
code: ResultCode.Fail,
|
|
115
|
-
message: '消息缺少标识符 ID',
|
|
116
|
-
data: null
|
|
117
|
-
});
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
// 重新绑定并发送消息
|
|
121
|
-
const reBind = () => {
|
|
122
|
-
if (childrenClient.size === 0) {
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
else if (childrenClient.size === 1) {
|
|
126
|
-
// 只有一个客户端,直接绑定
|
|
127
|
-
const [bindId, clientWs] = childrenClient.entries().next().value;
|
|
128
|
-
childrenBind.set(ID, bindId);
|
|
129
|
-
clientWs.send(message);
|
|
26
|
+
const createServer = () => {
|
|
27
|
+
try {
|
|
28
|
+
// create
|
|
29
|
+
const app = new Koa();
|
|
30
|
+
// MessageRouter
|
|
31
|
+
app.use(router.routes());
|
|
32
|
+
app.use(router.allowedMethods());
|
|
33
|
+
// Cors
|
|
34
|
+
app.use(koaCors({
|
|
35
|
+
origin: '*', // 允许所有来源
|
|
36
|
+
allowMethods: ['GET', 'POST', 'PUT', 'DELETE'] // 允许的 HTTP 方法
|
|
37
|
+
}));
|
|
38
|
+
const server = app.listen(port, listeningListener);
|
|
39
|
+
// 创建 WebSocketServer 并监听同一个端口
|
|
40
|
+
global.chatbotServer = new WebSocketServer({ server });
|
|
41
|
+
/**
|
|
42
|
+
*
|
|
43
|
+
* @param originId
|
|
44
|
+
* @param ws
|
|
45
|
+
*/
|
|
46
|
+
const setPlatformClient = (originId, ws) => {
|
|
47
|
+
// 仅允许有一个平台连接
|
|
48
|
+
if (platformClient.size > 0) {
|
|
49
|
+
logger.error({
|
|
50
|
+
code: ResultCode.Fail,
|
|
51
|
+
message: `平台连接已存在: ${originId}`,
|
|
52
|
+
data: null
|
|
53
|
+
});
|
|
54
|
+
ws.close(); // 关闭新连接
|
|
130
55
|
return;
|
|
131
56
|
}
|
|
132
|
-
//
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
57
|
+
// 设置平台客户端
|
|
58
|
+
platformClient.set(originId, ws);
|
|
59
|
+
// 处理api
|
|
60
|
+
const handleApi = (DeviceId, message) => {
|
|
61
|
+
// 指定的设备 处理消费。终端有记录每个客户端是谁
|
|
62
|
+
if (childrenClient.has(DeviceId)) {
|
|
63
|
+
const clientWs = childrenClient.get(DeviceId);
|
|
64
|
+
if (clientWs && clientWs.readyState === WebSocket.OPEN) {
|
|
65
|
+
// 发送消息到指定的子客户端
|
|
66
|
+
clientWs.send(message);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
// 如果连接已关闭,删除该客户端
|
|
70
|
+
childrenClient.delete(DeviceId);
|
|
71
|
+
}
|
|
141
72
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
73
|
+
else if (fullClient.has(DeviceId)) {
|
|
74
|
+
const clientWs = fullClient.get(DeviceId);
|
|
75
|
+
if (clientWs && clientWs.readyState === WebSocket.OPEN) {
|
|
76
|
+
// 发送消息到指定的全量客户端
|
|
77
|
+
clientWs.send(message);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
// 如果连接已关闭,删除该客户端
|
|
81
|
+
fullClient.delete(DeviceId);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
// 处理 action
|
|
86
|
+
const handleAction = (DeviceId, message) => {
|
|
87
|
+
if (childrenClient.has(DeviceId)) {
|
|
88
|
+
const clientWs = childrenClient.get(DeviceId);
|
|
89
|
+
if (clientWs && clientWs.readyState === WebSocket.OPEN) {
|
|
90
|
+
// 发送消息到指定的子客户端
|
|
91
|
+
clientWs.send(message);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
// 如果连接已关闭,删除该客户端
|
|
95
|
+
childrenClient.delete(DeviceId);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else if (fullClient.has(DeviceId)) {
|
|
99
|
+
const clientWs = fullClient.get(DeviceId);
|
|
100
|
+
if (clientWs && clientWs.readyState === WebSocket.OPEN) {
|
|
101
|
+
// 发送消息到指定的全量客户端
|
|
102
|
+
clientWs.send(message);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
// 如果连接已关闭,删除该客户端
|
|
106
|
+
fullClient.delete(DeviceId);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
// 处理事件
|
|
111
|
+
const handleEvent = (message, ID) => {
|
|
112
|
+
// 全量客户端
|
|
113
|
+
fullClient.forEach((clientWs, clientId) => {
|
|
114
|
+
// 检查状态 并检查状态
|
|
115
|
+
if (clientWs.readyState === WebSocket.OPEN) {
|
|
116
|
+
clientWs.send(message);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
// 如果连接已关闭,删除该客户端
|
|
120
|
+
childrenClient.delete(clientId);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
// 根据所在群进行分流。
|
|
124
|
+
// 确保同一个频道的消息。都流向同一个客户端。
|
|
125
|
+
if (!ID) {
|
|
126
|
+
logger.error({
|
|
127
|
+
code: ResultCode.Fail,
|
|
128
|
+
message: '消息缺少标识符 ID',
|
|
129
|
+
data: null
|
|
130
|
+
});
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
// 重新绑定并发送消息
|
|
134
|
+
const reBind = () => {
|
|
135
|
+
if (childrenClient.size === 0) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
else if (childrenClient.size === 1) {
|
|
139
|
+
// 只有一个客户端,直接绑定
|
|
140
|
+
const [bindId, clientWs] = childrenClient.entries().next().value;
|
|
141
|
+
childrenBind.set(ID, bindId);
|
|
142
|
+
clientWs.send(message);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
// 有多个客户端,找到绑定最少的那个。
|
|
146
|
+
// 如果大家都一样。就拿最近的第一个直接绑定。
|
|
147
|
+
let minBindCount = Infinity;
|
|
148
|
+
let bindId = null;
|
|
149
|
+
childrenClient.forEach((_, id) => {
|
|
150
|
+
const count = Array.from(childrenBind.values()).filter(v => v === id).length;
|
|
151
|
+
if (count < minBindCount) {
|
|
152
|
+
minBindCount = count;
|
|
153
|
+
bindId = id;
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
if (bindId) {
|
|
157
|
+
const clientWs = childrenClient.get(bindId);
|
|
158
|
+
if (clientWs && clientWs.readyState === WebSocket.OPEN) {
|
|
159
|
+
// 进行绑定
|
|
160
|
+
childrenBind.set(ID, bindId);
|
|
161
|
+
// 发送消息到绑定的客户端
|
|
162
|
+
clientWs.send(message);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
// 如果连接已关闭,删除该客户端
|
|
166
|
+
childrenClient.delete(bindId);
|
|
167
|
+
// 重新进行绑定
|
|
168
|
+
reBind();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
logger.error({
|
|
173
|
+
code: ResultCode.Fail,
|
|
174
|
+
message: '服务端出现意外,无法绑定客户端',
|
|
175
|
+
data: null
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
// 判断该id是否被分配过
|
|
180
|
+
if (!childrenBind.has(ID)) {
|
|
146
181
|
// 进行绑定
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
clientWs.send(message);
|
|
182
|
+
reBind();
|
|
183
|
+
return;
|
|
150
184
|
}
|
|
151
|
-
|
|
185
|
+
const bindId = childrenBind.get(ID);
|
|
186
|
+
if (!childrenClient.has(bindId)) {
|
|
187
|
+
// 出现意外。
|
|
188
|
+
// 重新进行绑定。
|
|
189
|
+
reBind();
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const clientWs = childrenClient.get(bindId);
|
|
193
|
+
if (!clientWs || clientWs.readyState !== WebSocket.OPEN) {
|
|
152
194
|
// 如果连接已关闭,删除该客户端
|
|
153
195
|
childrenClient.delete(bindId);
|
|
154
196
|
// 重新进行绑定
|
|
155
197
|
reBind();
|
|
198
|
+
return;
|
|
156
199
|
}
|
|
157
|
-
|
|
158
|
-
|
|
200
|
+
clientWs.send(message);
|
|
201
|
+
};
|
|
202
|
+
// 得到平台客户端的消息
|
|
203
|
+
ws.on('message', (message) => {
|
|
204
|
+
try {
|
|
205
|
+
// 解析消息
|
|
206
|
+
const parsedMessage = flattedJSON.parse(message.toString());
|
|
207
|
+
// 1. 解析得到 actionId ,说明是消费行为请求。要广播告诉所有客户端。
|
|
208
|
+
// 2. 解析得到 name ,说明是一个事件请求。
|
|
209
|
+
// 3. 解析得到 apiId ,说明是一个接口请求。
|
|
210
|
+
// 4. 解析得到 testID ,说明是一个测试请求。
|
|
211
|
+
logger.debug({
|
|
212
|
+
code: ResultCode.Ok,
|
|
213
|
+
message: '服务端接收到消息',
|
|
214
|
+
data: parsedMessage
|
|
215
|
+
});
|
|
216
|
+
if (parsedMessage.apiId) {
|
|
217
|
+
// 指定的设备 处理消费。终端有记录每个客户端是谁
|
|
218
|
+
const DeviceId = parsedMessage.DeviceId;
|
|
219
|
+
handleApi(DeviceId, message);
|
|
220
|
+
}
|
|
221
|
+
else if (parsedMessage?.actionId) {
|
|
222
|
+
// 指定的设备 处理消费。终端有记录每个客户端是谁
|
|
223
|
+
const DeviceId = parsedMessage.DeviceId;
|
|
224
|
+
handleAction(DeviceId, message);
|
|
225
|
+
}
|
|
226
|
+
else if (parsedMessage?.name) {
|
|
227
|
+
const ID = parsedMessage.ChannelId || parsedMessage.GuildId || parsedMessage.DeviceId;
|
|
228
|
+
handleEvent(message, ID);
|
|
229
|
+
}
|
|
230
|
+
else if (parsedMessage?.testID) {
|
|
231
|
+
// 继续解析数据。测试请求。
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
logger.error({
|
|
236
|
+
code: ResultCode.Fail,
|
|
237
|
+
message: '服务端解析平台消息失败',
|
|
238
|
+
data: error
|
|
239
|
+
});
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
// 处理关闭事件
|
|
244
|
+
ws.on('close', () => {
|
|
245
|
+
platformClient.delete(originId);
|
|
246
|
+
logger.debug({
|
|
247
|
+
code: ResultCode.Fail,
|
|
248
|
+
message: `Client ${originId} disconnected`,
|
|
249
|
+
data: null
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
ws.on('error', err => {
|
|
159
253
|
logger.error({
|
|
160
254
|
code: ResultCode.Fail,
|
|
161
|
-
message:
|
|
255
|
+
message: `Client ${originId} error`,
|
|
256
|
+
data: err
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
};
|
|
260
|
+
// 设置子客户端
|
|
261
|
+
const setChildrenClient = (originId, ws) => {
|
|
262
|
+
childrenClient.set(originId, ws);
|
|
263
|
+
// 得到子客户端的消息。只会是actions请求。
|
|
264
|
+
ws.on('message', (message) => {
|
|
265
|
+
// tudo
|
|
266
|
+
// 为什么 子客户端的行为,不携带目标平台的 DeviceId?
|
|
267
|
+
// 导致无法进行多个平台连接。
|
|
268
|
+
if (platformClient.size > 0) {
|
|
269
|
+
platformClient.forEach((platformWs, platformId) => {
|
|
270
|
+
// 检查平台客户端状态
|
|
271
|
+
if (platformWs.readyState === WebSocket.OPEN) {
|
|
272
|
+
platformWs.send(message);
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
// 如果连接已关闭,删除该平台客户端
|
|
276
|
+
platformClient.delete(platformId);
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
// 处理关闭事件
|
|
282
|
+
ws.on('close', () => {
|
|
283
|
+
childrenClient.delete(originId);
|
|
284
|
+
logger.debug({
|
|
285
|
+
code: ResultCode.Fail,
|
|
286
|
+
message: `Client ${originId} disconnected`,
|
|
162
287
|
data: null
|
|
163
288
|
});
|
|
164
|
-
}
|
|
289
|
+
});
|
|
290
|
+
ws.on('error', err => {
|
|
291
|
+
logger.error({
|
|
292
|
+
code: ResultCode.Fail,
|
|
293
|
+
message: `Client ${originId} error`,
|
|
294
|
+
data: err
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
};
|
|
298
|
+
// 全量客户端
|
|
299
|
+
const setFullClient = (originId, ws) => {
|
|
300
|
+
fullClient.set(originId, ws);
|
|
301
|
+
// 处理消息事件
|
|
302
|
+
ws.on('message', (message) => {
|
|
303
|
+
// tudo
|
|
304
|
+
// 为什么 子客户端的行为,不携带目标平台的 DeviceId?
|
|
305
|
+
// 导致无法进行多个平台连接。
|
|
306
|
+
if (platformClient.size > 0) {
|
|
307
|
+
platformClient.forEach((platformWs, platformId) => {
|
|
308
|
+
// 检查平台客户端状态
|
|
309
|
+
if (platformWs.readyState === WebSocket.OPEN) {
|
|
310
|
+
platformWs.send(message);
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
// 如果连接已关闭,删除该平台客户端
|
|
314
|
+
platformClient.delete(platformId);
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
// 处理关闭事件
|
|
320
|
+
ws.on('close', () => {
|
|
321
|
+
fullClient.delete(originId);
|
|
322
|
+
logger.debug({
|
|
323
|
+
code: ResultCode.Fail,
|
|
324
|
+
message: `Client ${originId} disconnected`,
|
|
325
|
+
data: null
|
|
326
|
+
});
|
|
327
|
+
});
|
|
165
328
|
};
|
|
166
|
-
//
|
|
167
|
-
|
|
168
|
-
//
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
// 重新进行绑定
|
|
184
|
-
reBind();
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
clientWs.send(message);
|
|
188
|
-
};
|
|
189
|
-
// 得到平台客户端的消息
|
|
190
|
-
ws.on('message', (message) => {
|
|
191
|
-
try {
|
|
192
|
-
// 解析消息
|
|
193
|
-
const parsedMessage = flattedJSON.parse(message.toString());
|
|
194
|
-
// 1. 解析得到 actionId ,说明是消费行为请求。要广播告诉所有客户端。
|
|
195
|
-
// 2. 解析得到 name ,说明是一个事件请求。
|
|
196
|
-
// 3. 解析得到 apiId ,说明是一个接口请求。
|
|
197
|
-
// 4. 解析得到 testID ,说明是一个测试请求。
|
|
329
|
+
// 处理客户端连接
|
|
330
|
+
global.chatbotServer.on('connection', (ws, request) => {
|
|
331
|
+
// 测试平台的连接
|
|
332
|
+
if (request.url === '/testone') {
|
|
333
|
+
connectionTestOne(ws, request);
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
// 读取请求头中的 来源
|
|
337
|
+
const headers = request.headers;
|
|
338
|
+
const origin = headers[USER_AGENT_HEADER] || USER_AGENT_HEADER_VALUE_MAP.client;
|
|
339
|
+
// 来源id
|
|
340
|
+
const originId = headers[DEVICE_ID_HEADER];
|
|
341
|
+
if (!originId) {
|
|
342
|
+
// 如果没有来源 ID,拒绝连接
|
|
343
|
+
ws.close(4000, 'Missing Device ID');
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
198
346
|
logger.debug({
|
|
199
347
|
code: ResultCode.Ok,
|
|
200
|
-
message:
|
|
201
|
-
data:
|
|
348
|
+
message: `Client ${originId} connected`,
|
|
349
|
+
data: null
|
|
202
350
|
});
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
}
|
|
208
|
-
else if (parsedMessage?.actionId) {
|
|
209
|
-
// 指定的设备 处理消费。终端有记录每个客户端是谁
|
|
210
|
-
const DeviceId = parsedMessage.DeviceId;
|
|
211
|
-
handleAction(DeviceId, message);
|
|
351
|
+
// 根据来源进行分类
|
|
352
|
+
if (origin === USER_AGENT_HEADER_VALUE_MAP.platform) {
|
|
353
|
+
setPlatformClient(originId, ws);
|
|
354
|
+
return;
|
|
212
355
|
}
|
|
213
|
-
else if (
|
|
214
|
-
|
|
215
|
-
|
|
356
|
+
else if (origin === USER_AGENT_HEADER_VALUE_MAP.client) {
|
|
357
|
+
// 连接时,需要给客户端发送主动消息
|
|
358
|
+
ws.send(flattedJSON.stringify({
|
|
359
|
+
active: 'sync',
|
|
360
|
+
payload: {
|
|
361
|
+
value: getConfig().value,
|
|
362
|
+
args: getConfig().argv,
|
|
363
|
+
package: {
|
|
364
|
+
version: getConfig().package?.version
|
|
365
|
+
},
|
|
366
|
+
env: {
|
|
367
|
+
login: process.env.login,
|
|
368
|
+
platform: process.env.platform,
|
|
369
|
+
port: process.env.port
|
|
370
|
+
}
|
|
371
|
+
},
|
|
372
|
+
// 主动消息
|
|
373
|
+
activeId: originId
|
|
374
|
+
}));
|
|
216
375
|
}
|
|
217
|
-
|
|
218
|
-
|
|
376
|
+
const isFullReceive = headers[FULL_RECEIVE_HEADER] === '1';
|
|
377
|
+
// 如果是全量接收
|
|
378
|
+
if (isFullReceive) {
|
|
379
|
+
setFullClient(originId, ws);
|
|
380
|
+
return;
|
|
219
381
|
}
|
|
220
|
-
|
|
221
|
-
catch (error) {
|
|
222
|
-
logger.error({
|
|
223
|
-
code: ResultCode.Fail,
|
|
224
|
-
message: '服务端解析平台消息失败',
|
|
225
|
-
data: error
|
|
226
|
-
});
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
});
|
|
230
|
-
// 处理关闭事件
|
|
231
|
-
ws.on('close', () => {
|
|
232
|
-
delete platformClient[originId];
|
|
233
|
-
logger.debug({
|
|
234
|
-
code: ResultCode.Fail,
|
|
235
|
-
message: `Client ${originId} disconnected`,
|
|
236
|
-
data: null
|
|
382
|
+
setChildrenClient(originId, ws);
|
|
237
383
|
});
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
384
|
+
chatbotServer.on('error', (err) => {
|
|
385
|
+
// 清理所有客户端连接
|
|
386
|
+
platformClient.clear();
|
|
387
|
+
childrenClient.clear();
|
|
388
|
+
fullClient.clear();
|
|
389
|
+
// 发现是端口已经被占用
|
|
390
|
+
if (err.code === 'EADDRINUSE') {
|
|
391
|
+
logger.error({
|
|
392
|
+
code: ResultCode.FailInternal,
|
|
393
|
+
message: `端口 ${port} 已被占用,请检查是否有其他服务在运行`,
|
|
394
|
+
data: err.message
|
|
395
|
+
});
|
|
396
|
+
const reCreateTime = getReConnectTime();
|
|
397
|
+
// 清理所有客户端连接,开始重新创建服务器
|
|
398
|
+
setTimeout(() => {
|
|
399
|
+
createServer();
|
|
400
|
+
}, reCreateTime);
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
logger.error({
|
|
404
|
+
code: ResultCode.FailInternal,
|
|
405
|
+
message: 'WebSocket server error',
|
|
406
|
+
data: err.message || 'Unknown error'
|
|
407
|
+
});
|
|
408
|
+
}
|
|
244
409
|
});
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
// 得到子客户端的消息。只会是actions请求。
|
|
251
|
-
ws.on('message', (message) => {
|
|
252
|
-
// tudo
|
|
253
|
-
// 为什么 子客户端的行为,不携带目标平台的 DeviceId?
|
|
254
|
-
// 导致无法进行多个平台连接。
|
|
255
|
-
if (platformClient.size > 0) {
|
|
256
|
-
platformClient.forEach(platformWs => {
|
|
257
|
-
// 检查平台客户端状态
|
|
258
|
-
if (platformWs.readyState === WebSocket.OPEN) {
|
|
259
|
-
platformWs.send(message);
|
|
260
|
-
}
|
|
261
|
-
else {
|
|
262
|
-
// 如果连接已关闭,删除该平台客户端
|
|
263
|
-
platformClient.delete(originId);
|
|
264
|
-
}
|
|
410
|
+
chatbotServer.on('close', () => {
|
|
411
|
+
logger.info({
|
|
412
|
+
code: ResultCode.Ok,
|
|
413
|
+
message: 'WebSocket server closed',
|
|
414
|
+
data: null
|
|
265
415
|
});
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
delete childrenClient[originId];
|
|
271
|
-
logger.debug({
|
|
272
|
-
code: ResultCode.Fail,
|
|
273
|
-
message: `Client ${originId} disconnected`,
|
|
274
|
-
data: null
|
|
416
|
+
// 清理所有客户端连接
|
|
417
|
+
platformClient.clear();
|
|
418
|
+
childrenClient.clear();
|
|
419
|
+
fullClient.clear();
|
|
275
420
|
});
|
|
276
|
-
}
|
|
277
|
-
|
|
421
|
+
}
|
|
422
|
+
catch (error) {
|
|
278
423
|
logger.error({
|
|
279
|
-
code: ResultCode.
|
|
280
|
-
message:
|
|
281
|
-
data:
|
|
282
|
-
});
|
|
283
|
-
});
|
|
284
|
-
};
|
|
285
|
-
// 全量客户端
|
|
286
|
-
const setFullClient = (originId, ws) => {
|
|
287
|
-
fullClient.set(originId, ws);
|
|
288
|
-
// 处理消息事件
|
|
289
|
-
ws.on('message', (message) => {
|
|
290
|
-
// tudo
|
|
291
|
-
// 为什么 子客户端的行为,不携带目标平台的 DeviceId?
|
|
292
|
-
// 导致无法进行多个平台连接。
|
|
293
|
-
if (platformClient.size > 0) {
|
|
294
|
-
platformClient.forEach(platformWs => {
|
|
295
|
-
// 检查平台客户端状态
|
|
296
|
-
if (platformWs.readyState === WebSocket.OPEN) {
|
|
297
|
-
platformWs.send(message);
|
|
298
|
-
}
|
|
299
|
-
else {
|
|
300
|
-
// 如果连接已关闭,删除该平台客户端
|
|
301
|
-
platformClient.delete(originId);
|
|
302
|
-
}
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
|
-
});
|
|
306
|
-
// 处理关闭事件
|
|
307
|
-
ws.on('close', () => {
|
|
308
|
-
delete fullClient[originId];
|
|
309
|
-
logger.debug({
|
|
310
|
-
code: ResultCode.Fail,
|
|
311
|
-
message: `Client ${originId} disconnected`,
|
|
312
|
-
data: null
|
|
424
|
+
code: ResultCode.FailInternal,
|
|
425
|
+
message: '创建 CBP 服务器失败',
|
|
426
|
+
data: error
|
|
313
427
|
});
|
|
314
|
-
});
|
|
315
|
-
};
|
|
316
|
-
// 处理客户端连接
|
|
317
|
-
global.chatbotServer.on('connection', (ws, request) => {
|
|
318
|
-
// 测试平台的连接
|
|
319
|
-
if (request.url === '/testone') {
|
|
320
|
-
connectionTestOne(ws);
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
// 读取请求头中的 来源
|
|
324
|
-
const headers = request.headers;
|
|
325
|
-
const origin = headers[USER_AGENT_HEADER] || USER_AGENT_HEADER_VALUE_MAP.client;
|
|
326
|
-
// 来源id
|
|
327
|
-
const originId = headers[DEVICE_ID_HEADER];
|
|
328
|
-
if (!originId) {
|
|
329
|
-
// 如果没有来源 ID,拒绝连接
|
|
330
|
-
ws.close(4000, 'Missing Device ID');
|
|
331
|
-
return;
|
|
332
|
-
}
|
|
333
|
-
logger.debug({
|
|
334
|
-
code: ResultCode.Ok,
|
|
335
|
-
message: `Client ${originId} connected`,
|
|
336
|
-
data: null
|
|
337
|
-
});
|
|
338
|
-
// 根据来源进行分类
|
|
339
|
-
if (origin === USER_AGENT_HEADER_VALUE_MAP.platform) {
|
|
340
|
-
setPlatformClient(originId, ws);
|
|
341
428
|
return;
|
|
342
429
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
ws.send(flattedJSON.stringify({
|
|
346
|
-
active: 'sync',
|
|
347
|
-
payload: {
|
|
348
|
-
value: getConfig().value,
|
|
349
|
-
args: getConfig().argv,
|
|
350
|
-
package: {
|
|
351
|
-
version: getConfig().package?.version
|
|
352
|
-
},
|
|
353
|
-
env: {
|
|
354
|
-
login: process.env.login,
|
|
355
|
-
platform: process.env.platform,
|
|
356
|
-
port: process.env.port
|
|
357
|
-
}
|
|
358
|
-
},
|
|
359
|
-
// 主动消息
|
|
360
|
-
activeId: originId
|
|
361
|
-
}));
|
|
362
|
-
}
|
|
363
|
-
const isFullReceive = headers[FULL_RECEIVE_HEADER] === '1';
|
|
364
|
-
// 如果是全量接收
|
|
365
|
-
if (isFullReceive) {
|
|
366
|
-
setFullClient(originId, ws);
|
|
367
|
-
return;
|
|
368
|
-
}
|
|
369
|
-
setChildrenClient(originId, ws);
|
|
370
|
-
});
|
|
430
|
+
};
|
|
431
|
+
createServer();
|
|
371
432
|
};
|
|
372
433
|
|
|
373
434
|
export { cbpServer };
|
package/lib/cbp/router.js
CHANGED
|
@@ -3,11 +3,12 @@ import KoaRouter from 'koa-router';
|
|
|
3
3
|
const router = new KoaRouter({
|
|
4
4
|
prefix: '/'
|
|
5
5
|
});
|
|
6
|
-
//
|
|
7
|
-
router.get('/
|
|
6
|
+
// 响应服务在线
|
|
7
|
+
router.get('/online', ctx => {
|
|
8
|
+
ctx.status = 200;
|
|
8
9
|
ctx.body = {
|
|
9
10
|
code: 200,
|
|
10
|
-
message: '
|
|
11
|
+
message: 'service online',
|
|
11
12
|
data: null
|
|
12
13
|
};
|
|
13
14
|
});
|