alemonjs 2.1.0-alpha.2 → 2.1.0-alpha.21

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.
Files changed (60) hide show
  1. package/README.md +85 -25
  2. package/lib/app/event-group.d.ts +11 -0
  3. package/lib/app/event-group.js +28 -0
  4. package/lib/app/event-middleware.d.ts +10 -2
  5. package/lib/app/event-middleware.js +11 -1
  6. package/lib/app/event-processor-event.js +1 -1
  7. package/lib/app/event-processor-middleware.js +1 -1
  8. package/lib/app/event-processor.js +1 -1
  9. package/lib/app/event-response.d.ts +10 -2
  10. package/lib/app/event-response.js +12 -1
  11. package/lib/app/hook-use-api.d.ts +19 -24
  12. package/lib/app/hook-use-api.js +136 -117
  13. package/lib/app/hook-use-subscribe.d.ts +20 -3
  14. package/lib/app/hook-use-subscribe.js +13 -1
  15. package/lib/app/load.js +10 -14
  16. package/lib/app/message-api.d.ts +28 -8
  17. package/lib/app/message-api.js +31 -14
  18. package/lib/app/message-format.d.ts +5 -12
  19. package/lib/app/message-format.js +16 -7
  20. package/lib/app/store.js +4 -3
  21. package/lib/cbp/actions.js +11 -7
  22. package/lib/cbp/api.js +37 -0
  23. package/lib/cbp/config.js +8 -2
  24. package/lib/cbp/connect.d.ts +6 -2
  25. package/lib/cbp/connect.js +213 -30
  26. package/lib/cbp/index.js +53 -6
  27. package/lib/{app → core}/utils.d.ts +2 -3
  28. package/lib/{app → core}/utils.js +3 -4
  29. package/lib/core/variable.js +7 -1
  30. package/lib/global.d.ts +18 -1
  31. package/lib/index.d.ts +11 -10
  32. package/lib/index.js +7 -7
  33. package/lib/main.js +6 -5
  34. package/lib/typing/actions.d.ts +1 -1
  35. package/lib/typing/apis.d.ts +18 -0
  36. package/lib/typing/client/index.d.ts +1 -1
  37. package/lib/typing/event/base/expansion.d.ts +5 -0
  38. package/lib/typing/event/base/guild.d.ts +4 -0
  39. package/lib/typing/event/base/user.d.ts +4 -0
  40. package/lib/typing/event/channal/index.d.ts +3 -2
  41. package/lib/typing/event/guild/index.d.ts +3 -2
  42. package/lib/typing/event/index.d.ts +13 -1
  43. package/lib/typing/event/interaction/index.d.ts +3 -2
  44. package/lib/typing/event/map.d.ts +0 -2
  45. package/lib/typing/event/member/index.d.ts +3 -2
  46. package/lib/typing/event/message/message.d.ts +6 -5
  47. package/lib/typing/event/message/private.message.d.ts +4 -3
  48. package/lib/typing/event/request/index.d.ts +3 -2
  49. package/lib/typing/message/button.d.ts +6 -5
  50. package/lib/typing/message/index.d.ts +4 -4
  51. package/lib/typing/message/markdown.d.ts +13 -3
  52. package/lib/utils.d.ts +80 -0
  53. package/lib/utils.js +203 -0
  54. package/package.json +12 -3
  55. package/lib/app/define-bot.d.ts +0 -17
  56. package/lib/app/define-bot.js +0 -39
  57. package/lib/cbp/index.d.ts +0 -32
  58. package/lib/cbp/message.js +0 -9
  59. package/lib/jsx.d.ts +0 -142
  60. package/lib/jsx.js +0 -234
package/lib/app/store.js CHANGED
@@ -15,6 +15,8 @@ import log4js from 'log4js';
15
15
  const createLogger = () => {
16
16
  const logDir = process.env?.LOG_PATH ?? `./logs/${process.env.LOG_NAME ?? ''}`;
17
17
  mkdirSync(logDir, { recursive: true });
18
+ // 当环境被设置为 development 时。被视为 trace
19
+ const level = process.env.NODE_ENV === 'development' ? 'trace' : 'info';
18
20
  log4js.configure({
19
21
  appenders: {
20
22
  console: {
@@ -48,13 +50,12 @@ const createLogger = () => {
48
50
  }
49
51
  },
50
52
  categories: {
51
- default: { appenders: ['console'], level: 'error' },
52
- // 记录级别
53
+ default: { appenders: ['console'], level: level },
53
54
  command: { appenders: ['console', 'command'], level: 'info' },
54
55
  error: { appenders: ['console', 'command', 'error'], level: 'warn' }
55
56
  }
56
57
  });
57
- const defaultLogger = log4js.getLogger('message');
58
+ const defaultLogger = log4js.getLogger('default');
58
59
  const commandLogger = log4js.getLogger('command');
59
60
  const errorLogger = log4js.getLogger('error');
60
61
  return {
@@ -1,6 +1,7 @@
1
1
  import { ResultCode } from '../core/code.js';
2
- import { createResult } from '../app/utils.js';
2
+ import { createResult } from '../core/utils.js';
3
3
  import { generateUniqueId, actionResolves, deviceId, actionTimeouts, timeoutTime } from './config.js';
4
+ import * as flattedJSON from 'flatted';
4
5
 
5
6
  /**
6
7
  * 发送行为
@@ -11,20 +12,23 @@ const sendAction = (data) => {
11
12
  return new Promise(resolve => {
12
13
  actionResolves.set(actionId, resolve);
13
14
  // 设置唯一标识符
14
- data.actionID = actionId;
15
+ data.actionId = actionId;
15
16
  // 设置设备 ID
16
17
  data.DeviceId = deviceId;
17
- global.chatbotClient.send(JSON.stringify(data));
18
+ // 发送消息
19
+ global.chatbotClient.send(flattedJSON.stringify(data));
18
20
  // 12 秒后超时
19
21
  const timeout = setTimeout(() => {
20
- // 不会当错误进行处理
21
- resolve(createResult(ResultCode.Fail, '请求超时', null));
22
- // 手动清理
23
- clearTimeout(timeout);
22
+ // 被清理了
23
+ if (!actionResolves.has(actionId) || !actionTimeouts.has(actionId)) {
24
+ return;
25
+ }
24
26
  // 删除回调
25
27
  actionResolves.delete(actionId);
26
28
  // 删除超时器
27
29
  actionTimeouts.delete(actionId);
30
+ // 不会当错误进行处理。而是传入错误码
31
+ resolve([createResult(ResultCode.Fail, '行为超时', null)]);
28
32
  }, timeoutTime);
29
33
  actionTimeouts.set(actionId, timeout);
30
34
  });
package/lib/cbp/api.js ADDED
@@ -0,0 +1,37 @@
1
+ import { ResultCode } from '../core/code.js';
2
+ import { createResult } from '../core/utils.js';
3
+ import { generateUniqueId, apiResolves, deviceId, apiTimeouts, timeoutTime } from './config.js';
4
+ import * as flattedJSON from 'flatted';
5
+
6
+ /**
7
+ * 发送行为
8
+ * @param data
9
+ */
10
+ const sendAPI = (data) => {
11
+ const ApiId = generateUniqueId();
12
+ return new Promise(resolve => {
13
+ apiResolves.set(ApiId, resolve);
14
+ // 设置唯一标识符
15
+ data.apiId = ApiId;
16
+ // 设置设备 ID
17
+ data.DeviceId = deviceId;
18
+ // 发送消息
19
+ global.chatbotClient.send(flattedJSON.stringify(data));
20
+ // 12 秒后超时
21
+ const timeout = setTimeout(() => {
22
+ // 被清理了
23
+ if (!apiResolves.has(ApiId) || !apiTimeouts.has(ApiId)) {
24
+ return;
25
+ }
26
+ // 删除回调
27
+ apiResolves.delete(ApiId);
28
+ // 删除超时器
29
+ apiTimeouts.delete(ApiId);
30
+ // 不会当错误进行处理。而是传入错误码
31
+ resolve([createResult(ResultCode.Fail, '接口超时', null)]);
32
+ }, timeoutTime);
33
+ apiTimeouts.set(ApiId, timeout);
34
+ });
35
+ };
36
+
37
+ export { sendAPI };
package/lib/cbp/config.js CHANGED
@@ -15,8 +15,12 @@ const DEVICE_ID_HEADER = 'x-device-id';
15
15
  const FULL_RECEIVE_HEADER = 'x-full-receive';
16
16
  // 行为回调
17
17
  const actionResolves = new Map();
18
+ // 接口回调
19
+ const apiResolves = new Map();
18
20
  // 超时器
19
21
  const actionTimeouts = new Map();
22
+ // 接口超时器
23
+ const apiTimeouts = new Map();
20
24
  // 分配绑定记录
21
25
  const childrenBind = new Map();
22
26
  // 生成唯一标识符
@@ -26,6 +30,8 @@ const generateUniqueId = () => {
26
30
  // 超时时间
27
31
  const timeoutTime = 1000 * 12; // 12秒
28
32
  // 失败重连
29
- const reconnectInterval = 6000; // 6秒
33
+ const reconnectInterval = 1000 * 6; // 6秒
34
+ // 心跳间隔
35
+ const HEARTBEAT_INTERVAL = 1000 * 18; // 18秒
30
36
 
31
- export { DEVICE_ID_HEADER, FULL_RECEIVE_HEADER, USER_AGENT_HEADER, actionResolves, actionTimeouts, childrenBind, childrenClient, deviceId, fullClient, generateUniqueId, platformClient, reconnectInterval, timeoutTime };
37
+ export { DEVICE_ID_HEADER, FULL_RECEIVE_HEADER, HEARTBEAT_INTERVAL, USER_AGENT_HEADER, actionResolves, actionTimeouts, apiResolves, apiTimeouts, childrenBind, childrenClient, deviceId, fullClient, generateUniqueId, platformClient, reconnectInterval, timeoutTime };
@@ -1,6 +1,8 @@
1
1
  import { Actions } from '../typing/actions.js';
2
2
  import { EventsEnum } from '../typing/event/map.js';
3
+ import { Result } from '../core/utils.js';
3
4
  import '../global.js';
5
+ import { Apis } from '../typing/apis.js';
4
6
 
5
7
  type CBPClientOptions = {
6
8
  open?: () => void;
@@ -12,12 +14,14 @@ type CBPClientOptions = {
12
14
  * @param onopen
13
15
  */
14
16
  declare const cbpClient: (url: string, options?: CBPClientOptions) => void;
15
- type ReplyFunc = (data: Actions, consume: (payload: any) => void) => void;
17
+ type ActionReplyFunc = (data: Actions, consume: (payload: Result[]) => void) => void;
18
+ type ApiReplyFunc = (data: Apis, consume: (payload: Result[]) => void) => void;
16
19
  declare const cbpPlatform: (url: string, options?: {
17
20
  open: () => void;
18
21
  }) => {
19
22
  send: (data: EventsEnum) => void;
20
- onactions: (reply: ReplyFunc) => void;
23
+ onactions: (reply: ActionReplyFunc) => void;
24
+ onapis: (reply: ApiReplyFunc) => void;
21
25
  };
22
26
 
23
27
  export { cbpClient, cbpPlatform };
@@ -1,8 +1,67 @@
1
1
  import { WebSocket } from 'ws';
2
2
  import { onProcessor } from '../app/event-processor.js';
3
3
  import { ResultCode } from '../core/code.js';
4
- import { deviceId, FULL_RECEIVE_HEADER, DEVICE_ID_HEADER, USER_AGENT_HEADER, actionResolves, actionTimeouts, reconnectInterval } from './config.js';
4
+ import { deviceId, FULL_RECEIVE_HEADER, DEVICE_ID_HEADER, USER_AGENT_HEADER, apiResolves, apiTimeouts, actionResolves, actionTimeouts, reconnectInterval, HEARTBEAT_INTERVAL } from './config.js';
5
+ import { createResult } from '../core/utils.js';
6
+ import * as flattedJSON from 'flatted';
5
7
 
8
+ // 心跳
9
+ const useHeartbeat = ({ ping, isConnected, terminate }) => {
10
+ let heartbeatTimer = null;
11
+ let lastPong = Date.now();
12
+ const stopHeartbeat = () => {
13
+ if (heartbeatTimer) {
14
+ clearInterval(heartbeatTimer);
15
+ heartbeatTimer = null;
16
+ }
17
+ };
18
+ const callback = () => {
19
+ if (isConnected()) {
20
+ const diff = Date.now() - lastPong;
21
+ const max = HEARTBEAT_INTERVAL * 2; // 最大心跳间隔
22
+ // 检查上次 pong 是否超时
23
+ if (diff > max) {
24
+ logger.debug({
25
+ code: ResultCode.Fail,
26
+ message: '心跳超时,断开重连',
27
+ data: null
28
+ });
29
+ terminate(); // 强制断开
30
+ return;
31
+ }
32
+ ping();
33
+ logger.debug({
34
+ code: ResultCode.Ok,
35
+ message: `发送 ping`,
36
+ data: null
37
+ });
38
+ heartbeatTimer = setTimeout(callback, HEARTBEAT_INTERVAL);
39
+ }
40
+ else {
41
+ stopHeartbeat(); // 如果连接已关闭,停止心跳
42
+ terminate(); // 强制断开
43
+ }
44
+ };
45
+ const startHeartbeat = () => {
46
+ lastPong = Date.now();
47
+ stopHeartbeat();
48
+ callback();
49
+ };
50
+ const control = {
51
+ start: startHeartbeat,
52
+ stop: stopHeartbeat,
53
+ pong: () => {
54
+ // 收到 pong,说明连接正常
55
+ lastPong = Date.now();
56
+ logger.debug({
57
+ code: ResultCode.Ok,
58
+ message: `收到 pong`,
59
+ data: null
60
+ });
61
+ }
62
+ };
63
+ return [control];
64
+ };
6
65
  /**
7
66
  * CBP 客户端
8
67
  * @param url
@@ -17,6 +76,27 @@ const cbpClient = (url, options = {}) => {
17
76
  delete global.chatbotClient;
18
77
  }
19
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
+ });
20
100
  const start = () => {
21
101
  global.chatbotClient = new WebSocket(url, {
22
102
  headers: {
@@ -25,15 +105,21 @@ const cbpClient = (url, options = {}) => {
25
105
  [FULL_RECEIVE_HEADER]: isFullReceive ? '1' : '0'
26
106
  }
27
107
  });
28
- global.chatbotClient.on('open', open);
108
+ global.chatbotClient.on('open', () => {
109
+ open();
110
+ heartbeatControl.start(); // 启动心跳
111
+ });
112
+ global.chatbotClient.on('pong', () => {
113
+ heartbeatControl.pong(); // 更新 pong 时间
114
+ });
29
115
  // 客户端接收,被标准化的平台消息
30
116
  global.chatbotClient.on('message', message => {
31
117
  try {
32
118
  // 解析消息
33
- const parsedMessage = JSON.parse(message.toString());
119
+ const parsedMessage = flattedJSON.parse(message.toString());
34
120
  logger.debug({
35
121
  code: ResultCode.Ok,
36
- message: '接收到消息',
122
+ message: '客户端接收到消息',
37
123
  data: parsedMessage
38
124
  });
39
125
  if (parsedMessage?.activeId) {
@@ -47,19 +133,46 @@ const cbpClient = (url, options = {}) => {
47
133
  }
48
134
  }
49
135
  }
50
- else if (parsedMessage?.actionID) {
51
- // 如果有 actionID,说明要消费掉本地的行为请求
52
- const resolve = actionResolves.get(parsedMessage.actionID);
136
+ else if (parsedMessage?.apiId) {
137
+ // 如果有 apiId,说明是一个接口请求。要进行处理
138
+ const resolve = apiResolves.get(parsedMessage.apiId);
53
139
  if (resolve) {
140
+ apiResolves.delete(parsedMessage.apiId);
54
141
  // 清除超时器
55
- const timeout = actionTimeouts.get(parsedMessage.actionID);
142
+ const timeout = apiTimeouts.get(parsedMessage.apiId);
56
143
  if (timeout) {
144
+ apiTimeouts.delete(parsedMessage.apiId);
57
145
  clearTimeout(timeout);
58
- actionTimeouts.delete(parsedMessage.actionID);
59
146
  }
60
147
  // 调用回调函数
61
- resolve(parsedMessage.payload);
62
- actionResolves.delete(parsedMessage.actionID);
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
+ }
63
176
  }
64
177
  }
65
178
  else if (parsedMessage.name) {
@@ -70,13 +183,14 @@ const cbpClient = (url, options = {}) => {
70
183
  catch (error) {
71
184
  logger.error({
72
185
  code: ResultCode.Fail,
73
- message: '解析消息失败',
186
+ message: '客户端解析消息失败',
74
187
  data: error
75
188
  });
76
189
  }
77
190
  });
78
191
  global.chatbotClient.on('close', () => {
79
- logger.debug({
192
+ heartbeatControl.stop(); // 停止心跳
193
+ logger.warn({
80
194
  code: ResultCode.Fail,
81
195
  message: '连接关闭,尝试重新连接...',
82
196
  data: null
@@ -87,6 +201,13 @@ const cbpClient = (url, options = {}) => {
87
201
  start(); // 重新连接
88
202
  }, reconnectInterval); // 6秒后重连
89
203
  });
204
+ global.chatbotClient.on('error', err => {
205
+ logger.error({
206
+ code: ResultCode.Fail,
207
+ message: '客户端错误',
208
+ data: err
209
+ });
210
+ });
90
211
  };
91
212
  start();
92
213
  };
@@ -97,6 +218,26 @@ const cbpPlatform = (url, options = {
97
218
  delete global.chatbotPlatform;
98
219
  }
99
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
+ });
100
241
  /**
101
242
  * 发送数据
102
243
  * @param data
@@ -104,32 +245,50 @@ const cbpPlatform = (url, options = {
104
245
  const send = (data) => {
105
246
  if (global.chatbotPlatform && global.chatbotPlatform.readyState === WebSocket.OPEN) {
106
247
  data.DeviceId = deviceId; // 设置设备 ID
107
- global.chatbotPlatform.send(JSON.stringify(data));
248
+ global.chatbotPlatform.send(flattedJSON.stringify(data));
108
249
  }
109
250
  };
110
- const msg = [];
251
+ const actionReplys = [];
252
+ const apiReplys = [];
111
253
  /**
112
254
  * 消费数据
113
255
  * @param data
114
256
  * @param payload
115
257
  */
116
- const reply = (data, payload) => {
258
+ const replyAction = (data, payload) => {
117
259
  if (global.chatbotPlatform && global.chatbotPlatform.readyState === WebSocket.OPEN) {
118
- global.chatbotPlatform.send(JSON.stringify({
260
+ // 透传消费。也就是对应的设备进行处理消费。
261
+ global.chatbotPlatform.send(flattedJSON.stringify({
119
262
  action: data.action,
120
263
  payload: payload,
121
- actionID: data.actionID,
122
- // 透传消费。也就是对应的设备进行处理消费。
264
+ actionId: data.actionId,
123
265
  DeviceId: data.DeviceId
124
266
  }));
125
267
  }
126
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
+ };
127
280
  /**
128
281
  * 接收行为
129
282
  * @param reply
130
283
  */
131
284
  const onactions = (reply) => {
132
- msg.push(reply);
285
+ actionReplys.push(reply);
286
+ };
287
+ /**
288
+ * 接收接口
289
+ */
290
+ const onapis = (reply) => {
291
+ apiReplys.push(reply);
133
292
  };
134
293
  /**
135
294
  * 启动 WebSocket 连接
@@ -141,19 +300,34 @@ const cbpPlatform = (url, options = {
141
300
  [DEVICE_ID_HEADER]: deviceId
142
301
  }
143
302
  });
144
- global.chatbotPlatform.on('open', open);
303
+ global.chatbotPlatform.on('open', () => {
304
+ open();
305
+ heartbeatControl.start(); // 启动心跳
306
+ });
307
+ global.chatbotPlatform.on('pong', () => {
308
+ heartbeatControl.pong(); // 更新 pong 时间
309
+ });
145
310
  global.chatbotPlatform.on('message', message => {
146
311
  try {
147
- const data = JSON.parse(message.toString());
312
+ const data = flattedJSON.parse(message.toString());
148
313
  logger.debug({
149
314
  code: ResultCode.Ok,
150
- message: '平台接收消息',
315
+ message: '平台端接收消息',
151
316
  data: data
152
317
  });
153
- for (const cb of msg) {
154
- cb(data,
155
- // 传入一个消费函数
156
- val => reply(data, val));
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
+ }
157
331
  }
158
332
  }
159
333
  catch (error) {
@@ -165,9 +339,10 @@ const cbpPlatform = (url, options = {
165
339
  }
166
340
  });
167
341
  global.chatbotPlatform.on('close', err => {
168
- logger.debug({
342
+ heartbeatControl.stop(); // 停止心跳
343
+ logger.warn({
169
344
  code: ResultCode.Fail,
170
- message: '平台连接关闭,尝试重新连接...',
345
+ message: '平台端连接关闭,尝试重新连接...',
171
346
  data: err
172
347
  });
173
348
  delete global.chatbotPlatform;
@@ -176,11 +351,19 @@ const cbpPlatform = (url, options = {
176
351
  start(); // 重新连接
177
352
  }, reconnectInterval); // 6秒后重连
178
353
  });
354
+ global.chatbotPlatform.on('error', err => {
355
+ logger.error({
356
+ code: ResultCode.Fail,
357
+ message: '平台端错误',
358
+ data: err
359
+ });
360
+ });
179
361
  };
180
362
  start();
181
363
  const client = {
182
364
  send,
183
- onactions
365
+ onactions,
366
+ onapis
184
367
  };
185
368
  return client;
186
369
  };
package/lib/cbp/index.js CHANGED
@@ -6,6 +6,7 @@ import koaCors from '@koa/cors';
6
6
  import { ResultCode } from '../core/code.js';
7
7
  import { USER_AGENT_HEADER, DEVICE_ID_HEADER, FULL_RECEIVE_HEADER, platformClient, childrenClient, fullClient, childrenBind } from './config.js';
8
8
  import { getConfig } from '../core/config.js';
9
+ import * as flattedJSON from 'flatted';
9
10
 
10
11
  const cbpServer = (port, listeningListener) => {
11
12
  if (global.chatbotServer) {
@@ -46,10 +47,42 @@ const cbpServer = (port, listeningListener) => {
46
47
  ws.on('message', (message) => {
47
48
  try {
48
49
  // 解析消息
49
- const parsedMessage = JSON.parse(message.toString());
50
- // 1. 解析得到 actionID ,说明是消费行为请求。要广播告诉所有客户端。
50
+ const parsedMessage = flattedJSON.parse(message.toString());
51
+ // 1. 解析得到 actionId ,说明是消费行为请求。要广播告诉所有客户端。
51
52
  // 2. 解析得到 name ,说明是一个事件请求。
52
- if (parsedMessage?.actionID) {
53
+ // 3. 解析得到 apiId ,说明是一个接口请求。
54
+ logger.debug({
55
+ code: ResultCode.Ok,
56
+ message: '服务端接收到消息',
57
+ data: parsedMessage
58
+ });
59
+ if (parsedMessage.apiId) {
60
+ // 指定的设备 处理消费。终端有记录每个客户端是谁
61
+ const DeviceId = parsedMessage.DeviceId;
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
+ }
72
+ }
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
+ else if (parsedMessage?.actionId) {
53
86
  // 指定的设备 处理消费。终端有记录每个客户端是谁
54
87
  const DeviceId = parsedMessage.DeviceId;
55
88
  if (childrenClient.has(DeviceId)) {
@@ -139,7 +172,7 @@ const cbpServer = (port, listeningListener) => {
139
172
  else {
140
173
  logger.error({
141
174
  code: ResultCode.Fail,
142
- message: '出现意外,无法绑定客户端',
175
+ message: '服务端出现意外,无法绑定客户端',
143
176
  data: null
144
177
  });
145
178
  }
@@ -171,7 +204,7 @@ const cbpServer = (port, listeningListener) => {
171
204
  catch (error) {
172
205
  logger.error({
173
206
  code: ResultCode.Fail,
174
- message: '解析平台消息失败',
207
+ message: '服务端解析平台消息失败',
175
208
  data: error
176
209
  });
177
210
  return;
@@ -186,6 +219,13 @@ const cbpServer = (port, listeningListener) => {
186
219
  data: null
187
220
  });
188
221
  });
222
+ ws.on('error', err => {
223
+ logger.error({
224
+ code: ResultCode.Fail,
225
+ message: `Client ${originId} error`,
226
+ data: err
227
+ });
228
+ });
189
229
  };
190
230
  // 设置子客户端
191
231
  const setChildrenClient = (originId, ws) => {
@@ -217,6 +257,13 @@ const cbpServer = (port, listeningListener) => {
217
257
  data: null
218
258
  });
219
259
  });
260
+ ws.on('error', err => {
261
+ logger.error({
262
+ code: ResultCode.Fail,
263
+ message: `Client ${originId} error`,
264
+ data: err
265
+ });
266
+ });
220
267
  };
221
268
  // 全量客户端
222
269
  const setFullClient = (originId, ws) => {
@@ -272,7 +319,7 @@ const cbpServer = (port, listeningListener) => {
272
319
  return;
273
320
  }
274
321
  // 连接时,需要给客户端发送主动消息
275
- ws.send(JSON.stringify({
322
+ ws.send(flattedJSON.stringify({
276
323
  active: 'sync',
277
324
  payload: {
278
325
  value: getConfig().value,
@@ -1,5 +1,5 @@
1
1
  import { Dirent } from 'fs';
2
- import { ResultCode } from '../core/code.js';
2
+ import { ResultCode } from './code.js';
3
3
 
4
4
  /**
5
5
  * 将字符串转为定长字符串
@@ -30,8 +30,7 @@ declare const useUserHashKey: (event: {
30
30
  declare const createEventName: (url: string, appKey: string) => string;
31
31
  /**
32
32
  * 将字符串转为数字
33
- * @param str
34
- * @returns
33
+ * @deprecated 已废弃
35
34
  */
36
35
  declare const stringToNumber: (str: string, size?: number) => number;
37
36
  /**
@@ -2,8 +2,8 @@ import crypto from 'crypto';
2
2
  import fs, { existsSync, readdirSync } from 'fs';
3
3
  import path, { join } from 'path';
4
4
  import { createRequire } from 'module';
5
- import { ResultCode } from '../core/code.js';
6
- import { file_suffix_response } from '../core/variable.js';
5
+ import { ResultCode } from './code.js';
6
+ import { file_suffix_response } from './variable.js';
7
7
 
8
8
  const require = createRequire(import.meta.url);
9
9
  /**
@@ -48,8 +48,7 @@ const createEventName = (url, appKey) => {
48
48
  };
49
49
  /**
50
50
  * 将字符串转为数字
51
- * @param str
52
- * @returns
51
+ * @deprecated 已废弃
53
52
  */
54
53
  const stringToNumber = (str, size = 33) => {
55
54
  let hash = 5381;