@pixelhue/event-controller-sdk 0.0.1 → 0.0.14

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 (61) hide show
  1. package/dist/index.d.ts +0 -1
  2. package/dist/index.js +0 -1
  3. package/dist/packages/tcp/ConnectManager.d.ts +1 -2
  4. package/dist/packages/tcp/ConnectManager.js +2 -3
  5. package/dist/packages/tcp/QueueManager.d.ts +0 -1
  6. package/dist/packages/tcp/QueueManager.js +9 -14
  7. package/dist/packages/tcp/SocketWrapper.d.ts +13 -3
  8. package/dist/packages/tcp/SocketWrapper.js +68 -28
  9. package/dist/packages/tcp/constants.d.ts +0 -1
  10. package/dist/packages/tcp/constants.js +0 -1
  11. package/dist/packages/tcp/discoveryService.d.ts +0 -1
  12. package/dist/packages/tcp/discoveryService.js +0 -1
  13. package/dist/packages/tcp/protocolHandler.d.ts +0 -1
  14. package/dist/packages/tcp/protocolHandler.js +2 -2
  15. package/dist/packages/tcp/tcpWrapper.d.ts +27 -4
  16. package/dist/packages/tcp/tcpWrapper.js +106 -50
  17. package/dist/packages/tcp/types.d.ts +0 -1
  18. package/dist/packages/tcp/types.js +0 -1
  19. package/dist/packages/tcp/utils.d.ts +0 -1
  20. package/dist/packages/tcp/utils.js +0 -1
  21. package/package.json +87 -82
  22. package/dist/index.d.ts.map +0 -1
  23. package/dist/index.js.map +0 -1
  24. package/dist/packages/tcp/ConnectManager.d.ts.map +0 -1
  25. package/dist/packages/tcp/ConnectManager.js.map +0 -1
  26. package/dist/packages/tcp/QueueManager.d.ts.map +0 -1
  27. package/dist/packages/tcp/QueueManager.js.map +0 -1
  28. package/dist/packages/tcp/SocketWrapper.d.ts.map +0 -1
  29. package/dist/packages/tcp/SocketWrapper.js.map +0 -1
  30. package/dist/packages/tcp/constants.d.ts.map +0 -1
  31. package/dist/packages/tcp/constants.js.map +0 -1
  32. package/dist/packages/tcp/demo.d.ts +0 -3
  33. package/dist/packages/tcp/demo.d.ts.map +0 -1
  34. package/dist/packages/tcp/demo.js +0 -164
  35. package/dist/packages/tcp/demo.js.map +0 -1
  36. package/dist/packages/tcp/discoveryService.d.ts.map +0 -1
  37. package/dist/packages/tcp/discoveryService.js.map +0 -1
  38. package/dist/packages/tcp/protocolHandler.d.ts.map +0 -1
  39. package/dist/packages/tcp/protocolHandler.js.map +0 -1
  40. package/dist/packages/tcp/tcpWrapper.d.ts.map +0 -1
  41. package/dist/packages/tcp/tcpWrapper.js.map +0 -1
  42. package/dist/packages/tcp/test-build-parse-debug.d.ts +0 -2
  43. package/dist/packages/tcp/test-build-parse-debug.d.ts.map +0 -1
  44. package/dist/packages/tcp/test-build-parse-debug.js +0 -73
  45. package/dist/packages/tcp/test-build-parse-debug.js.map +0 -1
  46. package/dist/packages/tcp/test-packet-split.d.ts +0 -43
  47. package/dist/packages/tcp/test-packet-split.d.ts.map +0 -1
  48. package/dist/packages/tcp/test-packet-split.js +0 -417
  49. package/dist/packages/tcp/test-packet-split.js.map +0 -1
  50. package/dist/packages/tcp/test-protocol-handler.d.ts +0 -6
  51. package/dist/packages/tcp/test-protocol-handler.d.ts.map +0 -1
  52. package/dist/packages/tcp/test-protocol-handler.js +0 -225
  53. package/dist/packages/tcp/test-protocol-handler.js.map +0 -1
  54. package/dist/packages/tcp/test-server.d.ts +0 -54
  55. package/dist/packages/tcp/test-server.d.ts.map +0 -1
  56. package/dist/packages/tcp/test-server.js +0 -412
  57. package/dist/packages/tcp/test-server.js.map +0 -1
  58. package/dist/packages/tcp/types.d.ts.map +0 -1
  59. package/dist/packages/tcp/types.js.map +0 -1
  60. package/dist/packages/tcp/utils.d.ts.map +0 -1
  61. package/dist/packages/tcp/utils.js.map +0 -1
package/dist/index.d.ts CHANGED
@@ -14,4 +14,3 @@ export { QueueOverflowStrategy } from './packages/tcp/types.js';
14
14
  export { SUPPORTED_MODELS, DEFAULT_TCP_PORT, DEFAULT_ENABLE_HEARTBEAT, DEFAULT_AUTO_RECONNECT, DEFAULT_HEARTBEAT_INTERVAL, DEFAULT_RECONNECT_INTERVAL, DEFAULT_HEARTBEAT_TIMEOUT, DEFAULT_MAX_RECONNECT_INTERVAL, DEFAULT_ENABLE_EXPONENTIAL_BACKOFF, DEFAULT_MDNS_QUERY_INTERVAL, DEFAULT_MAX_RECONNECT_ATTEMPTS, } from './packages/tcp/constants.js';
15
15
  export { parseHost, parsePort } from './packages/tcp/utils.js';
16
16
  export type { ProtocolParseResult } from './packages/tcp/protocolHandler.js';
17
- //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -15,4 +15,3 @@ export { QueueOverflowStrategy } from './packages/tcp/types.js';
15
15
  export { SUPPORTED_MODELS, DEFAULT_TCP_PORT, DEFAULT_ENABLE_HEARTBEAT, DEFAULT_AUTO_RECONNECT, DEFAULT_HEARTBEAT_INTERVAL, DEFAULT_RECONNECT_INTERVAL, DEFAULT_HEARTBEAT_TIMEOUT, DEFAULT_MAX_RECONNECT_INTERVAL, DEFAULT_ENABLE_EXPONENTIAL_BACKOFF, DEFAULT_MDNS_QUERY_INTERVAL, DEFAULT_MAX_RECONNECT_ATTEMPTS, } from './packages/tcp/constants.js';
16
16
  // 工具函数导出
17
17
  export { parseHost, parsePort } from './packages/tcp/utils.js';
18
- //# sourceMappingURL=index.js.map
@@ -1,6 +1,6 @@
1
1
  import { EventEmitter } from 'eventemitter3';
2
- import type { ConnectionManagerEvents, SocketConnectOptions } from './types.js';
3
2
  import { SocketWrapper } from './SocketWrapper.js';
3
+ import type { ConnectionManagerEvents, SocketConnectOptions } from './types.js';
4
4
  /**
5
5
  * MINI连接管理器
6
6
  */
@@ -63,4 +63,3 @@ export declare class MiniConnectionManager extends EventEmitter<ConnectionManage
63
63
  */
64
64
  destroy(): Promise<void>;
65
65
  }
66
- //# sourceMappingURL=ConnectManager.d.ts.map
@@ -71,7 +71,7 @@ export class MiniConnectionManager extends EventEmitter {
71
71
  const connectionId = this.getConnectionId(address, port);
72
72
  const socketWrapper = this.connections.get(connectionId);
73
73
  if (socketWrapper) {
74
- await socketWrapper.disconnect();
74
+ socketWrapper.disconnect();
75
75
  this.connections.delete(connectionId);
76
76
  // 触发断开事件,传递 SocketWrapper
77
77
  this.emit('disconnected', socketWrapper);
@@ -169,8 +169,7 @@ export class MiniConnectionManager extends EventEmitter {
169
169
  */
170
170
  async destroy() {
171
171
  this.isShuttingDown = true;
172
- await this.disconnectAll();
172
+ this.disconnectAll();
173
173
  this.removeAllListeners();
174
174
  }
175
175
  }
176
- //# sourceMappingURL=ConnectManager.js.map
@@ -38,4 +38,3 @@ export declare class QueueManager {
38
38
  */
39
39
  clear(): void;
40
40
  }
41
- //# sourceMappingURL=QueueManager.d.ts.map
@@ -40,18 +40,13 @@ export class QueueManager {
40
40
  addToQueue(requestId, data, processor, onError, cachedParseResult) {
41
41
  this.queue
42
42
  .add(async () => {
43
- try {
44
- // 处理队列项
45
- await processor(requestId, data, cachedParseResult);
46
- // 去重标记
47
- this.processedRequestIds.add(requestId);
48
- // 限制去重集合大小,防止内存泄漏
49
- if (this.processedRequestIds.size > this.queueOptions.maxLength * 2) {
50
- this.processedRequestIds.clear();
51
- }
52
- }
53
- catch (error) {
54
- throw error; // 重新抛出,让 p-queue 处理
43
+ // 处理队列项
44
+ await processor(requestId, data, cachedParseResult);
45
+ // 去重标记
46
+ this.processedRequestIds.add(requestId);
47
+ // 限制去重集合大小,防止内存泄漏
48
+ if (this.processedRequestIds.size > this.queueOptions.maxLength * 2) {
49
+ this.processedRequestIds.clear();
55
50
  }
56
51
  })
57
52
  .catch((error) => {
@@ -79,11 +74,12 @@ export class QueueManager {
79
74
  case QueueOverflowStrategy.DROP_NEWEST:
80
75
  // 丢弃最新数据
81
76
  break;
82
- case QueueOverflowStrategy.REJECT:
77
+ case QueueOverflowStrategy.REJECT: {
83
78
  // 拒绝新数据并触发错误
84
79
  const error = new Error(`Queue overflow: max length ${this.queueOptions.maxLength} reached`);
85
80
  onError(error, requestId);
86
81
  break;
82
+ }
87
83
  case QueueOverflowStrategy.DROP_OLDEST:
88
84
  default:
89
85
  // p-queue 不支持直接丢弃最旧的任务
@@ -99,4 +95,3 @@ export class QueueManager {
99
95
  this.processedRequestIds.clear();
100
96
  }
101
97
  }
102
- //# sourceMappingURL=QueueManager.js.map
@@ -1,6 +1,6 @@
1
1
  import { EventEmitter } from 'events';
2
- import type { ISocketWrapper, SocketConnectOptions, QueueOptions, ProtocolSendPayload } from './types.js';
3
2
  import { TcpWrapper } from './tcpWrapper.js';
3
+ import type { ISocketWrapper, ProtocolSendPayload, QueueOptions, SocketConnectOptions } from './types.js';
4
4
  /**
5
5
  * SocketWrapper - TCP Socket 最小传输封装
6
6
  *
@@ -36,7 +36,7 @@ export declare class SocketWrapper extends EventEmitter implements ISocketWrappe
36
36
  constructor(queueOptions?: Partial<QueueOptions>);
37
37
  /**
38
38
  * 检查是否是心跳数据(ping/pong)
39
- * 使用 Buffer 直接比较,避免字符串转换开销
39
+ * 使用 TcpWrapper 的 heartbeatResponseChecker 统一检查
40
40
  */
41
41
  private isHeartbeatData;
42
42
  /**
@@ -44,6 +44,17 @@ export declare class SocketWrapper extends EventEmitter implements ISocketWrappe
44
44
  * @param data 接收到的数据
45
45
  */
46
46
  private handleReceiveData;
47
+ /**
48
+ * 移除缓冲区开头的心跳数据(处理粘包情况:心跳数据 + 协议数据)
49
+ * @returns 如果移除了心跳数据返回 true,否则返回 false
50
+ */
51
+ private removeHeartbeatPrefix;
52
+ /**
53
+ * 处理提取出的协议包
54
+ * @param packets 有效协议包列表
55
+ * @param invalidPackets 无效协议包列表
56
+ */
57
+ private processExtractedPackets;
47
58
  /**
48
59
  * 处理协议数据(使用半包粘包处理)
49
60
  * 使用循环替代递归,避免栈溢出风险
@@ -103,4 +114,3 @@ export declare class SocketWrapper extends EventEmitter implements ISocketWrappe
103
114
  */
104
115
  getTcpWrapper(): TcpWrapper;
105
116
  }
106
- //# sourceMappingURL=SocketWrapper.d.ts.map
@@ -1,14 +1,12 @@
1
1
  // ALL_CODE_LINE: 329
2
2
  // AI_CODE_LINE: 53
3
3
  import { EventEmitter } from 'events';
4
- import { TcpWrapper } from './tcpWrapper.js';
5
- import { QueueManager, DEFAULT_QUEUE_OPTIONS } from './QueueManager.js';
6
4
  import { ProtocolHandler } from './protocolHandler.js';
5
+ import { DEFAULT_QUEUE_OPTIONS, QueueManager } from './QueueManager.js';
6
+ import { TcpWrapper } from './tcpWrapper.js';
7
7
  /**
8
- * 心跳数据常量(预定义 Buffer,避免重复转换)
8
+ * 心跳数据长度常量
9
9
  */
10
- const HEARTBEAT_PING = Buffer.from('ping', 'utf8');
11
- const HEARTBEAT_PONG = Buffer.from('pong', 'utf8');
12
10
  const HEARTBEAT_LENGTH = 4;
13
11
  /**
14
12
  * SocketWrapper - TCP Socket 最小传输封装
@@ -76,13 +74,11 @@ export class SocketWrapper extends EventEmitter {
76
74
  }
77
75
  /**
78
76
  * 检查是否是心跳数据(ping/pong)
79
- * 使用 Buffer 直接比较,避免字符串转换开销
77
+ * 使用 TcpWrapper 的 heartbeatResponseChecker 统一检查
80
78
  */
81
79
  isHeartbeatData(buffer) {
82
- if (buffer.length !== HEARTBEAT_LENGTH) {
83
- return false;
84
- }
85
- return buffer.equals(HEARTBEAT_PING) || buffer.equals(HEARTBEAT_PONG);
80
+ const heartbeatResponseChecker = this.tcpWrapper.getHeartbeatResponseChecker();
81
+ return heartbeatResponseChecker(buffer);
86
82
  }
87
83
  /**
88
84
  * 接收数据处理
@@ -103,6 +99,38 @@ export class SocketWrapper extends EventEmitter {
103
99
  // 处理协议数据
104
100
  this.handleProtocolData();
105
101
  }
102
+ /**
103
+ * 移除缓冲区开头的心跳数据(处理粘包情况:心跳数据 + 协议数据)
104
+ * @returns 如果移除了心跳数据返回 true,否则返回 false
105
+ */
106
+ removeHeartbeatPrefix() {
107
+ if (!this.receiveBuffer || this.receiveBuffer.length < HEARTBEAT_LENGTH) {
108
+ return false;
109
+ }
110
+ const first4Bytes = this.receiveBuffer.slice(0, HEARTBEAT_LENGTH);
111
+ if (!this.isHeartbeatData(first4Bytes)) {
112
+ return false;
113
+ }
114
+ // 移除前 4 字节的心跳数据
115
+ this.receiveBuffer =
116
+ this.receiveBuffer.length > HEARTBEAT_LENGTH ? this.receiveBuffer.slice(HEARTBEAT_LENGTH) : null;
117
+ return true;
118
+ }
119
+ /**
120
+ * 处理提取出的协议包
121
+ * @param packets 有效协议包列表
122
+ * @param invalidPackets 无效协议包列表
123
+ */
124
+ processExtractedPackets(packets, invalidPackets) {
125
+ // 处理校验失败的废包
126
+ if (invalidPackets.length > 0) {
127
+ this.emit('error', new Error(`Invalid packets detected: ${invalidPackets.length} packets dropped`));
128
+ }
129
+ // 处理每个有效完整包
130
+ for (const packet of packets) {
131
+ this.processPacket(packet);
132
+ }
133
+ }
106
134
  /**
107
135
  * 处理协议数据(使用半包粘包处理)
108
136
  * 使用循环替代递归,避免栈溢出风险
@@ -110,34 +138,42 @@ export class SocketWrapper extends EventEmitter {
110
138
  handleProtocolData() {
111
139
  if (!this.receiveBuffer)
112
140
  return;
141
+ // 保护机制:跟踪 remaining 长度未变化的次数 防止异常数据导致死循环
142
+ const MAX_STAGNANT_LOOPS = 10; // 最大停滞循环次数
143
+ let stagnantCount = 0;
144
+ let lastRemainingLength = 0;
113
145
  // 循环处理,直到没有更多数据需要处理
114
146
  while (this.receiveBuffer) {
115
147
  // 检查并过滤心跳数据(处理粘包情况:心跳数据 + 协议数据)
116
- if (this.receiveBuffer.length >= HEARTBEAT_LENGTH) {
117
- const first4Bytes = this.receiveBuffer.slice(0, HEARTBEAT_LENGTH);
118
- if (this.isHeartbeatData(first4Bytes)) {
119
- // 移除前 4 字节的心跳数据,继续处理剩余数据
120
- this.receiveBuffer =
121
- this.receiveBuffer.length > HEARTBEAT_LENGTH ? this.receiveBuffer.slice(HEARTBEAT_LENGTH) : null;
122
- continue; // 继续循环处理剩余数据
123
- }
148
+ if (this.removeHeartbeatPrefix()) {
149
+ continue; // 继续循环处理剩余数据
124
150
  }
125
151
  // 提取所有完整协议包(自动校验)
126
152
  const { packets, remaining, invalidPackets } = this.protocolHandler.extractAllCompletePackets(this.receiveBuffer);
127
- // 处理校验失败的废包
128
- if (invalidPackets.length > 0) {
129
- this.emit('error', new Error(`Invalid packets detected: ${invalidPackets.length} packets dropped`));
130
- }
131
- // 处理每个有效完整包
132
- for (const packet of packets) {
133
- this.processPacket(packet);
134
- }
153
+ // 处理提取出的协议包
154
+ this.processExtractedPackets(packets, invalidPackets);
135
155
  // 更新接收缓冲区为剩余数据(半包数据保留)
136
156
  this.receiveBuffer = remaining;
137
157
  // 如果没有剩余数据,退出循环
138
158
  if (!remaining || remaining.length === 0) {
139
159
  break;
140
160
  }
161
+ // 保护机制:检查 remaining 长度是否一直没变化
162
+ if (remaining.length > 0) {
163
+ if (remaining.length === lastRemainingLength) {
164
+ // 长度没变化,增加停滞计数
165
+ stagnantCount += 1;
166
+ if (stagnantCount > MAX_STAGNANT_LOOPS) {
167
+ this.receiveBuffer = null; // 丢弃剩余数据
168
+ break;
169
+ }
170
+ }
171
+ else {
172
+ // 长度有变化,重置停滞计数
173
+ stagnantCount = 0;
174
+ lastRemainingLength = remaining.length;
175
+ }
176
+ }
141
177
  }
142
178
  }
143
179
  /**
@@ -213,6 +249,11 @@ export class SocketWrapper extends EventEmitter {
213
249
  this.emit('error', new Error('Socket is not writable'));
214
250
  return;
215
251
  }
252
+ // 防止发送空数据:如果数据长度为 0,记录错误并返回
253
+ if (!bytes || bytes.length === 0) {
254
+ this.emit('error', new Error('尝试发送空数据包(size === 0),可能是协议构建失败'));
255
+ return;
256
+ }
216
257
  socket.write(bytes, (err) => {
217
258
  if (err) {
218
259
  this.emit('error', err);
@@ -242,7 +283,7 @@ export class SocketWrapper extends EventEmitter {
242
283
  if (typeof buildOptions.seqId !== 'number') {
243
284
  buildOptions.seqId = this.protocolHandler.generateSeqId();
244
285
  }
245
- const buffer = this.protocolHandler.build(payload);
286
+ const buffer = this.protocolHandler.build(buildOptions);
246
287
  const resolvedRequestId = buildOptions.seqId;
247
288
  this.writeToSocket(buffer);
248
289
  return resolvedRequestId;
@@ -278,4 +319,3 @@ export class SocketWrapper extends EventEmitter {
278
319
  return this.tcpWrapper;
279
320
  }
280
321
  }
281
- //# sourceMappingURL=SocketWrapper.js.map
@@ -22,4 +22,3 @@ export declare const DEFAULT_ENABLE_EXPONENTIAL_BACKOFF = true;
22
22
  export declare const DEFAULT_MDNS_QUERY_INTERVAL = 10000;
23
23
  /** 默认最大重连次数 */
24
24
  export declare const DEFAULT_MAX_RECONNECT_ATTEMPTS = 0;
25
- //# sourceMappingURL=constants.d.ts.map
@@ -24,4 +24,3 @@ export const DEFAULT_ENABLE_EXPONENTIAL_BACKOFF = true;
24
24
  export const DEFAULT_MDNS_QUERY_INTERVAL = 10000; // 10秒
25
25
  /** 默认最大重连次数 */
26
26
  export const DEFAULT_MAX_RECONNECT_ATTEMPTS = 0;
27
- //# sourceMappingURL=constants.js.map
@@ -39,4 +39,3 @@ export declare class MiniDiscoveryService extends EventEmitter<DiscoveryEvents>
39
39
  */
40
40
  destroy(): void;
41
41
  }
42
- //# sourceMappingURL=discoveryService.d.ts.map
@@ -163,4 +163,3 @@ export class MiniDiscoveryService extends EventEmitter {
163
163
  this.removeAllListeners(); // 清理当前DiscoveryService(继承自EventEmitter)的所有事件监听器,避免内存泄漏
164
164
  }
165
165
  }
166
- //# sourceMappingURL=discoveryService.js.map
@@ -61,4 +61,3 @@ export declare class ProtocolHandler {
61
61
  invalidPackets: Buffer[];
62
62
  };
63
63
  }
64
- //# sourceMappingURL=protocolHandler.d.ts.map
@@ -4,8 +4,8 @@
4
4
  * Uniform Protocol 协议处理模块
5
5
  * 封装协议解析、校验和构建功能
6
6
  */
7
- import { UniformProtocolParser } from '@unico/uniform-protocol-parser';
8
7
  import { UniformProtocolBuilder } from '@unico/uniform-protocol-builder';
8
+ import { UniformProtocolParser } from '@unico/uniform-protocol-parser';
9
9
  /**
10
10
  * Uniform Protocol 协议处理器
11
11
  */
@@ -42,6 +42,7 @@ export class ProtocolHandler {
42
42
  };
43
43
  }
44
44
  catch (error) {
45
+ console.error('解析协议数据包时出错:', error);
45
46
  throw error;
46
47
  }
47
48
  }
@@ -93,4 +94,3 @@ export class ProtocolHandler {
93
94
  };
94
95
  }
95
96
  }
96
- //# sourceMappingURL=protocolHandler.js.map
@@ -1,5 +1,5 @@
1
1
  import * as net from 'net';
2
- import type { SocketConnectOptions, HeartbeatResponseChecker } from './types.js';
2
+ import type { HeartbeatResponseChecker, SocketConnectOptions } from './types.js';
3
3
  /**
4
4
  * tcp连接管理器
5
5
  * 负责处理 TCP 连接、重连、超时检测等
@@ -33,7 +33,7 @@ export declare class TcpWrapper {
33
33
  private pendingHeartbeat;
34
34
  /** 连续心跳超时次数 */
35
35
  private heartbeatTimeoutCount;
36
- /** 心跳响应识别函数 */
36
+ /** 心跳响应识别函数(同时检查 ping 和 pong) */
37
37
  private heartbeatResponseChecker;
38
38
  /** 最大重连次数,0 表示无限制 */
39
39
  private maxReconnectAttempts;
@@ -65,7 +65,6 @@ export declare class TcpWrapper {
65
65
  private onError?;
66
66
  /** 连接关闭回调(手动断开或重连失败时触发) */
67
67
  private onClose?;
68
- constructor();
69
68
  /**
70
69
  * 设置 Socket 事件监听
71
70
  */
@@ -110,6 +109,27 @@ export declare class TcpWrapper {
110
109
  * 设置连接超时
111
110
  */
112
111
  private setConnectTimeout;
112
+ /**
113
+ * 握手超时处理入口
114
+ * 提取为独立方法以降低 setConnectTimeout 的复杂度
115
+ */
116
+ private handleHandshakeTimeout;
117
+ /**
118
+ * 是否还有剩余的握手重试次数
119
+ */
120
+ private hasRemainingHandshakeAttempts;
121
+ /**
122
+ * 执行握手重试流程:销毁当前 socket、计算重试间隔并尝试重新连接
123
+ */
124
+ private retryHandshakeConnection;
125
+ /**
126
+ * 安排一次新的握手重连尝试
127
+ */
128
+ private scheduleHandshakeReconnect;
129
+ /**
130
+ * 握手多次超时后的失败处理
131
+ */
132
+ private handleHandshakeFailure;
113
133
  /**
114
134
  * 清除连接超时定时器
115
135
  */
@@ -152,6 +172,10 @@ export declare class TcpWrapper {
152
172
  * 设置心跳响应识别函数
153
173
  */
154
174
  setHeartbeatResponseChecker(checker: HeartbeatResponseChecker): void;
175
+ /**
176
+ * 获取心跳响应识别函数
177
+ */
178
+ getHeartbeatResponseChecker(): HeartbeatResponseChecker;
155
179
  /**
156
180
  * 获取当前连接地址
157
181
  */
@@ -165,4 +189,3 @@ export declare class TcpWrapper {
165
189
  */
166
190
  getReconnectAttempts(): number;
167
191
  }
168
- //# sourceMappingURL=tcpWrapper.d.ts.map
@@ -1,7 +1,7 @@
1
1
  // ALL_CODE_LINE: 450
2
2
  // AI_CODE_LINE: 40
3
3
  import * as net from 'net';
4
- import { DEFAULT_AUTO_RECONNECT, DEFAULT_RECONNECT_INTERVAL, DEFAULT_HEARTBEAT_INTERVAL, DEFAULT_HEARTBEAT_TIMEOUT, DEFAULT_MAX_RECONNECT_INTERVAL, DEFAULT_ENABLE_EXPONENTIAL_BACKOFF, DEFAULT_MAX_RECONNECT_ATTEMPTS, } from './constants.js';
4
+ import { DEFAULT_AUTO_RECONNECT, DEFAULT_ENABLE_EXPONENTIAL_BACKOFF, DEFAULT_HEARTBEAT_INTERVAL, DEFAULT_HEARTBEAT_TIMEOUT, DEFAULT_MAX_RECONNECT_ATTEMPTS, DEFAULT_MAX_RECONNECT_INTERVAL, DEFAULT_RECONNECT_INTERVAL, } from './constants.js';
5
5
  /**
6
6
  * tcp连接管理器
7
7
  * 负责处理 TCP 连接、重连、超时检测等
@@ -35,8 +35,13 @@ export class TcpWrapper {
35
35
  pendingHeartbeat = false;
36
36
  /** 连续心跳超时次数 */
37
37
  heartbeatTimeoutCount = 0;
38
- /** 心跳响应识别函数 */
38
+ /** 心跳响应识别函数(同时检查 ping 和 pong) */
39
39
  heartbeatResponseChecker = (data) => {
40
+ // 检查 ping(发送的心跳)
41
+ if (data.length === 4 && data.toString('utf8') === 'ping') {
42
+ return true;
43
+ }
44
+ // 检查 pong(心跳响应)
40
45
  // data 是 Buffer 对象,需要转换为字符串比较
41
46
  // 心跳响应可能是 "pong"(4字节)或 "pong\n"(5字节,带换行符)
42
47
  if (data.length === 4) {
@@ -90,7 +95,6 @@ export class TcpWrapper {
90
95
  onError;
91
96
  /** 连接关闭回调(手动断开或重连失败时触发) */
92
97
  onClose;
93
- constructor() { }
94
98
  /**
95
99
  * 设置 Socket 事件监听
96
100
  */
@@ -103,6 +107,8 @@ export class TcpWrapper {
103
107
  if (this.connectStartTime > 0) {
104
108
  this.connectStartTime = 0; // 重置时间戳
105
109
  }
110
+ // 禁用 Nagle 算法,确保小包立即发送(不延迟合并)
111
+ this.socket?.setNoDelay(true);
106
112
  // 连接成功,重置所有计数器
107
113
  this.reconnectAttempts = 0;
108
114
  this.heartbeatTimeoutCount = 0;
@@ -121,7 +127,7 @@ export class TcpWrapper {
121
127
  }
122
128
  this.onData?.(data);
123
129
  });
124
- this.socket.on('close', (_hadError) => {
130
+ this.socket.on('close', () => {
125
131
  this.clearConnectTimeout();
126
132
  this.stopHeartbeat();
127
133
  this.cleanup();
@@ -206,7 +212,8 @@ export class TcpWrapper {
206
212
  return;
207
213
  }
208
214
  // 增加重连计数
209
- this.reconnectAttempts++;
215
+ this.reconnectAttempts += 1;
216
+ // 此时已经通过上面的检查,确保 address、port、connectOptions 都不为 null
210
217
  try {
211
218
  this.connect(this.address, this.port, this.connectOptions);
212
219
  }
@@ -252,7 +259,7 @@ export class TcpWrapper {
252
259
  this.clearHeartbeatTimeout();
253
260
  this.heartbeatTimeout = setTimeout(() => {
254
261
  if (this.pendingHeartbeat) {
255
- this.heartbeatTimeoutCount++;
262
+ this.heartbeatTimeoutCount += 1;
256
263
  // 只有连续2次心跳超时才清理socket
257
264
  if (this.heartbeatTimeoutCount >= 2) {
258
265
  this.connectionActive = false;
@@ -286,48 +293,88 @@ export class TcpWrapper {
286
293
  setConnectTimeout() {
287
294
  this.clearConnectTimeout();
288
295
  this.connectTimeout = setTimeout(() => {
289
- if (this.socket && !this.socket.destroyed) {
290
- this.handshakeTimeoutAttempts++;
291
- // 如果未达到最大尝试次数,重试连接
292
- if (this.handshakeTimeoutAttempts < this.maxHandshakeTimeoutAttempts) {
293
- // 清理当前socket
294
- this.socket.destroy();
295
- this.socket = null;
296
- // 计算重试延迟(使用指数退避)
297
- const retryDelay = this.calculateHandshakeRetryInterval();
298
- // 重新尝试连接
299
- if (this.address && this.port && this.connectOptions) {
300
- setTimeout(() => {
301
- if (this.connectionActive && !this.isConnected()) {
302
- try {
303
- // 重新创建连接
304
- this.socket = net.createConnection({
305
- host: this.address,
306
- port: this.port,
307
- keepAlive: true,
308
- keepAliveInitialDelay: 1000,
309
- });
310
- // 重新设置超时和事件
311
- this.setConnectTimeout();
312
- this.setupSocketEvents();
313
- }
314
- catch (error) {
315
- this.onError?.(error);
316
- }
317
- }
318
- }, retryDelay);
319
- }
320
- }
321
- else {
322
- // 超过最大尝试次数,断开连接
323
- this.connectionActive = false;
324
- this.socket.destroy();
325
- this.onError?.(new Error(`Connection timeout after ${this.maxHandshakeTimeoutAttempts} attempts`));
326
- this.onClose?.();
327
- }
328
- }
296
+ this.handleHandshakeTimeout();
329
297
  }, 1000);
330
298
  }
299
+ /**
300
+ * 握手超时处理入口
301
+ * 提取为独立方法以降低 setConnectTimeout 的复杂度
302
+ */
303
+ handleHandshakeTimeout() {
304
+ // socket 已销毁或不存在时无需处理
305
+ if (!this.socket || this.socket.destroyed) {
306
+ return;
307
+ }
308
+ this.handshakeTimeoutAttempts += 1;
309
+ if (this.hasRemainingHandshakeAttempts()) {
310
+ this.retryHandshakeConnection();
311
+ }
312
+ else {
313
+ this.handleHandshakeFailure();
314
+ }
315
+ }
316
+ /**
317
+ * 是否还有剩余的握手重试次数
318
+ */
319
+ hasRemainingHandshakeAttempts() {
320
+ return this.handshakeTimeoutAttempts < this.maxHandshakeTimeoutAttempts;
321
+ }
322
+ /**
323
+ * 执行握手重试流程:销毁当前 socket、计算重试间隔并尝试重新连接
324
+ */
325
+ retryHandshakeConnection() {
326
+ // 清理当前 socket
327
+ this.socket?.destroy();
328
+ this.socket = null;
329
+ // 计算重试延迟(使用指数退避)
330
+ const retryDelay = this.calculateHandshakeRetryInterval();
331
+ // 保存连接信息到局部变量,避免在异步回调中使用可变的实例属性
332
+ const address = this.address;
333
+ const port = this.port;
334
+ const connectOptions = this.connectOptions;
335
+ if (!address || !port || !connectOptions) {
336
+ return;
337
+ }
338
+ this.scheduleHandshakeReconnect(address, port, retryDelay);
339
+ }
340
+ /**
341
+ * 安排一次新的握手重连尝试
342
+ */
343
+ scheduleHandshakeReconnect(address, port, retryDelay) {
344
+ setTimeout(() => {
345
+ if (!this.connectionActive || this.isConnected()) {
346
+ return;
347
+ }
348
+ try {
349
+ this.socket = new net.Socket({
350
+ readableHighWaterMark: 1024 * 1024, // 1024KB 读取缓冲区
351
+ writableHighWaterMark: 1024 * 1024, // 1024KB 写入缓冲区
352
+ });
353
+ // 连接到服务器
354
+ this.socket.connect({
355
+ host: address,
356
+ port,
357
+ keepAlive: true,
358
+ keepAliveInitialDelay: 1000,
359
+ });
360
+ // 重新设置超时和事件
361
+ this.setConnectTimeout();
362
+ this.setupSocketEvents();
363
+ }
364
+ catch (error) {
365
+ this.onError?.(error);
366
+ }
367
+ }, retryDelay);
368
+ }
369
+ /**
370
+ * 握手多次超时后的失败处理
371
+ */
372
+ handleHandshakeFailure() {
373
+ this.connectionActive = false;
374
+ this.socket?.destroy();
375
+ this.onError?.(new Error(`Connection timeout after ${this.maxHandshakeTimeoutAttempts} attempts`));
376
+ this.onClose?.();
377
+ }
331
378
  /**
332
379
  * 清除连接超时定时器
333
380
  */
@@ -396,12 +443,16 @@ export class TcpWrapper {
396
443
  }
397
444
  // 记录连接开始时间(用于计算握手时间)
398
445
  this.connectStartTime = Date.now();
399
- // 创建 TCP 连接
400
- this.socket = net.createConnection({
446
+ this.socket = new net.Socket({
447
+ readableHighWaterMark: 1024 * 1024, // 1024KB 读取缓冲区
448
+ writableHighWaterMark: 1024 * 1024, // 1024KB 写入缓冲区
449
+ });
450
+ // 连接到服务器
451
+ this.socket.connect({
401
452
  host,
402
453
  port,
403
454
  keepAlive: true,
404
- keepAliveInitialDelay: 1000, // TCP keepalive 初始延迟时间(毫秒)
455
+ keepAliveInitialDelay: 1000,
405
456
  });
406
457
  // 设置连接超时( 1000ms)
407
458
  this.setConnectTimeout();
@@ -450,6 +501,12 @@ export class TcpWrapper {
450
501
  setHeartbeatResponseChecker(checker) {
451
502
  this.heartbeatResponseChecker = checker || ((data) => data.toString() === 'pong');
452
503
  }
504
+ /**
505
+ * 获取心跳响应识别函数
506
+ */
507
+ getHeartbeatResponseChecker() {
508
+ return this.heartbeatResponseChecker;
509
+ }
453
510
  /**
454
511
  * 获取当前连接地址
455
512
  */
@@ -469,4 +526,3 @@ export class TcpWrapper {
469
526
  return this.reconnectAttempts;
470
527
  }
471
528
  }
472
- //# sourceMappingURL=tcpWrapper.js.map
@@ -229,4 +229,3 @@ export interface DiscoveryServiceOptions {
229
229
  /** 服务协议 */
230
230
  protocol?: string;
231
231
  }
232
- //# sourceMappingURL=types.d.ts.map
@@ -10,4 +10,3 @@ export var QueueOverflowStrategy;
10
10
  /** 拒绝新数据并触发错误 */
11
11
  QueueOverflowStrategy["REJECT"] = "reject";
12
12
  })(QueueOverflowStrategy || (QueueOverflowStrategy = {}));
13
- //# sourceMappingURL=types.js.map
@@ -11,4 +11,3 @@ export declare function parseHost(url: string): string | null;
11
11
  * @param url 连接地址
12
12
  */
13
13
  export declare function parsePort(url: string): number | null;
14
- //# sourceMappingURL=utils.d.ts.map
@@ -44,4 +44,3 @@ export function parsePort(url) {
44
44
  return null;
45
45
  }
46
46
  }
47
- //# sourceMappingURL=utils.js.map