alemonjs 2.1.0-alpha.4 → 2.1.0-alpha.6

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/app/load.js CHANGED
@@ -51,7 +51,7 @@ const loadChildren = async (mainPath, appName) => {
51
51
  // 卸载
52
52
  App.un();
53
53
  try {
54
- await app?.unMounted(e);
54
+ app?.unMounted && (await app.unMounted(e));
55
55
  }
56
56
  catch (e) {
57
57
  // 卸载周期出意外,不需要进行卸载
@@ -59,15 +59,13 @@ const loadChildren = async (mainPath, appName) => {
59
59
  }
60
60
  };
61
61
  // onCreated 创建
62
- if (typeof app?.onCreated == 'function') {
63
- try {
64
- await app?.onCreated();
65
- }
66
- catch (e) {
67
- unMounted(e);
68
- // 出错了,结束后续的操作。
69
- return;
70
- }
62
+ try {
63
+ app?.onCreated && (await app?.onCreated());
64
+ }
65
+ catch (e) {
66
+ unMounted(e);
67
+ // 出错了,结束后续的操作。
68
+ return;
71
69
  }
72
70
  // onMounted 加载
73
71
  try {
@@ -119,9 +117,7 @@ const loadChildren = async (mainPath, appName) => {
119
117
  App.pushMiddleware(mwData);
120
118
  App.on();
121
119
  try {
122
- if (typeof app?.onMounted == 'function') {
123
- await app?.onMounted({ response: resData, middleware: mwData });
124
- }
120
+ app?.onMounted && (await app.onMounted({ response: resData, middleware: mwData }));
125
121
  }
126
122
  catch (e) {
127
123
  unMounted(e);
package/lib/cbp/config.js CHANGED
@@ -26,6 +26,8 @@ const generateUniqueId = () => {
26
26
  // 超时时间
27
27
  const timeoutTime = 1000 * 12; // 12秒
28
28
  // 失败重连
29
- const reconnectInterval = 6000; // 6秒
29
+ const reconnectInterval = 1000 * 6; // 6秒
30
+ // 心跳间隔
31
+ const HEARTBEAT_INTERVAL = 1000 * 18; // 18秒
30
32
 
31
- export { DEVICE_ID_HEADER, FULL_RECEIVE_HEADER, USER_AGENT_HEADER, actionResolves, actionTimeouts, childrenBind, childrenClient, deviceId, fullClient, generateUniqueId, platformClient, reconnectInterval, timeoutTime };
33
+ export { DEVICE_ID_HEADER, FULL_RECEIVE_HEADER, HEARTBEAT_INTERVAL, USER_AGENT_HEADER, actionResolves, actionTimeouts, childrenBind, childrenClient, deviceId, fullClient, generateUniqueId, platformClient, reconnectInterval, timeoutTime };
@@ -1,7 +1,7 @@
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, actionResolves, actionTimeouts, reconnectInterval, HEARTBEAT_INTERVAL } from './config.js';
5
5
  import '../app/define-chidren.js';
6
6
  import '../app/event-middleware.js';
7
7
  import '../app/event-response.js';
@@ -17,6 +17,63 @@ import '../app/message-api.js';
17
17
  import '../app/message-format.js';
18
18
  import { createResult } from '../app/utils.js';
19
19
 
20
+ // 心跳
21
+ const useHeartbeat = ({ ping, isConnected, terminate, }) => {
22
+ let heartbeatTimer = null;
23
+ let lastPong = Date.now();
24
+ const stopHeartbeat = () => {
25
+ if (heartbeatTimer) {
26
+ clearInterval(heartbeatTimer);
27
+ heartbeatTimer = null;
28
+ }
29
+ };
30
+ const callback = () => {
31
+ if (isConnected()) {
32
+ const diff = Date.now() - lastPong;
33
+ const max = HEARTBEAT_INTERVAL * 2; // 最大心跳间隔
34
+ // 检查上次 pong 是否超时
35
+ if (diff > max) {
36
+ logger.debug({
37
+ code: ResultCode.Fail,
38
+ message: '心跳超时,断开重连',
39
+ data: null
40
+ });
41
+ terminate(); // 强制断开
42
+ return;
43
+ }
44
+ ping();
45
+ logger.debug({
46
+ code: ResultCode.Ok,
47
+ message: `发送 ping`,
48
+ data: null
49
+ });
50
+ heartbeatTimer = setTimeout(callback, HEARTBEAT_INTERVAL);
51
+ }
52
+ else {
53
+ stopHeartbeat(); // 如果连接已关闭,停止心跳
54
+ terminate(); // 强制断开
55
+ }
56
+ };
57
+ const startHeartbeat = () => {
58
+ lastPong = Date.now();
59
+ stopHeartbeat();
60
+ callback();
61
+ };
62
+ const control = {
63
+ start: startHeartbeat,
64
+ stop: stopHeartbeat,
65
+ pong: () => {
66
+ // 收到 pong,说明连接正常
67
+ lastPong = Date.now();
68
+ logger.debug({
69
+ code: ResultCode.Ok,
70
+ message: `收到 pong`,
71
+ data: null
72
+ });
73
+ }
74
+ };
75
+ return [control];
76
+ };
20
77
  /**
21
78
  * CBP 客户端
22
79
  * @param url
@@ -31,6 +88,27 @@ const cbpClient = (url, options = {}) => {
31
88
  delete global.chatbotClient;
32
89
  }
33
90
  const { open = () => { }, isFullReceive = true } = options;
91
+ const [heartbeatControl] = useHeartbeat({
92
+ ping: () => {
93
+ global.chatbotClient.ping?.();
94
+ },
95
+ isConnected: () => {
96
+ return global.chatbotClient && global.chatbotClient.readyState === WebSocket.OPEN;
97
+ },
98
+ terminate: () => {
99
+ try {
100
+ // 强制断开连接
101
+ global.chatbotClient.terminate?.();
102
+ }
103
+ catch (error) {
104
+ logger.debug({
105
+ code: ResultCode.Fail,
106
+ message: '强制断开连接失败',
107
+ data: error
108
+ });
109
+ }
110
+ }
111
+ });
34
112
  const start = () => {
35
113
  global.chatbotClient = new WebSocket(url, {
36
114
  headers: {
@@ -39,7 +117,13 @@ const cbpClient = (url, options = {}) => {
39
117
  [FULL_RECEIVE_HEADER]: isFullReceive ? '1' : '0'
40
118
  }
41
119
  });
42
- global.chatbotClient.on('open', open);
120
+ global.chatbotClient.on('open', () => {
121
+ open();
122
+ heartbeatControl.start(); // 启动心跳
123
+ });
124
+ global.chatbotClient.on('pong', () => {
125
+ heartbeatControl.pong(); // 更新 pong 时间
126
+ });
43
127
  // 客户端接收,被标准化的平台消息
44
128
  global.chatbotClient.on('message', message => {
45
129
  try {
@@ -96,7 +180,8 @@ const cbpClient = (url, options = {}) => {
96
180
  }
97
181
  });
98
182
  global.chatbotClient.on('close', () => {
99
- logger.debug({
183
+ heartbeatControl.stop(); // 停止心跳
184
+ logger.warn({
100
185
  code: ResultCode.Fail,
101
186
  message: '连接关闭,尝试重新连接...',
102
187
  data: null
@@ -124,6 +209,27 @@ const cbpPlatform = (url, options = {
124
209
  delete global.chatbotPlatform;
125
210
  }
126
211
  const { open = () => { } } = options;
212
+ const [heartbeatControl] = useHeartbeat({
213
+ ping: () => {
214
+ global.chatbotClient.ping?.();
215
+ },
216
+ isConnected: () => {
217
+ return global.chatbotClient && global.chatbotClient.readyState === WebSocket.OPEN;
218
+ },
219
+ terminate: () => {
220
+ try {
221
+ // 强制断开连接
222
+ global.chatbotClient.terminate?.();
223
+ }
224
+ catch (error) {
225
+ logger.debug({
226
+ code: ResultCode.Fail,
227
+ message: '强制断开连接失败',
228
+ data: error
229
+ });
230
+ }
231
+ }
232
+ });
127
233
  /**
128
234
  * 发送数据
129
235
  * @param data
@@ -168,7 +274,13 @@ const cbpPlatform = (url, options = {
168
274
  [DEVICE_ID_HEADER]: deviceId
169
275
  }
170
276
  });
171
- global.chatbotPlatform.on('open', open);
277
+ global.chatbotPlatform.on('open', () => {
278
+ open();
279
+ heartbeatControl.start(); // 启动心跳
280
+ });
281
+ global.chatbotPlatform.on('pong', () => {
282
+ heartbeatControl.pong(); // 更新 pong 时间
283
+ });
172
284
  global.chatbotPlatform.on('message', message => {
173
285
  try {
174
286
  const data = JSON.parse(message.toString());
@@ -192,7 +304,8 @@ const cbpPlatform = (url, options = {
192
304
  }
193
305
  });
194
306
  global.chatbotPlatform.on('close', err => {
195
- logger.debug({
307
+ heartbeatControl.stop(); // 停止心跳
308
+ logger.warn({
196
309
  code: ResultCode.Fail,
197
310
  message: '平台端连接关闭,尝试重新连接...',
198
311
  data: err
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alemonjs",
3
- "version": "2.1.0-alpha.4",
3
+ "version": "2.1.0-alpha.6",
4
4
  "description": "bot script",
5
5
  "author": "lemonade",
6
6
  "license": "MIT",