@pixelhue/event-controller-sdk 0.0.1

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 (62) hide show
  1. package/README.md +76 -0
  2. package/dist/index.d.ts +17 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +18 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/packages/tcp/ConnectManager.d.ts +66 -0
  7. package/dist/packages/tcp/ConnectManager.d.ts.map +1 -0
  8. package/dist/packages/tcp/ConnectManager.js +176 -0
  9. package/dist/packages/tcp/ConnectManager.js.map +1 -0
  10. package/dist/packages/tcp/QueueManager.d.ts +41 -0
  11. package/dist/packages/tcp/QueueManager.d.ts.map +1 -0
  12. package/dist/packages/tcp/QueueManager.js +102 -0
  13. package/dist/packages/tcp/QueueManager.js.map +1 -0
  14. package/dist/packages/tcp/SocketWrapper.d.ts +106 -0
  15. package/dist/packages/tcp/SocketWrapper.d.ts.map +1 -0
  16. package/dist/packages/tcp/SocketWrapper.js +281 -0
  17. package/dist/packages/tcp/SocketWrapper.js.map +1 -0
  18. package/dist/packages/tcp/constants.d.ts +25 -0
  19. package/dist/packages/tcp/constants.d.ts.map +1 -0
  20. package/dist/packages/tcp/constants.js +27 -0
  21. package/dist/packages/tcp/constants.js.map +1 -0
  22. package/dist/packages/tcp/demo.d.ts +3 -0
  23. package/dist/packages/tcp/demo.d.ts.map +1 -0
  24. package/dist/packages/tcp/demo.js +164 -0
  25. package/dist/packages/tcp/demo.js.map +1 -0
  26. package/dist/packages/tcp/discoveryService.d.ts +42 -0
  27. package/dist/packages/tcp/discoveryService.d.ts.map +1 -0
  28. package/dist/packages/tcp/discoveryService.js +166 -0
  29. package/dist/packages/tcp/discoveryService.js.map +1 -0
  30. package/dist/packages/tcp/protocolHandler.d.ts +64 -0
  31. package/dist/packages/tcp/protocolHandler.d.ts.map +1 -0
  32. package/dist/packages/tcp/protocolHandler.js +96 -0
  33. package/dist/packages/tcp/protocolHandler.js.map +1 -0
  34. package/dist/packages/tcp/tcpWrapper.d.ts +168 -0
  35. package/dist/packages/tcp/tcpWrapper.d.ts.map +1 -0
  36. package/dist/packages/tcp/tcpWrapper.js +472 -0
  37. package/dist/packages/tcp/tcpWrapper.js.map +1 -0
  38. package/dist/packages/tcp/test-build-parse-debug.d.ts +2 -0
  39. package/dist/packages/tcp/test-build-parse-debug.d.ts.map +1 -0
  40. package/dist/packages/tcp/test-build-parse-debug.js +73 -0
  41. package/dist/packages/tcp/test-build-parse-debug.js.map +1 -0
  42. package/dist/packages/tcp/test-packet-split.d.ts +43 -0
  43. package/dist/packages/tcp/test-packet-split.d.ts.map +1 -0
  44. package/dist/packages/tcp/test-packet-split.js +417 -0
  45. package/dist/packages/tcp/test-packet-split.js.map +1 -0
  46. package/dist/packages/tcp/test-protocol-handler.d.ts +6 -0
  47. package/dist/packages/tcp/test-protocol-handler.d.ts.map +1 -0
  48. package/dist/packages/tcp/test-protocol-handler.js +225 -0
  49. package/dist/packages/tcp/test-protocol-handler.js.map +1 -0
  50. package/dist/packages/tcp/test-server.d.ts +54 -0
  51. package/dist/packages/tcp/test-server.d.ts.map +1 -0
  52. package/dist/packages/tcp/test-server.js +412 -0
  53. package/dist/packages/tcp/test-server.js.map +1 -0
  54. package/dist/packages/tcp/types.d.ts +232 -0
  55. package/dist/packages/tcp/types.d.ts.map +1 -0
  56. package/dist/packages/tcp/types.js +13 -0
  57. package/dist/packages/tcp/types.js.map +1 -0
  58. package/dist/packages/tcp/utils.d.ts +14 -0
  59. package/dist/packages/tcp/utils.d.ts.map +1 -0
  60. package/dist/packages/tcp/utils.js +47 -0
  61. package/dist/packages/tcp/utils.js.map +1 -0
  62. package/package.json +82 -0
@@ -0,0 +1,412 @@
1
+ // ALL_CODE_LINE: 462
2
+ // AI_CODE_LINE: 462
3
+ import * as net from 'net';
4
+ import { ProtocolHandler } from './protocolHandler.js';
5
+ class TestTCPServer {
6
+ server = null;
7
+ clients = new Map();
8
+ port;
9
+ host;
10
+ protocolHandler;
11
+ /** 预设的测试数据包(十六进制) */
12
+ testDataPacket;
13
+ constructor(port = 8080, host = '127.0.0.1') {
14
+ this.port = port;
15
+ this.host = host;
16
+ this.protocolHandler = new ProtocolHandler();
17
+ // 标准测试数据包(使用 ProtocolHandler.build 生成)
18
+ // 包含完整的 Frame Head、Request Head 和 TLV 数据,符合协议规范
19
+ this.testDataPacket = Buffer.from('4E4F56410101000000000000000000005B0079796B20010000000100000000001030500000001D007B22736571223A302C22736E223A22222C22736F75726365223A22227D01000100000024007B226D657373616765223A2248656C6C6F2066726F6D207465737420736572766572227D', 'hex');
20
+ }
21
+ /**
22
+ * 处理心跳(ping/pong)
23
+ */
24
+ handleHeartbeat(data, socket, clientId) {
25
+ // 心跳数据是纯文本 "ping"(4字节),需要精确匹配
26
+ // 如果数据长度正好是4字节且内容是"ping",则认为是心跳
27
+ if (data.length === 4) {
28
+ const dataStr = data.toString('utf8');
29
+ if (dataStr === 'ping') {
30
+ // 记录接收到心跳
31
+ console.log(`💓 Received ping from ${clientId}`);
32
+ // 响应心跳
33
+ socket.write(Buffer.from('pong'), (err) => {
34
+ if (err) {
35
+ console.error(`❌ Error sending pong to ${clientId}:`, err.message);
36
+ }
37
+ else {
38
+ console.log(`💓 Sent pong to ${clientId}`);
39
+ }
40
+ });
41
+ return true;
42
+ }
43
+ }
44
+ // 如果数据长度小于协议最小长度(22字节),且不是心跳,可能是其他非协议数据
45
+ return false;
46
+ }
47
+ /**
48
+ * 处理协议数据
49
+ */
50
+ handleProtocolData(clientId, data) {
51
+ const client = this.clients.get(clientId);
52
+ if (!client)
53
+ return;
54
+ // 将新数据追加到接收缓冲区
55
+ if (!client.receiveBuffer || client.receiveBuffer.length === 0) {
56
+ client.receiveBuffer = data;
57
+ }
58
+ else {
59
+ client.receiveBuffer = Buffer.concat([client.receiveBuffer, data]);
60
+ }
61
+ // 提取所有完整协议包
62
+ const { packets, remaining, invalidPackets } = this.protocolHandler.extractAllCompletePackets(client.receiveBuffer);
63
+ // 处理校验失败的废包
64
+ if (invalidPackets.length > 0) {
65
+ console.log(`⚠️ Invalid packets detected from ${clientId}: ${invalidPackets.length} packets dropped`);
66
+ }
67
+ // 处理每个有效完整包
68
+ for (const packet of packets) {
69
+ try {
70
+ const parseResult = this.protocolHandler.parse(packet);
71
+ const { data: requestData, header, requestId, isResponse } = parseResult;
72
+ console.log(`📨 Received protocol packet from ${clientId}:`);
73
+ console.log(` RequestId: ${requestId}`);
74
+ console.log(` IsResponse: ${isResponse}`);
75
+ console.log(` Header:`, JSON.stringify(header, null, 2));
76
+ console.log(` Data:`, JSON.stringify(requestData, null, 2));
77
+ console.log(` Size: ${packet.length} bytes`);
78
+ console.log(` Raw Hex: ${packet.toString('hex').toUpperCase().substring(0, 100)}...\n`);
79
+ // 如果不是响应包,则发送响应(回发相同的数据)
80
+ if (!isResponse) {
81
+ console.log(`📤 Sending response back to ${clientId}...`);
82
+ this.sendResponse(clientId, requestId, requestData, header);
83
+ }
84
+ }
85
+ catch (error) {
86
+ console.error(`❌ Error parsing packet from ${clientId}:`, error);
87
+ }
88
+ }
89
+ // 更新接收缓冲区为剩余数据(半包数据保留)
90
+ client.receiveBuffer = remaining;
91
+ }
92
+ /**
93
+ * 发送响应
94
+ */
95
+ sendResponse(clientId, requestId, requestData, requestHeader) {
96
+ const client = this.clients.get(clientId);
97
+ if (!client || !client.socket.writable)
98
+ return;
99
+ // 构建响应数据(回发相同的数据,便于验证)
100
+ const responseData = requestData; // 直接回发原始数据
101
+ const responseHeader = requestHeader; // 使用相同的 header
102
+ // 构建协议响应包
103
+ const responsePacket = this.protocolHandler.build(responseData, responseHeader, {
104
+ seqId: requestId, // 使用相同的 requestId
105
+ isResponse: true, // 标记为响应包
106
+ });
107
+ // 发送响应
108
+ client.socket.write(responsePacket, (err) => {
109
+ if (err) {
110
+ console.error(`❌ Error sending response to ${clientId}:`, err.message);
111
+ }
112
+ else {
113
+ client.sentBytes += responsePacket.length;
114
+ console.log(`📤 Sent response to ${clientId}:`);
115
+ console.log(` RequestId: ${requestId}`);
116
+ console.log(` Response:`, responseData);
117
+ console.log(` Size: ${responsePacket.length} bytes\n`);
118
+ }
119
+ });
120
+ }
121
+ /**
122
+ * 启动服务器
123
+ */
124
+ start() {
125
+ this.server = net.createServer((socket) => {
126
+ const clientId = `${socket.remoteAddress}:${socket.remotePort}`;
127
+ console.log(`✅ Client connected: ${clientId}`);
128
+ // 保存客户端信息
129
+ this.clients.set(clientId, {
130
+ socket,
131
+ connectedAt: new Date(),
132
+ receivedBytes: 0,
133
+ sentBytes: 0,
134
+ receiveBuffer: null,
135
+ });
136
+ // 客户端连接后,20秒后自动发送预设的测试数据包(已注释,避免干扰测试)
137
+ // setTimeout(() => {
138
+ // console.log(`⏰ 20 seconds elapsed, sending test data packet to ${clientId}...`);
139
+ // this.sendTestDataPacket(clientId);
140
+ // }, 20000); // 延迟20秒发送
141
+ // 客户端连接后,自动发送预设的测试数据包(可选,通过环境变量控制)(已注释)
142
+ // 可以通过环境变量 AUTO_SEND_TEST_DATA 控制是否自动发送
143
+ // if (process.env.AUTO_SEND_TEST_DATA === 'true') {
144
+ // setTimeout(() => {
145
+ // this.sendTestDataPacket(clientId);
146
+ // }, 1000); // 延迟1秒发送,确保连接稳定
147
+ // }
148
+ // 接收数据
149
+ socket.on('data', (data) => {
150
+ const client = this.clients.get(clientId);
151
+ if (client) {
152
+ client.receivedBytes += data.length;
153
+ }
154
+ // 先检查是否是心跳(必须在处理协议数据之前)
155
+ // 心跳数据是纯文本 "ping",不应该被当作协议数据包处理
156
+ if (this.handleHeartbeat(data, socket, clientId)) {
157
+ // 心跳已处理,不继续处理(静默处理,不输出日志以避免日志过多)
158
+ return;
159
+ }
160
+ // 注意:不要在这里过滤小段数据!
161
+ // 即使是小段数据(小于22字节),也应该传递给 handleProtocolData
162
+ // 因为协议处理器需要这些数据来组装半包
163
+ // handleProtocolData 内部会维护接收缓冲区,只有当缓冲区中有完整包时才会处理
164
+ // 处理协议数据(包括半包数据)
165
+ this.handleProtocolData(clientId, data);
166
+ });
167
+ // 客户端断开连接
168
+ socket.on('close', (_hadError) => {
169
+ const client = this.clients.get(clientId);
170
+ if (client) {
171
+ const duration = Date.now() - client.connectedAt.getTime();
172
+ console.log(`🔌 Client disconnected: ${clientId}`);
173
+ console.log(` Duration: ${(duration / 1000).toFixed(2)}s`);
174
+ console.log(` Received: ${client.receivedBytes} bytes`);
175
+ console.log(` Sent: ${client.sentBytes} bytes\n`);
176
+ }
177
+ this.clients.delete(clientId);
178
+ });
179
+ // 错误处理
180
+ socket.on('error', (err) => {
181
+ console.error(`❌ Socket error for ${clientId}:`, err.message);
182
+ });
183
+ });
184
+ // 服务器错误处理
185
+ this.server.on('error', (err) => {
186
+ console.error('❌ Server error:', err.message);
187
+ if (err.code === 'EADDRINUSE') {
188
+ console.error(` Port ${this.port} is already in use.`);
189
+ console.error(' Please use a different port or stop the existing server.\n');
190
+ }
191
+ });
192
+ // 开始监听
193
+ this.server.listen(this.port, this.host, () => {
194
+ console.log('🚀 TCP Test Server started (Uniform Protocol)');
195
+ console.log(` Listening on ${this.host}:${this.port}`);
196
+ console.log(` Protocol: Uniform Protocol`);
197
+ console.log(` Heartbeat: ping/pong`);
198
+ if (process.env.AUTO_SEND_TEST_DATA === 'true') {
199
+ console.log(` Auto-send test data: Enabled (will send after client connects)`);
200
+ }
201
+ console.log(` Ready to accept connections...\n`);
202
+ });
203
+ }
204
+ /**
205
+ * 停止服务器
206
+ */
207
+ stop() {
208
+ if (this.server) {
209
+ console.log('\n🛑 Stopping server...');
210
+ // 关闭所有客户端连接
211
+ for (const [clientId, client] of this.clients.entries()) {
212
+ console.log(` Closing connection: ${clientId}`);
213
+ client.socket.destroy();
214
+ }
215
+ this.clients.clear();
216
+ // 关闭服务器
217
+ this.server.close(() => {
218
+ console.log(' Server stopped\n');
219
+ });
220
+ this.server = null;
221
+ }
222
+ }
223
+ /**
224
+ * 获取连接的客户端数量
225
+ */
226
+ getClientCount() {
227
+ return this.clients.size;
228
+ }
229
+ /**
230
+ * 向所有客户端发送测试数据(使用 Uniform Protocol)
231
+ */
232
+ broadcastTestData(data, header = {}) {
233
+ if (this.clients.size === 0) {
234
+ console.log('⚠️ No clients connected');
235
+ return;
236
+ }
237
+ console.log(`📤 Broadcasting test data to ${this.clients.size} client(s)...`);
238
+ // 构建协议包
239
+ const testPacket = this.protocolHandler.build(data, header, {
240
+ isResponse: false,
241
+ });
242
+ for (const [clientId, client] of this.clients.entries()) {
243
+ client.socket.write(testPacket, (err) => {
244
+ if (err) {
245
+ console.error(`❌ Error broadcasting to ${clientId}:`, err.message);
246
+ }
247
+ else {
248
+ client.sentBytes += testPacket.length;
249
+ console.log(` Sent to ${clientId}: ${JSON.stringify(data)}`);
250
+ }
251
+ });
252
+ }
253
+ console.log('');
254
+ }
255
+ /**
256
+ * 断开所有客户端连接(模拟服务器断开)
257
+ */
258
+ disconnectAllClients() {
259
+ console.log(`🔌 Disconnecting all ${this.clients.size} client(s)...\n`);
260
+ for (const client of this.clients.values()) {
261
+ client.socket.destroy();
262
+ }
263
+ this.clients.clear();
264
+ }
265
+ /**
266
+ * 向指定客户端发送预设的测试数据包(原始十六进制数据)
267
+ * @param clientId 客户端ID,如果为null则向所有客户端发送
268
+ */
269
+ sendTestDataPacket(clientId) {
270
+ if (clientId) {
271
+ // 向指定客户端发送
272
+ const client = this.clients.get(clientId);
273
+ if (!client || !client.socket.writable) {
274
+ console.log(`⚠️ Client ${clientId} not found or not writable`);
275
+ return;
276
+ }
277
+ client.socket.write(this.testDataPacket, (err) => {
278
+ if (err) {
279
+ console.error(`❌ Error sending test data packet to ${clientId}:`, err.message);
280
+ }
281
+ else {
282
+ client.sentBytes += this.testDataPacket.length;
283
+ console.log(`📤 Sent test data packet to ${clientId}:`);
284
+ console.log(` Hex: ${this.testDataPacket.toString('hex').toUpperCase()}`);
285
+ console.log(` Size: ${this.testDataPacket.length} bytes\n`);
286
+ }
287
+ });
288
+ }
289
+ else {
290
+ // 向所有客户端发送
291
+ if (this.clients.size === 0) {
292
+ console.log('⚠️ No clients connected');
293
+ return;
294
+ }
295
+ console.log(`📤 Broadcasting test data packet to ${this.clients.size} client(s)...`);
296
+ for (const [id, client] of this.clients.entries()) {
297
+ if (client.socket.writable) {
298
+ client.socket.write(this.testDataPacket, (err) => {
299
+ if (err) {
300
+ console.error(`❌ Error sending test data packet to ${id}:`, err.message);
301
+ }
302
+ else {
303
+ client.sentBytes += this.testDataPacket.length;
304
+ console.log(` Sent to ${id}: ${this.testDataPacket.length} bytes`);
305
+ }
306
+ });
307
+ }
308
+ }
309
+ console.log(` Hex: ${this.testDataPacket.toString('hex').toUpperCase()}\n`);
310
+ }
311
+ }
312
+ /**
313
+ * 向所有客户端发送原始十六进制数据
314
+ * @param hexString 十六进制字符串(空格分隔或连续)
315
+ */
316
+ sendRawHexData(hexString, clientId) {
317
+ // 移除空格并转换为Buffer
318
+ const hex = hexString.replace(/\s+/g, '');
319
+ let data;
320
+ try {
321
+ data = Buffer.from(hex, 'hex');
322
+ }
323
+ catch (error) {
324
+ console.error(`❌ Invalid hex string: ${error}`);
325
+ return;
326
+ }
327
+ if (clientId) {
328
+ // 向指定客户端发送
329
+ const client = this.clients.get(clientId);
330
+ if (!client || !client.socket.writable) {
331
+ console.log(`⚠️ Client ${clientId} not found or not writable`);
332
+ return;
333
+ }
334
+ client.socket.write(data, (err) => {
335
+ if (err) {
336
+ console.error(`❌ Error sending raw hex data to ${clientId}:`, err.message);
337
+ }
338
+ else {
339
+ client.sentBytes += data.length;
340
+ console.log(`📤 Sent raw hex data to ${clientId}:`);
341
+ console.log(` Hex: ${data.toString('hex').toUpperCase()}`);
342
+ console.log(` Size: ${data.length} bytes\n`);
343
+ }
344
+ });
345
+ }
346
+ else {
347
+ // 向所有客户端发送
348
+ if (this.clients.size === 0) {
349
+ console.log('⚠️ No clients connected');
350
+ return;
351
+ }
352
+ console.log(`📤 Broadcasting raw hex data to ${this.clients.size} client(s)...`);
353
+ for (const [id, client] of this.clients.entries()) {
354
+ if (client.socket.writable) {
355
+ client.socket.write(data, (err) => {
356
+ if (err) {
357
+ console.error(`❌ Error sending raw hex data to ${id}:`, err.message);
358
+ }
359
+ else {
360
+ client.sentBytes += data.length;
361
+ console.log(` Sent to ${id}: ${data.length} bytes`);
362
+ }
363
+ });
364
+ }
365
+ }
366
+ console.log(` Hex: ${data.toString('hex').toUpperCase()}\n`);
367
+ }
368
+ }
369
+ }
370
+ // 主函数
371
+ function main() {
372
+ const port = parseInt(process.env.PORT || '8080', 10);
373
+ const host = process.env.HOST || '127.0.0.1';
374
+ const server = new TestTCPServer(port, host);
375
+ // 启动服务器
376
+ server.start();
377
+ // 处理 Ctrl+C 优雅退出
378
+ const exitHandler = () => {
379
+ console.log('\n');
380
+ server.stop();
381
+ process.exit(0);
382
+ };
383
+ process.on('SIGINT', exitHandler);
384
+ process.on('SIGTERM', exitHandler);
385
+ // 可选:定期发送预设的测试数据包(取消注释以启用)
386
+ // const testDataInterval = setInterval(() => {
387
+ // if (server.getClientCount() > 0) {
388
+ // server.sendTestDataPacket(); // 发送预设的测试数据包
389
+ // }
390
+ // }, 10000); // 每10秒发送一次
391
+ // 可选:定期发送协议格式的测试数据(取消注释以启用)
392
+ // const protocolTestInterval = setInterval(() => {
393
+ // if (server.getClientCount() > 0) {
394
+ // server.broadcastTestData(
395
+ // { message: 'Broadcast test', timestamp: Date.now() },
396
+ // { type: 'broadcast', version: '1.0' }
397
+ // );
398
+ // }
399
+ // }, 10000); // 每10秒发送一次
400
+ // 清理定时器(如果使用了)
401
+ // process.on('exit', () => {
402
+ // clearInterval(testDataInterval);
403
+ // clearInterval(protocolTestInterval);
404
+ // });
405
+ }
406
+ // 如果直接运行此文件,启动服务器
407
+ if (import.meta.url === `file://${process.argv[1]?.replace(/\\/g, '/')}` ||
408
+ process.argv[1]?.includes('test-server.ts')) {
409
+ main();
410
+ }
411
+ export { TestTCPServer };
412
+ //# sourceMappingURL=test-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-server.js","sourceRoot":"","sources":["../../../src/packages/tcp/test-server.ts"],"names":[],"mappings":"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","sourcesContent":["// ALL_CODE_LINE: 462\r\n// AI_CODE_LINE: 462\r\n\r\nimport * as net from 'net';\r\nimport { ProtocolHandler } from './protocolHandler.js';\r\n\r\n/**\r\n * 支持 Uniform Protocol 的 TCP 测试服务器\r\n * 用于测试 SocketWrapper 的功能\r\n *\r\n * 功能:\r\n * - 接收客户端连接\r\n * - 处理 Uniform Protocol 格式的数据包\r\n * - 解析请求并发送响应(使用 Uniform Protocol 格式)\r\n * - 处理心跳(ping/pong)\r\n * - 可以主动发送测试数据\r\n * - 支持模拟断开连接\r\n *\r\n * 使用方式:\r\n * npm run test-server\r\n * 或\r\n * npx tsx src/packages/tcp/test-server.ts\r\n */\r\n\r\ninterface ClientInfo {\r\n\tsocket: net.Socket;\r\n\tconnectedAt: Date;\r\n\treceivedBytes: number;\r\n\tsentBytes: number;\r\n\treceiveBuffer: Buffer | null;\r\n}\r\n\r\nclass TestTCPServer {\r\n\tprivate server: net.Server | null = null;\r\n\tprivate clients: Map<string, ClientInfo> = new Map();\r\n\tprivate port: number;\r\n\tprivate host: string;\r\n\tprivate protocolHandler: ProtocolHandler;\r\n\t/** 预设的测试数据包(十六进制) */\r\n\tprivate readonly testDataPacket: Buffer;\r\n\r\n\tconstructor(port: number = 8080, host: string = '127.0.0.1') {\r\n\t\tthis.port = port;\r\n\t\tthis.host = host;\r\n\t\tthis.protocolHandler = new ProtocolHandler();\r\n\t\t// 标准测试数据包(使用 ProtocolHandler.build 生成)\r\n\t\t// 包含完整的 Frame Head、Request Head 和 TLV 数据,符合协议规范\r\n\t\tthis.testDataPacket = Buffer.from(\r\n\t\t\t'4E4F56410101000000000000000000005B0079796B20010000000100000000001030500000001D007B22736571223A302C22736E223A22222C22736F75726365223A22227D01000100000024007B226D657373616765223A2248656C6C6F2066726F6D207465737420736572766572227D',\r\n\t\t\t'hex'\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * 处理心跳(ping/pong)\r\n\t */\r\n\tprivate handleHeartbeat(data: Buffer, socket: net.Socket, clientId: string): boolean {\r\n\t\t// 心跳数据是纯文本 \"ping\"(4字节),需要精确匹配\r\n\t\t// 如果数据长度正好是4字节且内容是\"ping\",则认为是心跳\r\n\t\tif (data.length === 4) {\r\n\t\t\tconst dataStr = data.toString('utf8');\r\n\t\t\tif (dataStr === 'ping') {\r\n\t\t\t\t// 记录接收到心跳\r\n\t\t\t\tconsole.log(`💓 Received ping from ${clientId}`);\r\n\t\t\t\t// 响应心跳\r\n\t\t\t\tsocket.write(Buffer.from('pong'), (err) => {\r\n\t\t\t\t\tif (err) {\r\n\t\t\t\t\t\tconsole.error(`❌ Error sending pong to ${clientId}:`, err.message);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tconsole.log(`💓 Sent pong to ${clientId}`);\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t}\r\n\t\t// 如果数据长度小于协议最小长度(22字节),且不是心跳,可能是其他非协议数据\r\n\t\treturn false;\r\n\t}\r\n\r\n\t/**\r\n\t * 处理协议数据\r\n\t */\r\n\tprivate handleProtocolData(clientId: string, data: Buffer): void {\r\n\t\tconst client = this.clients.get(clientId);\r\n\t\tif (!client) return;\r\n\r\n\t\t// 将新数据追加到接收缓冲区\r\n\t\tif (!client.receiveBuffer || client.receiveBuffer.length === 0) {\r\n\t\t\tclient.receiveBuffer = data;\r\n\t\t} else {\r\n\t\t\tclient.receiveBuffer = Buffer.concat([client.receiveBuffer, data]);\r\n\t\t}\r\n\r\n\t\t// 提取所有完整协议包\r\n\t\tconst { packets, remaining, invalidPackets } = this.protocolHandler.extractAllCompletePackets(client.receiveBuffer);\r\n\r\n\t\t// 处理校验失败的废包\r\n\t\tif (invalidPackets.length > 0) {\r\n\t\t\tconsole.log(`⚠️ Invalid packets detected from ${clientId}: ${invalidPackets.length} packets dropped`);\r\n\t\t}\r\n\r\n\t\t// 处理每个有效完整包\r\n\t\tfor (const packet of packets) {\r\n\t\t\ttry {\r\n\t\t\t\tconst parseResult = this.protocolHandler.parse(packet);\r\n\t\t\t\tconst { data: requestData, header, requestId, isResponse } = parseResult;\r\n\r\n\t\t\t\tconsole.log(`📨 Received protocol packet from ${clientId}:`);\r\n\t\t\t\tconsole.log(` RequestId: ${requestId}`);\r\n\t\t\t\tconsole.log(` IsResponse: ${isResponse}`);\r\n\t\t\t\tconsole.log(` Header:`, JSON.stringify(header, null, 2));\r\n\t\t\t\tconsole.log(` Data:`, JSON.stringify(requestData, null, 2));\r\n\t\t\t\tconsole.log(` Size: ${packet.length} bytes`);\r\n\t\t\t\tconsole.log(` Raw Hex: ${packet.toString('hex').toUpperCase().substring(0, 100)}...\\n`);\r\n\r\n\t\t\t\t// 如果不是响应包,则发送响应(回发相同的数据)\r\n\t\t\t\tif (!isResponse) {\r\n\t\t\t\t\tconsole.log(`📤 Sending response back to ${clientId}...`);\r\n\t\t\t\t\tthis.sendResponse(clientId, requestId, requestData, header);\r\n\t\t\t\t}\r\n\t\t\t} catch (error) {\r\n\t\t\t\tconsole.error(`❌ Error parsing packet from ${clientId}:`, error);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// 更新接收缓冲区为剩余数据(半包数据保留)\r\n\t\tclient.receiveBuffer = remaining;\r\n\t}\r\n\r\n\t/**\r\n\t * 发送响应\r\n\t */\r\n\tprivate sendResponse(clientId: string, requestId: number, requestData: any, requestHeader: any): void {\r\n\t\tconst client = this.clients.get(clientId);\r\n\t\tif (!client || !client.socket.writable) return;\r\n\r\n\t\t// 构建响应数据(回发相同的数据,便于验证)\r\n\t\tconst responseData = requestData; // 直接回发原始数据\r\n\r\n\t\tconst responseHeader = requestHeader; // 使用相同的 header\r\n\r\n\t\t// 构建协议响应包\r\n\t\tconst responsePacket = this.protocolHandler.build(responseData, responseHeader, {\r\n\t\t\tseqId: requestId, // 使用相同的 requestId\r\n\t\t\tisResponse: true, // 标记为响应包\r\n\t\t});\r\n\r\n\t\t// 发送响应\r\n\t\tclient.socket.write(responsePacket, (err) => {\r\n\t\t\tif (err) {\r\n\t\t\t\tconsole.error(`❌ Error sending response to ${clientId}:`, err.message);\r\n\t\t\t} else {\r\n\t\t\t\tclient.sentBytes += responsePacket.length;\r\n\t\t\t\tconsole.log(`📤 Sent response to ${clientId}:`);\r\n\t\t\t\tconsole.log(` RequestId: ${requestId}`);\r\n\t\t\t\tconsole.log(` Response:`, responseData);\r\n\t\t\t\tconsole.log(` Size: ${responsePacket.length} bytes\\n`);\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * 启动服务器\r\n\t */\r\n\tstart(): void {\r\n\t\tthis.server = net.createServer((socket) => {\r\n\t\t\tconst clientId = `${socket.remoteAddress}:${socket.remotePort}`;\r\n\t\t\tconsole.log(`✅ Client connected: ${clientId}`);\r\n\r\n\t\t\t// 保存客户端信息\r\n\t\t\tthis.clients.set(clientId, {\r\n\t\t\t\tsocket,\r\n\t\t\t\tconnectedAt: new Date(),\r\n\t\t\t\treceivedBytes: 0,\r\n\t\t\t\tsentBytes: 0,\r\n\t\t\t\treceiveBuffer: null,\r\n\t\t\t});\r\n\r\n\t\t\t// 客户端连接后,20秒后自动发送预设的测试数据包(已注释,避免干扰测试)\r\n\t\t\t// setTimeout(() => {\r\n\t\t\t// \tconsole.log(`⏰ 20 seconds elapsed, sending test data packet to ${clientId}...`);\r\n\t\t\t// \tthis.sendTestDataPacket(clientId);\r\n\t\t\t// }, 20000); // 延迟20秒发送\r\n\r\n\t\t\t// 客户端连接后,自动发送预设的测试数据包(可选,通过环境变量控制)(已注释)\r\n\t\t\t// 可以通过环境变量 AUTO_SEND_TEST_DATA 控制是否自动发送\r\n\t\t\t// if (process.env.AUTO_SEND_TEST_DATA === 'true') {\r\n\t\t\t// \tsetTimeout(() => {\r\n\t\t\t// \t\tthis.sendTestDataPacket(clientId);\r\n\t\t\t// \t}, 1000); // 延迟1秒发送,确保连接稳定\r\n\t\t\t// }\r\n\r\n\t\t\t// 接收数据\r\n\t\t\tsocket.on('data', (data: Buffer) => {\r\n\t\t\t\tconst client = this.clients.get(clientId);\r\n\t\t\t\tif (client) {\r\n\t\t\t\t\tclient.receivedBytes += data.length;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// 先检查是否是心跳(必须在处理协议数据之前)\r\n\t\t\t\t// 心跳数据是纯文本 \"ping\",不应该被当作协议数据包处理\r\n\t\t\t\tif (this.handleHeartbeat(data, socket, clientId)) {\r\n\t\t\t\t\t// 心跳已处理,不继续处理(静默处理,不输出日志以避免日志过多)\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// 注意:不要在这里过滤小段数据!\r\n\t\t\t\t// 即使是小段数据(小于22字节),也应该传递给 handleProtocolData\r\n\t\t\t\t// 因为协议处理器需要这些数据来组装半包\r\n\t\t\t\t// handleProtocolData 内部会维护接收缓冲区,只有当缓冲区中有完整包时才会处理\r\n\r\n\t\t\t\t// 处理协议数据(包括半包数据)\r\n\t\t\t\tthis.handleProtocolData(clientId, data);\r\n\t\t\t});\r\n\r\n\t\t\t// 客户端断开连接\r\n\t\t\tsocket.on('close', (_hadError) => {\r\n\t\t\t\tconst client = this.clients.get(clientId);\r\n\t\t\t\tif (client) {\r\n\t\t\t\t\tconst duration = Date.now() - client.connectedAt.getTime();\r\n\t\t\t\t\tconsole.log(`🔌 Client disconnected: ${clientId}`);\r\n\t\t\t\t\tconsole.log(` Duration: ${(duration / 1000).toFixed(2)}s`);\r\n\t\t\t\t\tconsole.log(` Received: ${client.receivedBytes} bytes`);\r\n\t\t\t\t\tconsole.log(` Sent: ${client.sentBytes} bytes\\n`);\r\n\t\t\t\t}\r\n\t\t\t\tthis.clients.delete(clientId);\r\n\t\t\t});\r\n\r\n\t\t\t// 错误处理\r\n\t\t\tsocket.on('error', (err) => {\r\n\t\t\t\tconsole.error(`❌ Socket error for ${clientId}:`, err.message);\r\n\t\t\t});\r\n\t\t});\r\n\r\n\t\t// 服务器错误处理\r\n\t\tthis.server.on('error', (err) => {\r\n\t\t\tconsole.error('❌ Server error:', err.message);\r\n\t\t\tif ((err as NodeJS.ErrnoException).code === 'EADDRINUSE') {\r\n\t\t\t\tconsole.error(` Port ${this.port} is already in use.`);\r\n\t\t\t\tconsole.error(' Please use a different port or stop the existing server.\\n');\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\t// 开始监听\r\n\t\tthis.server.listen(this.port, this.host, () => {\r\n\t\t\tconsole.log('🚀 TCP Test Server started (Uniform Protocol)');\r\n\t\t\tconsole.log(` Listening on ${this.host}:${this.port}`);\r\n\t\t\tconsole.log(` Protocol: Uniform Protocol`);\r\n\t\t\tconsole.log(` Heartbeat: ping/pong`);\r\n\t\t\tif (process.env.AUTO_SEND_TEST_DATA === 'true') {\r\n\t\t\t\tconsole.log(` Auto-send test data: Enabled (will send after client connects)`);\r\n\t\t\t}\r\n\t\t\tconsole.log(` Ready to accept connections...\\n`);\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * 停止服务器\r\n\t */\r\n\tstop(): void {\r\n\t\tif (this.server) {\r\n\t\t\tconsole.log('\\n🛑 Stopping server...');\r\n\r\n\t\t\t// 关闭所有客户端连接\r\n\t\t\tfor (const [clientId, client] of this.clients.entries()) {\r\n\t\t\t\tconsole.log(` Closing connection: ${clientId}`);\r\n\t\t\t\tclient.socket.destroy();\r\n\t\t\t}\r\n\t\t\tthis.clients.clear();\r\n\r\n\t\t\t// 关闭服务器\r\n\t\t\tthis.server.close(() => {\r\n\t\t\t\tconsole.log(' Server stopped\\n');\r\n\t\t\t});\r\n\t\t\tthis.server = null;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * 获取连接的客户端数量\r\n\t */\r\n\tgetClientCount(): number {\r\n\t\treturn this.clients.size;\r\n\t}\r\n\r\n\t/**\r\n\t * 向所有客户端发送测试数据(使用 Uniform Protocol)\r\n\t */\r\n\tbroadcastTestData(data: any, header: any = {}): void {\r\n\t\tif (this.clients.size === 0) {\r\n\t\t\tconsole.log('⚠️ No clients connected');\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconsole.log(`📤 Broadcasting test data to ${this.clients.size} client(s)...`);\r\n\r\n\t\t// 构建协议包\r\n\t\tconst testPacket = this.protocolHandler.build(data, header, {\r\n\t\t\tisResponse: false,\r\n\t\t});\r\n\r\n\t\tfor (const [clientId, client] of this.clients.entries()) {\r\n\t\t\tclient.socket.write(testPacket, (err) => {\r\n\t\t\t\tif (err) {\r\n\t\t\t\t\tconsole.error(`❌ Error broadcasting to ${clientId}:`, err.message);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tclient.sentBytes += testPacket.length;\r\n\t\t\t\t\tconsole.log(` Sent to ${clientId}: ${JSON.stringify(data)}`);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\t\tconsole.log('');\r\n\t}\r\n\r\n\t/**\r\n\t * 断开所有客户端连接(模拟服务器断开)\r\n\t */\r\n\tdisconnectAllClients(): void {\r\n\t\tconsole.log(`🔌 Disconnecting all ${this.clients.size} client(s)...\\n`);\r\n\t\tfor (const client of this.clients.values()) {\r\n\t\t\tclient.socket.destroy();\r\n\t\t}\r\n\t\tthis.clients.clear();\r\n\t}\r\n\r\n\t/**\r\n\t * 向指定客户端发送预设的测试数据包(原始十六进制数据)\r\n\t * @param clientId 客户端ID,如果为null则向所有客户端发送\r\n\t */\r\n\tsendTestDataPacket(clientId?: string | null): void {\r\n\t\tif (clientId) {\r\n\t\t\t// 向指定客户端发送\r\n\t\t\tconst client = this.clients.get(clientId);\r\n\t\t\tif (!client || !client.socket.writable) {\r\n\t\t\t\tconsole.log(`⚠️ Client ${clientId} not found or not writable`);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tclient.socket.write(this.testDataPacket, (err) => {\r\n\t\t\t\tif (err) {\r\n\t\t\t\t\tconsole.error(`❌ Error sending test data packet to ${clientId}:`, err.message);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tclient.sentBytes += this.testDataPacket.length;\r\n\t\t\t\t\tconsole.log(`📤 Sent test data packet to ${clientId}:`);\r\n\t\t\t\t\tconsole.log(` Hex: ${this.testDataPacket.toString('hex').toUpperCase()}`);\r\n\t\t\t\t\tconsole.log(` Size: ${this.testDataPacket.length} bytes\\n`);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t} else {\r\n\t\t\t// 向所有客户端发送\r\n\t\t\tif (this.clients.size === 0) {\r\n\t\t\t\tconsole.log('⚠️ No clients connected');\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconsole.log(`📤 Broadcasting test data packet to ${this.clients.size} client(s)...`);\r\n\t\t\tfor (const [id, client] of this.clients.entries()) {\r\n\t\t\t\tif (client.socket.writable) {\r\n\t\t\t\t\tclient.socket.write(this.testDataPacket, (err) => {\r\n\t\t\t\t\t\tif (err) {\r\n\t\t\t\t\t\t\tconsole.error(`❌ Error sending test data packet to ${id}:`, err.message);\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tclient.sentBytes += this.testDataPacket.length;\r\n\t\t\t\t\t\t\tconsole.log(` Sent to ${id}: ${this.testDataPacket.length} bytes`);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tconsole.log(` Hex: ${this.testDataPacket.toString('hex').toUpperCase()}\\n`);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * 向所有客户端发送原始十六进制数据\r\n\t * @param hexString 十六进制字符串(空格分隔或连续)\r\n\t */\r\n\tsendRawHexData(hexString: string, clientId?: string | null): void {\r\n\t\t// 移除空格并转换为Buffer\r\n\t\tconst hex = hexString.replace(/\\s+/g, '');\r\n\t\tlet data: Buffer;\r\n\t\ttry {\r\n\t\t\tdata = Buffer.from(hex, 'hex');\r\n\t\t} catch (error) {\r\n\t\t\tconsole.error(`❌ Invalid hex string: ${error}`);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (clientId) {\r\n\t\t\t// 向指定客户端发送\r\n\t\t\tconst client = this.clients.get(clientId);\r\n\t\t\tif (!client || !client.socket.writable) {\r\n\t\t\t\tconsole.log(`⚠️ Client ${clientId} not found or not writable`);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tclient.socket.write(data, (err) => {\r\n\t\t\t\tif (err) {\r\n\t\t\t\t\tconsole.error(`❌ Error sending raw hex data to ${clientId}:`, err.message);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tclient.sentBytes += data.length;\r\n\t\t\t\t\tconsole.log(`📤 Sent raw hex data to ${clientId}:`);\r\n\t\t\t\t\tconsole.log(` Hex: ${data.toString('hex').toUpperCase()}`);\r\n\t\t\t\t\tconsole.log(` Size: ${data.length} bytes\\n`);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t} else {\r\n\t\t\t// 向所有客户端发送\r\n\t\t\tif (this.clients.size === 0) {\r\n\t\t\t\tconsole.log('⚠️ No clients connected');\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconsole.log(`📤 Broadcasting raw hex data to ${this.clients.size} client(s)...`);\r\n\t\t\tfor (const [id, client] of this.clients.entries()) {\r\n\t\t\t\tif (client.socket.writable) {\r\n\t\t\t\t\tclient.socket.write(data, (err) => {\r\n\t\t\t\t\t\tif (err) {\r\n\t\t\t\t\t\t\tconsole.error(`❌ Error sending raw hex data to ${id}:`, err.message);\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tclient.sentBytes += data.length;\r\n\t\t\t\t\t\t\tconsole.log(` Sent to ${id}: ${data.length} bytes`);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tconsole.log(` Hex: ${data.toString('hex').toUpperCase()}\\n`);\r\n\t\t}\r\n\t}\r\n}\r\n\r\n// 主函数\r\nfunction main() {\r\n\tconst port = parseInt(process.env.PORT || '8080', 10);\r\n\tconst host = process.env.HOST || '127.0.0.1';\r\n\r\n\tconst server = new TestTCPServer(port, host);\r\n\r\n\t// 启动服务器\r\n\tserver.start();\r\n\r\n\t// 处理 Ctrl+C 优雅退出\r\n\tconst exitHandler = () => {\r\n\t\tconsole.log('\\n');\r\n\t\tserver.stop();\r\n\t\tprocess.exit(0);\r\n\t};\r\n\r\n\tprocess.on('SIGINT', exitHandler);\r\n\tprocess.on('SIGTERM', exitHandler);\r\n\r\n\t// 可选:定期发送预设的测试数据包(取消注释以启用)\r\n\t// const testDataInterval = setInterval(() => {\r\n\t// \tif (server.getClientCount() > 0) {\r\n\t// \t\tserver.sendTestDataPacket(); // 发送预设的测试数据包\r\n\t// \t}\r\n\t// }, 10000); // 每10秒发送一次\r\n\r\n\t// 可选:定期发送协议格式的测试数据(取消注释以启用)\r\n\t// const protocolTestInterval = setInterval(() => {\r\n\t// \tif (server.getClientCount() > 0) {\r\n\t// \t\tserver.broadcastTestData(\r\n\t// \t\t\t{ message: 'Broadcast test', timestamp: Date.now() },\r\n\t// \t\t\t{ type: 'broadcast', version: '1.0' }\r\n\t// \t\t);\r\n\t// \t}\r\n\t// }, 10000); // 每10秒发送一次\r\n\r\n\t// 清理定时器(如果使用了)\r\n\t// process.on('exit', () => {\r\n\t// \tclearInterval(testDataInterval);\r\n\t// \tclearInterval(protocolTestInterval);\r\n\t// });\r\n}\r\n\r\n// 如果直接运行此文件,启动服务器\r\nif (\r\n\timport.meta.url === `file://${process.argv[1]?.replace(/\\\\/g, '/')}` ||\r\n\tprocess.argv[1]?.includes('test-server.ts')\r\n) {\r\n\tmain();\r\n}\r\n\r\nexport { TestTCPServer };\r\n"]}