alemonjs 2.1.0-alpha.26 → 2.1.0-alpha.28
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/actions.js +16 -5
- package/lib/cbp/api.js +16 -5
- package/lib/cbp/client.d.ts +10 -0
- package/lib/cbp/client.js +159 -0
- package/lib/cbp/config.js +1 -1
- package/lib/cbp/connect.js +2 -311
- package/lib/cbp/platform.d.ts +19 -0
- package/lib/cbp/platform.js +170 -0
- package/lib/cbp/router.js +1 -1
- package/lib/cbp/server.d.ts +8 -0
- package/lib/cbp/server.js +451 -0
- package/lib/cbp/testone.js +284 -6
- package/lib/cbp/typings.d.ts +13 -0
- package/lib/index.d.ts +3 -1
- package/lib/index.js +3 -1
- package/lib/main.js +7 -2
- package/lib/typing/actions.d.ts +53 -2
- package/package.json +1 -1
package/lib/cbp/actions.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ResultCode } from '../core/code.js';
|
|
2
2
|
import { createResult } from '../core/utils.js';
|
|
3
|
-
import { generateUniqueId,
|
|
3
|
+
import { generateUniqueId, deviceId, actionResolves, actionTimeouts, timeoutTime } from './config.js';
|
|
4
4
|
import * as flattedJSON from 'flatted';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -10,14 +10,24 @@ import * as flattedJSON from 'flatted';
|
|
|
10
10
|
const sendAction = (data) => {
|
|
11
11
|
const actionId = generateUniqueId();
|
|
12
12
|
return new Promise(resolve => {
|
|
13
|
-
actionResolves.set(actionId, resolve);
|
|
14
13
|
// 设置唯一标识符
|
|
15
14
|
data.actionId = actionId;
|
|
16
15
|
// 设置设备 ID
|
|
17
16
|
data.DeviceId = deviceId;
|
|
18
|
-
//
|
|
19
|
-
global.
|
|
20
|
-
|
|
17
|
+
// 沙盒模式
|
|
18
|
+
if (global.sandbox) {
|
|
19
|
+
if (!global.testoneClient) {
|
|
20
|
+
return resolve([createResult(ResultCode.Fail, '未连接到客户端', null)]);
|
|
21
|
+
}
|
|
22
|
+
// 发送消息
|
|
23
|
+
global.testoneClient.send(flattedJSON.stringify(data));
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
global.chatbotClient.send(flattedJSON.stringify(data));
|
|
27
|
+
}
|
|
28
|
+
// 设置回调函数
|
|
29
|
+
actionResolves.set(actionId, resolve);
|
|
30
|
+
// 超时
|
|
21
31
|
const timeout = setTimeout(() => {
|
|
22
32
|
// 被清理了
|
|
23
33
|
if (!actionResolves.has(actionId) || !actionTimeouts.has(actionId)) {
|
|
@@ -30,6 +40,7 @@ const sendAction = (data) => {
|
|
|
30
40
|
// 不会当错误进行处理。而是传入错误码
|
|
31
41
|
resolve([createResult(ResultCode.Fail, '行为超时', null)]);
|
|
32
42
|
}, timeoutTime);
|
|
43
|
+
// 设置超时
|
|
33
44
|
actionTimeouts.set(actionId, timeout);
|
|
34
45
|
});
|
|
35
46
|
};
|
package/lib/cbp/api.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ResultCode } from '../core/code.js';
|
|
2
2
|
import { createResult } from '../core/utils.js';
|
|
3
|
-
import { generateUniqueId,
|
|
3
|
+
import { generateUniqueId, deviceId, apiResolves, apiTimeouts, timeoutTime } from './config.js';
|
|
4
4
|
import * as flattedJSON from 'flatted';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -10,14 +10,24 @@ import * as flattedJSON from 'flatted';
|
|
|
10
10
|
const sendAPI = (data) => {
|
|
11
11
|
const ApiId = generateUniqueId();
|
|
12
12
|
return new Promise(resolve => {
|
|
13
|
-
apiResolves.set(ApiId, resolve);
|
|
14
13
|
// 设置唯一标识符
|
|
15
14
|
data.apiId = ApiId;
|
|
16
15
|
// 设置设备 ID
|
|
17
16
|
data.DeviceId = deviceId;
|
|
18
|
-
//
|
|
19
|
-
global.
|
|
20
|
-
|
|
17
|
+
// 沙盒模式
|
|
18
|
+
if (global.sandbox) {
|
|
19
|
+
if (!global.testoneClient) {
|
|
20
|
+
return resolve([createResult(ResultCode.Fail, '未连接到客户端', null)]);
|
|
21
|
+
}
|
|
22
|
+
// 发送消息
|
|
23
|
+
global.testoneClient.send(flattedJSON.stringify(data));
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
// 发送消息
|
|
27
|
+
global.chatbotClient.send(flattedJSON.stringify(data));
|
|
28
|
+
}
|
|
29
|
+
apiResolves.set(ApiId, resolve);
|
|
30
|
+
// 超时
|
|
21
31
|
const timeout = setTimeout(() => {
|
|
22
32
|
// 被清理了
|
|
23
33
|
if (!apiResolves.has(ApiId) || !apiTimeouts.has(ApiId)) {
|
|
@@ -30,6 +40,7 @@ const sendAPI = (data) => {
|
|
|
30
40
|
// 不会当错误进行处理。而是传入错误码
|
|
31
41
|
resolve([createResult(ResultCode.Fail, '接口超时', null)]);
|
|
32
42
|
}, timeoutTime);
|
|
43
|
+
// 设置超时
|
|
33
44
|
apiTimeouts.set(ApiId, timeout);
|
|
34
45
|
});
|
|
35
46
|
};
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { WebSocket } from 'ws';
|
|
2
|
+
import { onProcessor } from '../app/event-processor.js';
|
|
3
|
+
import { ResultCode } from '../core/code.js';
|
|
4
|
+
import { deviceId, FULL_RECEIVE_HEADER, DEVICE_ID_HEADER, USER_AGENT_HEADER, apiResolves, apiTimeouts, actionResolves, actionTimeouts, reconnectInterval } from './config.js';
|
|
5
|
+
import { createResult } from '../core/utils.js';
|
|
6
|
+
import * as flattedJSON from 'flatted';
|
|
7
|
+
import { useHeartbeat } from './connect.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* CBP 客户端
|
|
11
|
+
* @param url
|
|
12
|
+
* @param onopen
|
|
13
|
+
*/
|
|
14
|
+
const cbpClient = (url, options = {}) => {
|
|
15
|
+
/**
|
|
16
|
+
* 纯 cbpClient 连接,会没有 一些 全局变量。
|
|
17
|
+
* 需要在此处进行判断并设置
|
|
18
|
+
*/
|
|
19
|
+
if (global.chatbotClient) {
|
|
20
|
+
delete global.chatbotClient;
|
|
21
|
+
}
|
|
22
|
+
const { open = () => { }, isFullReceive = true } = options;
|
|
23
|
+
const [heartbeatControl] = useHeartbeat({
|
|
24
|
+
ping: () => {
|
|
25
|
+
global?.chatbotClient?.ping?.();
|
|
26
|
+
},
|
|
27
|
+
isConnected: () => {
|
|
28
|
+
return global?.chatbotClient && global?.chatbotClient?.readyState === WebSocket.OPEN;
|
|
29
|
+
},
|
|
30
|
+
terminate: () => {
|
|
31
|
+
try {
|
|
32
|
+
// 强制断开连接
|
|
33
|
+
global?.chatbotClient?.terminate?.();
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
logger.debug({
|
|
37
|
+
code: ResultCode.Fail,
|
|
38
|
+
message: '强制断开连接失败',
|
|
39
|
+
data: error
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
const start = () => {
|
|
45
|
+
global.chatbotClient = new WebSocket(url, {
|
|
46
|
+
headers: {
|
|
47
|
+
[USER_AGENT_HEADER]: 'client',
|
|
48
|
+
[DEVICE_ID_HEADER]: deviceId,
|
|
49
|
+
[FULL_RECEIVE_HEADER]: isFullReceive ? '1' : '0'
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
global.chatbotClient.on('open', () => {
|
|
53
|
+
open();
|
|
54
|
+
heartbeatControl.start(); // 启动心跳
|
|
55
|
+
});
|
|
56
|
+
global.chatbotClient.on('pong', () => {
|
|
57
|
+
heartbeatControl.pong(); // 更新 pong 时间
|
|
58
|
+
});
|
|
59
|
+
// 客户端接收,被标准化的平台消息
|
|
60
|
+
global.chatbotClient.on('message', message => {
|
|
61
|
+
try {
|
|
62
|
+
// 解析消息
|
|
63
|
+
const parsedMessage = flattedJSON.parse(message.toString());
|
|
64
|
+
logger.debug({
|
|
65
|
+
code: ResultCode.Ok,
|
|
66
|
+
message: '客户端接收到消息',
|
|
67
|
+
data: parsedMessage
|
|
68
|
+
});
|
|
69
|
+
if (parsedMessage?.activeId) {
|
|
70
|
+
// 主端端主动消息。
|
|
71
|
+
if (parsedMessage.active === 'sync') {
|
|
72
|
+
const configs = parsedMessage.payload;
|
|
73
|
+
// env 同步
|
|
74
|
+
const env = configs.env || {};
|
|
75
|
+
for (const key in env) {
|
|
76
|
+
process.env[key] = env[key];
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else if (parsedMessage?.apiId) {
|
|
81
|
+
// 如果有 apiId,说明是一个接口请求。要进行处理
|
|
82
|
+
const resolve = apiResolves.get(parsedMessage.apiId);
|
|
83
|
+
if (resolve) {
|
|
84
|
+
apiResolves.delete(parsedMessage.apiId);
|
|
85
|
+
// 清除超时器
|
|
86
|
+
const timeout = apiTimeouts.get(parsedMessage.apiId);
|
|
87
|
+
if (timeout) {
|
|
88
|
+
apiTimeouts.delete(parsedMessage.apiId);
|
|
89
|
+
clearTimeout(timeout);
|
|
90
|
+
}
|
|
91
|
+
// 调用回调函数
|
|
92
|
+
if (Array.isArray(parsedMessage.payload)) {
|
|
93
|
+
resolve(parsedMessage.payload);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
// 错误处理
|
|
97
|
+
resolve([createResult(ResultCode.Fail, '接口处理错误', null)]);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
else if (parsedMessage?.actionId) {
|
|
102
|
+
// 如果有 actionId
|
|
103
|
+
const resolve = actionResolves.get(parsedMessage.actionId);
|
|
104
|
+
if (resolve) {
|
|
105
|
+
actionResolves.delete(parsedMessage.actionId);
|
|
106
|
+
// 清除超时器
|
|
107
|
+
const timeout = actionTimeouts.get(parsedMessage.actionId);
|
|
108
|
+
if (timeout) {
|
|
109
|
+
actionTimeouts.delete(parsedMessage.actionId);
|
|
110
|
+
clearTimeout(timeout);
|
|
111
|
+
}
|
|
112
|
+
// 调用回调函数
|
|
113
|
+
if (Array.isArray(parsedMessage.payload)) {
|
|
114
|
+
resolve(parsedMessage.payload);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
// 错误处理
|
|
118
|
+
resolve([createResult(ResultCode.Fail, '消费处理错误', null)]);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
else if (parsedMessage.name) {
|
|
123
|
+
// 如果有 name,说明是一个事件请求。要进行处理
|
|
124
|
+
onProcessor(parsedMessage.name, parsedMessage, parsedMessage.value);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
logger.error({
|
|
129
|
+
code: ResultCode.Fail,
|
|
130
|
+
message: '客户端解析消息失败',
|
|
131
|
+
data: error
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
global.chatbotClient.on('close', () => {
|
|
136
|
+
heartbeatControl.stop(); // 停止心跳
|
|
137
|
+
logger.warn({
|
|
138
|
+
code: ResultCode.Fail,
|
|
139
|
+
message: '连接关闭,尝试重新连接...',
|
|
140
|
+
data: null
|
|
141
|
+
});
|
|
142
|
+
delete global.chatbotClient;
|
|
143
|
+
// 重新连接逻辑
|
|
144
|
+
setTimeout(() => {
|
|
145
|
+
start(); // 重新连接
|
|
146
|
+
}, reconnectInterval); // 6秒后重连
|
|
147
|
+
});
|
|
148
|
+
global.chatbotClient.on('error', err => {
|
|
149
|
+
logger.error({
|
|
150
|
+
code: ResultCode.Fail,
|
|
151
|
+
message: '客户端错误',
|
|
152
|
+
data: err
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
};
|
|
156
|
+
start();
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
export { cbpClient };
|
package/lib/cbp/config.js
CHANGED
|
@@ -34,7 +34,7 @@ const generateUniqueId = () => {
|
|
|
34
34
|
return Date.now().toString(36) + Math.random().toString(36).substring(2);
|
|
35
35
|
};
|
|
36
36
|
// 超时时间
|
|
37
|
-
const timeoutTime = 1000 *
|
|
37
|
+
const timeoutTime = 1000 * 60 * 3; // 3分钟
|
|
38
38
|
// 失败重连
|
|
39
39
|
const reconnectInterval = 1000 * 6; // 6秒
|
|
40
40
|
// 心跳间隔
|
package/lib/cbp/connect.js
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import { WebSocket } from 'ws';
|
|
2
|
-
import { onProcessor } from '../app/event-processor.js';
|
|
3
1
|
import { ResultCode } from '../core/code.js';
|
|
4
|
-
import {
|
|
5
|
-
import { createResult } from '../core/utils.js';
|
|
6
|
-
import * as flattedJSON from 'flatted';
|
|
2
|
+
import { HEARTBEAT_INTERVAL } from './config.js';
|
|
7
3
|
|
|
8
4
|
// 心跳
|
|
9
5
|
const useHeartbeat = ({ ping, isConnected, terminate }) => {
|
|
@@ -62,310 +58,5 @@ const useHeartbeat = ({ ping, isConnected, terminate }) => {
|
|
|
62
58
|
};
|
|
63
59
|
return [control];
|
|
64
60
|
};
|
|
65
|
-
/**
|
|
66
|
-
* CBP 客户端
|
|
67
|
-
* @param url
|
|
68
|
-
* @param onopen
|
|
69
|
-
*/
|
|
70
|
-
const cbpClient = (url, options = {}) => {
|
|
71
|
-
/**
|
|
72
|
-
* 纯 cbpClient 连接,会没有 一些 全局变量。
|
|
73
|
-
* 需要在此处进行判断并设置
|
|
74
|
-
*/
|
|
75
|
-
if (!global.chatbotClient) {
|
|
76
|
-
delete global.chatbotClient;
|
|
77
|
-
}
|
|
78
|
-
const { open = () => { }, isFullReceive = true } = options;
|
|
79
|
-
const [heartbeatControl] = useHeartbeat({
|
|
80
|
-
ping: () => {
|
|
81
|
-
global?.chatbotClient?.ping?.();
|
|
82
|
-
},
|
|
83
|
-
isConnected: () => {
|
|
84
|
-
return global?.chatbotClient && global?.chatbotClient?.readyState === WebSocket.OPEN;
|
|
85
|
-
},
|
|
86
|
-
terminate: () => {
|
|
87
|
-
try {
|
|
88
|
-
// 强制断开连接
|
|
89
|
-
global?.chatbotClient?.terminate?.();
|
|
90
|
-
}
|
|
91
|
-
catch (error) {
|
|
92
|
-
logger.debug({
|
|
93
|
-
code: ResultCode.Fail,
|
|
94
|
-
message: '强制断开连接失败',
|
|
95
|
-
data: error
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
const start = () => {
|
|
101
|
-
global.chatbotClient = new WebSocket(url, {
|
|
102
|
-
headers: {
|
|
103
|
-
[USER_AGENT_HEADER]: 'client',
|
|
104
|
-
[DEVICE_ID_HEADER]: deviceId,
|
|
105
|
-
[FULL_RECEIVE_HEADER]: isFullReceive ? '1' : '0'
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
global.chatbotClient.on('open', () => {
|
|
109
|
-
open();
|
|
110
|
-
heartbeatControl.start(); // 启动心跳
|
|
111
|
-
});
|
|
112
|
-
global.chatbotClient.on('pong', () => {
|
|
113
|
-
heartbeatControl.pong(); // 更新 pong 时间
|
|
114
|
-
});
|
|
115
|
-
// 客户端接收,被标准化的平台消息
|
|
116
|
-
global.chatbotClient.on('message', message => {
|
|
117
|
-
try {
|
|
118
|
-
// 解析消息
|
|
119
|
-
const parsedMessage = flattedJSON.parse(message.toString());
|
|
120
|
-
logger.debug({
|
|
121
|
-
code: ResultCode.Ok,
|
|
122
|
-
message: '客户端接收到消息',
|
|
123
|
-
data: parsedMessage
|
|
124
|
-
});
|
|
125
|
-
if (parsedMessage?.activeId) {
|
|
126
|
-
// 主端端主动消息。
|
|
127
|
-
if (parsedMessage.active === 'sync') {
|
|
128
|
-
const configs = parsedMessage.payload;
|
|
129
|
-
// env 同步
|
|
130
|
-
const env = configs.env || {};
|
|
131
|
-
for (const key in env) {
|
|
132
|
-
process.env[key] = env[key];
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
else if (parsedMessage?.apiId) {
|
|
137
|
-
// 如果有 apiId,说明是一个接口请求。要进行处理
|
|
138
|
-
const resolve = apiResolves.get(parsedMessage.apiId);
|
|
139
|
-
if (resolve) {
|
|
140
|
-
apiResolves.delete(parsedMessage.apiId);
|
|
141
|
-
// 清除超时器
|
|
142
|
-
const timeout = apiTimeouts.get(parsedMessage.apiId);
|
|
143
|
-
if (timeout) {
|
|
144
|
-
apiTimeouts.delete(parsedMessage.apiId);
|
|
145
|
-
clearTimeout(timeout);
|
|
146
|
-
}
|
|
147
|
-
// 调用回调函数
|
|
148
|
-
if (Array.isArray(parsedMessage.payload)) {
|
|
149
|
-
resolve(parsedMessage.payload);
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
// 错误处理
|
|
153
|
-
resolve([createResult(ResultCode.Fail, '接口处理错误', null)]);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
else if (parsedMessage?.actionId) {
|
|
158
|
-
// 如果有 actionId
|
|
159
|
-
const resolve = actionResolves.get(parsedMessage.actionId);
|
|
160
|
-
if (resolve) {
|
|
161
|
-
actionResolves.delete(parsedMessage.actionId);
|
|
162
|
-
// 清除超时器
|
|
163
|
-
const timeout = actionTimeouts.get(parsedMessage.actionId);
|
|
164
|
-
if (timeout) {
|
|
165
|
-
actionTimeouts.delete(parsedMessage.actionId);
|
|
166
|
-
clearTimeout(timeout);
|
|
167
|
-
}
|
|
168
|
-
// 调用回调函数
|
|
169
|
-
if (Array.isArray(parsedMessage.payload)) {
|
|
170
|
-
resolve(parsedMessage.payload);
|
|
171
|
-
}
|
|
172
|
-
else {
|
|
173
|
-
// 错误处理
|
|
174
|
-
resolve([createResult(ResultCode.Fail, '消费处理错误', null)]);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
else if (parsedMessage.name) {
|
|
179
|
-
// 如果有 name,说明是一个事件请求。要进行处理
|
|
180
|
-
onProcessor(parsedMessage.name, parsedMessage, parsedMessage.value);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
catch (error) {
|
|
184
|
-
logger.error({
|
|
185
|
-
code: ResultCode.Fail,
|
|
186
|
-
message: '客户端解析消息失败',
|
|
187
|
-
data: error
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
});
|
|
191
|
-
global.chatbotClient.on('close', () => {
|
|
192
|
-
heartbeatControl.stop(); // 停止心跳
|
|
193
|
-
logger.warn({
|
|
194
|
-
code: ResultCode.Fail,
|
|
195
|
-
message: '连接关闭,尝试重新连接...',
|
|
196
|
-
data: null
|
|
197
|
-
});
|
|
198
|
-
delete global.chatbotClient;
|
|
199
|
-
// 重新连接逻辑
|
|
200
|
-
setTimeout(() => {
|
|
201
|
-
start(); // 重新连接
|
|
202
|
-
}, reconnectInterval); // 6秒后重连
|
|
203
|
-
});
|
|
204
|
-
global.chatbotClient.on('error', err => {
|
|
205
|
-
logger.error({
|
|
206
|
-
code: ResultCode.Fail,
|
|
207
|
-
message: '客户端错误',
|
|
208
|
-
data: err
|
|
209
|
-
});
|
|
210
|
-
});
|
|
211
|
-
};
|
|
212
|
-
start();
|
|
213
|
-
};
|
|
214
|
-
const cbpPlatform = (url, options = {
|
|
215
|
-
open: () => { }
|
|
216
|
-
}) => {
|
|
217
|
-
if (!global.chatbotPlatform) {
|
|
218
|
-
delete global.chatbotPlatform;
|
|
219
|
-
}
|
|
220
|
-
const { open = () => { } } = options;
|
|
221
|
-
const [heartbeatControl] = useHeartbeat({
|
|
222
|
-
ping: () => {
|
|
223
|
-
global?.chatbotPlatform?.ping?.();
|
|
224
|
-
},
|
|
225
|
-
isConnected: () => {
|
|
226
|
-
return global?.chatbotPlatform && global?.chatbotPlatform?.readyState === WebSocket.OPEN;
|
|
227
|
-
},
|
|
228
|
-
terminate: () => {
|
|
229
|
-
try {
|
|
230
|
-
global?.chatbotPlatform?.terminate?.();
|
|
231
|
-
}
|
|
232
|
-
catch (error) {
|
|
233
|
-
logger.debug({
|
|
234
|
-
code: ResultCode.Fail,
|
|
235
|
-
message: '强制断开连接失败',
|
|
236
|
-
data: error
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
});
|
|
241
|
-
/**
|
|
242
|
-
* 发送数据
|
|
243
|
-
* @param data
|
|
244
|
-
*/
|
|
245
|
-
const send = (data) => {
|
|
246
|
-
if (global.chatbotPlatform && global.chatbotPlatform.readyState === WebSocket.OPEN) {
|
|
247
|
-
data.DeviceId = deviceId; // 设置设备 ID
|
|
248
|
-
global.chatbotPlatform.send(flattedJSON.stringify(data));
|
|
249
|
-
}
|
|
250
|
-
};
|
|
251
|
-
const actionReplys = [];
|
|
252
|
-
const apiReplys = [];
|
|
253
|
-
/**
|
|
254
|
-
* 消费数据
|
|
255
|
-
* @param data
|
|
256
|
-
* @param payload
|
|
257
|
-
*/
|
|
258
|
-
const replyAction = (data, payload) => {
|
|
259
|
-
if (global.chatbotPlatform && global.chatbotPlatform.readyState === WebSocket.OPEN) {
|
|
260
|
-
// 透传消费。也就是对应的设备进行处理消费。
|
|
261
|
-
global.chatbotPlatform.send(flattedJSON.stringify({
|
|
262
|
-
action: data.action,
|
|
263
|
-
payload: payload,
|
|
264
|
-
actionId: data.actionId,
|
|
265
|
-
DeviceId: data.DeviceId
|
|
266
|
-
}));
|
|
267
|
-
}
|
|
268
|
-
};
|
|
269
|
-
const replyApi = (data, payload) => {
|
|
270
|
-
if (global.chatbotPlatform && global.chatbotPlatform.readyState === WebSocket.OPEN) {
|
|
271
|
-
// 透传消费。也就是对应的设备进行处理消费。
|
|
272
|
-
global.chatbotPlatform.send(flattedJSON.stringify({
|
|
273
|
-
action: data.action,
|
|
274
|
-
apiId: data.apiId,
|
|
275
|
-
DeviceId: data.DeviceId,
|
|
276
|
-
payload: payload
|
|
277
|
-
}));
|
|
278
|
-
}
|
|
279
|
-
};
|
|
280
|
-
/**
|
|
281
|
-
* 接收行为
|
|
282
|
-
* @param reply
|
|
283
|
-
*/
|
|
284
|
-
const onactions = (reply) => {
|
|
285
|
-
actionReplys.push(reply);
|
|
286
|
-
};
|
|
287
|
-
/**
|
|
288
|
-
* 接收接口
|
|
289
|
-
*/
|
|
290
|
-
const onapis = (reply) => {
|
|
291
|
-
apiReplys.push(reply);
|
|
292
|
-
};
|
|
293
|
-
/**
|
|
294
|
-
* 启动 WebSocket 连接
|
|
295
|
-
*/
|
|
296
|
-
const start = () => {
|
|
297
|
-
global.chatbotPlatform = new WebSocket(url, {
|
|
298
|
-
headers: {
|
|
299
|
-
[USER_AGENT_HEADER]: 'platform',
|
|
300
|
-
[DEVICE_ID_HEADER]: deviceId
|
|
301
|
-
}
|
|
302
|
-
});
|
|
303
|
-
global.chatbotPlatform.on('open', () => {
|
|
304
|
-
open();
|
|
305
|
-
heartbeatControl.start(); // 启动心跳
|
|
306
|
-
});
|
|
307
|
-
global.chatbotPlatform.on('pong', () => {
|
|
308
|
-
heartbeatControl.pong(); // 更新 pong 时间
|
|
309
|
-
});
|
|
310
|
-
global.chatbotPlatform.on('message', message => {
|
|
311
|
-
try {
|
|
312
|
-
const data = flattedJSON.parse(message.toString());
|
|
313
|
-
logger.debug({
|
|
314
|
-
code: ResultCode.Ok,
|
|
315
|
-
message: '平台端接收消息',
|
|
316
|
-
data: data
|
|
317
|
-
});
|
|
318
|
-
if (data.apiId) {
|
|
319
|
-
for (const cb of apiReplys) {
|
|
320
|
-
cb(data,
|
|
321
|
-
// 传入一个消费函数
|
|
322
|
-
val => replyApi(data, val));
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
else if (data.actionId) {
|
|
326
|
-
for (const cb of actionReplys) {
|
|
327
|
-
cb(data,
|
|
328
|
-
// 传入一个消费函数
|
|
329
|
-
val => replyAction(data, val));
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
catch (error) {
|
|
334
|
-
logger.error({
|
|
335
|
-
code: ResultCode.Fail,
|
|
336
|
-
message: '解析消息失败',
|
|
337
|
-
data: error
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
});
|
|
341
|
-
global.chatbotPlatform.on('close', err => {
|
|
342
|
-
heartbeatControl.stop(); // 停止心跳
|
|
343
|
-
logger.warn({
|
|
344
|
-
code: ResultCode.Fail,
|
|
345
|
-
message: '平台端连接关闭,尝试重新连接...',
|
|
346
|
-
data: err
|
|
347
|
-
});
|
|
348
|
-
delete global.chatbotPlatform;
|
|
349
|
-
// 重新连接逻辑
|
|
350
|
-
setTimeout(() => {
|
|
351
|
-
start(); // 重新连接
|
|
352
|
-
}, reconnectInterval); // 6秒后重连
|
|
353
|
-
});
|
|
354
|
-
global.chatbotPlatform.on('error', err => {
|
|
355
|
-
logger.error({
|
|
356
|
-
code: ResultCode.Fail,
|
|
357
|
-
message: '平台端错误',
|
|
358
|
-
data: err
|
|
359
|
-
});
|
|
360
|
-
});
|
|
361
|
-
};
|
|
362
|
-
start();
|
|
363
|
-
const client = {
|
|
364
|
-
send,
|
|
365
|
-
onactions,
|
|
366
|
-
onapis
|
|
367
|
-
};
|
|
368
|
-
return client;
|
|
369
|
-
};
|
|
370
61
|
|
|
371
|
-
export {
|
|
62
|
+
export { useHeartbeat };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { EventsEnum } from '../typing/event/map.js';
|
|
2
|
+
import '../global.js';
|
|
3
|
+
import { ActionReplyFunc, ApiReplyFunc } from './typings.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* CBP 平台端
|
|
7
|
+
* @param url
|
|
8
|
+
* @param options
|
|
9
|
+
* @returns
|
|
10
|
+
*/
|
|
11
|
+
declare const cbpPlatform: (url: string, options?: {
|
|
12
|
+
open: () => void;
|
|
13
|
+
}) => {
|
|
14
|
+
send: (data: EventsEnum) => void;
|
|
15
|
+
onactions: (reply: ActionReplyFunc) => void;
|
|
16
|
+
onapis: (reply: ApiReplyFunc) => void;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export { cbpPlatform };
|