icom-wlan-node 0.2.1 → 0.2.3
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/dist/index.d.ts +1 -0
- package/dist/index.js +5 -1
- package/dist/rig/IcomConstants.d.ts +12 -12
- package/dist/rig/IcomConstants.js +12 -12
- package/dist/rig/IcomControl.js +78 -17
- package/dist/utils/errorHandling.d.ts +55 -0
- package/dist/utils/errorHandling.js +147 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -4,3 +4,4 @@ export { MODE_MAP, CONNECTOR_MODE_MAP, DEFAULT_CONTROLLER_ADDR, METER_THRESHOLDS
|
|
|
4
4
|
export { parseTwoByteBcd, intToTwoByteBcd } from './utils/bcd';
|
|
5
5
|
export { IcomRigCommands } from './rig/IcomRigCommands';
|
|
6
6
|
export { AUDIO_RATE } from './rig/IcomAudio';
|
|
7
|
+
export { setupGlobalErrorHandlers, setupBasicErrorProtection, GlobalErrorHandlerOptions } from './utils/errorHandling';
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.AUDIO_RATE = exports.IcomRigCommands = exports.intToTwoByteBcd = exports.parseTwoByteBcd = exports.rawToCurrent = exports.rawToVoltage = exports.rawToPowerPercent = exports.getFilterString = exports.getConnectorModeString = exports.getModeString = exports.getConnectorModeCode = exports.getModeCode = exports.METER_CALIBRATION = exports.METER_THRESHOLDS = exports.DEFAULT_CONTROLLER_ADDR = exports.CONNECTOR_MODE_MAP = exports.MODE_MAP = exports.IcomControl = void 0;
|
|
17
|
+
exports.setupBasicErrorProtection = exports.setupGlobalErrorHandlers = exports.AUDIO_RATE = exports.IcomRigCommands = exports.intToTwoByteBcd = exports.parseTwoByteBcd = exports.rawToCurrent = exports.rawToVoltage = exports.rawToPowerPercent = exports.getFilterString = exports.getConnectorModeString = exports.getModeString = exports.getConnectorModeCode = exports.getModeCode = exports.METER_CALIBRATION = exports.METER_THRESHOLDS = exports.DEFAULT_CONTROLLER_ADDR = exports.CONNECTOR_MODE_MAP = exports.MODE_MAP = exports.IcomControl = void 0;
|
|
18
18
|
// Export types (includes ConnectionPhase, ConnectionMetrics, etc.)
|
|
19
19
|
__exportStar(require("./types"), exports);
|
|
20
20
|
// Export main class
|
|
@@ -44,3 +44,7 @@ var IcomRigCommands_1 = require("./rig/IcomRigCommands");
|
|
|
44
44
|
Object.defineProperty(exports, "IcomRigCommands", { enumerable: true, get: function () { return IcomRigCommands_1.IcomRigCommands; } });
|
|
45
45
|
var IcomAudio_1 = require("./rig/IcomAudio");
|
|
46
46
|
Object.defineProperty(exports, "AUDIO_RATE", { enumerable: true, get: function () { return IcomAudio_1.AUDIO_RATE; } });
|
|
47
|
+
// Export error handling utilities (optional, for robustness)
|
|
48
|
+
var errorHandling_1 = require("./utils/errorHandling");
|
|
49
|
+
Object.defineProperty(exports, "setupGlobalErrorHandlers", { enumerable: true, get: function () { return errorHandling_1.setupGlobalErrorHandlers; } });
|
|
50
|
+
Object.defineProperty(exports, "setupBasicErrorProtection", { enumerable: true, get: function () { return errorHandling_1.setupBasicErrorProtection; } });
|
|
@@ -92,14 +92,14 @@ export declare const METER_CALIBRATION: {
|
|
|
92
92
|
* Used for converting raw BCD to percentage
|
|
93
93
|
*/
|
|
94
94
|
readonly POWER: {
|
|
95
|
-
/** 50% power reference point */
|
|
95
|
+
/** 50% power reference point (raw=143, percent=50) */
|
|
96
96
|
readonly HALF: {
|
|
97
|
-
readonly raw:
|
|
97
|
+
readonly raw: 143;
|
|
98
98
|
readonly percent: 50;
|
|
99
99
|
};
|
|
100
|
-
/** 100% power reference point */
|
|
100
|
+
/** 100% power reference point (raw=213, percent=100) */
|
|
101
101
|
readonly FULL: {
|
|
102
|
-
readonly raw:
|
|
102
|
+
readonly raw: 213;
|
|
103
103
|
readonly percent: 100;
|
|
104
104
|
};
|
|
105
105
|
};
|
|
@@ -108,14 +108,14 @@ export declare const METER_CALIBRATION: {
|
|
|
108
108
|
* Used for converting raw BCD to volts
|
|
109
109
|
*/
|
|
110
110
|
readonly VOLTAGE: {
|
|
111
|
-
/** Low voltage reference: 5V */
|
|
111
|
+
/** Low voltage reference: 5V (raw=75) */
|
|
112
112
|
readonly LOW: {
|
|
113
|
-
readonly raw:
|
|
113
|
+
readonly raw: 75;
|
|
114
114
|
readonly volts: 5;
|
|
115
115
|
};
|
|
116
|
-
/** High voltage reference: 16V */
|
|
116
|
+
/** High voltage reference: 16V (raw=241) */
|
|
117
117
|
readonly HIGH: {
|
|
118
|
-
readonly raw:
|
|
118
|
+
readonly raw: 241;
|
|
119
119
|
readonly volts: 16;
|
|
120
120
|
};
|
|
121
121
|
};
|
|
@@ -124,14 +124,14 @@ export declare const METER_CALIBRATION: {
|
|
|
124
124
|
* Used for converting raw BCD to amperes
|
|
125
125
|
*/
|
|
126
126
|
readonly CURRENT: {
|
|
127
|
-
/** Low current reference: 2A */
|
|
127
|
+
/** Low current reference: 2A (raw=121) */
|
|
128
128
|
readonly LOW: {
|
|
129
|
-
readonly raw:
|
|
129
|
+
readonly raw: 121;
|
|
130
130
|
readonly amps: 2;
|
|
131
131
|
};
|
|
132
|
-
/** High current reference: 4A */
|
|
132
|
+
/** High current reference: 4A (raw=241) */
|
|
133
133
|
readonly HIGH: {
|
|
134
|
-
readonly raw:
|
|
134
|
+
readonly raw: 241;
|
|
135
135
|
readonly amps: 4;
|
|
136
136
|
};
|
|
137
137
|
};
|
|
@@ -123,30 +123,30 @@ exports.METER_CALIBRATION = {
|
|
|
123
123
|
* Used for converting raw BCD to percentage
|
|
124
124
|
*/
|
|
125
125
|
POWER: {
|
|
126
|
-
/** 50% power reference point */
|
|
127
|
-
HALF: { raw:
|
|
128
|
-
/** 100% power reference point */
|
|
129
|
-
FULL: { raw:
|
|
126
|
+
/** 50% power reference point (raw=143, percent=50) */
|
|
127
|
+
HALF: { raw: 143, percent: 50 },
|
|
128
|
+
/** 100% power reference point (raw=213, percent=100) */
|
|
129
|
+
FULL: { raw: 213, percent: 100 }
|
|
130
130
|
},
|
|
131
131
|
/**
|
|
132
132
|
* Voltage (CI-V 0x15/0x15) calibration points
|
|
133
133
|
* Used for converting raw BCD to volts
|
|
134
134
|
*/
|
|
135
135
|
VOLTAGE: {
|
|
136
|
-
/** Low voltage reference: 5V */
|
|
137
|
-
LOW: { raw:
|
|
138
|
-
/** High voltage reference: 16V */
|
|
139
|
-
HIGH: { raw:
|
|
136
|
+
/** Low voltage reference: 5V (raw=75) */
|
|
137
|
+
LOW: { raw: 75, volts: 5.0 },
|
|
138
|
+
/** High voltage reference: 16V (raw=241) */
|
|
139
|
+
HIGH: { raw: 241, volts: 16.0 }
|
|
140
140
|
},
|
|
141
141
|
/**
|
|
142
142
|
* Current (CI-V 0x15/0x16) calibration points
|
|
143
143
|
* Used for converting raw BCD to amperes
|
|
144
144
|
*/
|
|
145
145
|
CURRENT: {
|
|
146
|
-
/** Low current reference: 2A */
|
|
147
|
-
LOW: { raw:
|
|
148
|
-
/** High current reference: 4A */
|
|
149
|
-
HIGH: { raw:
|
|
146
|
+
/** Low current reference: 2A (raw=121) */
|
|
147
|
+
LOW: { raw: 121, amps: 2.0 },
|
|
148
|
+
/** High current reference: 4A (raw=241) */
|
|
149
|
+
HIGH: { raw: 241, amps: 4.0 }
|
|
150
150
|
}
|
|
151
151
|
};
|
|
152
152
|
/**
|
package/dist/rig/IcomControl.js
CHANGED
|
@@ -275,24 +275,48 @@ class IcomControl {
|
|
|
275
275
|
const abortHandler = (reason) => {
|
|
276
276
|
(0, debug_1.dbg)(`Aborting connection session ${sessionId}: ${reason}`);
|
|
277
277
|
const error = new Error(reason);
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
278
|
+
// Defensive error handling: wrap reject calls in try-catch to prevent
|
|
279
|
+
// synchronous errors from propagating if promises are already settled
|
|
280
|
+
try {
|
|
281
|
+
rejectLogin(error);
|
|
282
|
+
}
|
|
283
|
+
catch (err) {
|
|
284
|
+
(0, debug_1.dbg)(`Warning: Failed to reject loginReady promise: ${err}`);
|
|
285
|
+
}
|
|
286
|
+
try {
|
|
287
|
+
rejectCiv(error);
|
|
288
|
+
}
|
|
289
|
+
catch (err) {
|
|
290
|
+
(0, debug_1.dbg)(`Warning: Failed to reject civReady promise: ${err}`);
|
|
291
|
+
}
|
|
292
|
+
try {
|
|
293
|
+
rejectAudio(error);
|
|
294
|
+
}
|
|
295
|
+
catch (err) {
|
|
296
|
+
(0, debug_1.dbg)(`Warning: Failed to reject audioReady promise: ${err}`);
|
|
297
|
+
}
|
|
281
298
|
};
|
|
282
299
|
this.abortHandlers.set(sessionId, abortHandler);
|
|
300
|
+
// Track promise states for defensive cleanup
|
|
301
|
+
let loginResolved = false;
|
|
302
|
+
let civResolved = false;
|
|
303
|
+
let audioResolved = false;
|
|
283
304
|
// Temporary event listeners (local scope)
|
|
284
305
|
const onLogin = (res) => {
|
|
285
306
|
if (res.ok) {
|
|
286
|
-
(0, debug_1.dbg)(
|
|
307
|
+
(0, debug_1.dbg)(`Login ready - resolving local loginReady promise (sessionId=${sessionId})`);
|
|
308
|
+
loginResolved = true;
|
|
287
309
|
resolveLogin();
|
|
288
310
|
}
|
|
289
311
|
};
|
|
290
312
|
const onCivReady = () => {
|
|
291
|
-
(0, debug_1.dbg)(
|
|
313
|
+
(0, debug_1.dbg)(`CIV ready - resolving local civReady promise (sessionId=${sessionId})`);
|
|
314
|
+
civResolved = true;
|
|
292
315
|
resolveCiv();
|
|
293
316
|
};
|
|
294
317
|
const onAudioReady = () => {
|
|
295
|
-
(0, debug_1.dbg)(
|
|
318
|
+
(0, debug_1.dbg)(`Audio ready - resolving local audioReady promise (sessionId=${sessionId})`);
|
|
319
|
+
audioResolved = true;
|
|
296
320
|
resolveAudio();
|
|
297
321
|
};
|
|
298
322
|
this.ev.once('login', onLogin);
|
|
@@ -303,13 +327,36 @@ class IcomControl {
|
|
|
303
327
|
civReady,
|
|
304
328
|
audioReady,
|
|
305
329
|
cleanup: () => {
|
|
330
|
+
// Defensive cleanup: wrap each cleanup step in try-catch
|
|
331
|
+
// to ensure all cleanup steps execute even if one fails
|
|
332
|
+
(0, debug_1.dbg)(`Cleaning up connection session ${sessionId} (login=${loginResolved}, civ=${civResolved}, audio=${audioResolved})`);
|
|
306
333
|
// Remove abort handler for this specific sessionId
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
334
|
+
try {
|
|
335
|
+
this.abortHandlers.delete(sessionId);
|
|
336
|
+
}
|
|
337
|
+
catch (err) {
|
|
338
|
+
(0, debug_1.dbg)(`Warning: Failed to delete abort handler: ${err}`);
|
|
339
|
+
}
|
|
340
|
+
// Remove event listeners - wrap each in try-catch
|
|
341
|
+
try {
|
|
342
|
+
this.ev.off('login', onLogin);
|
|
343
|
+
}
|
|
344
|
+
catch (err) {
|
|
345
|
+
(0, debug_1.dbg)(`Warning: Failed to remove login listener: ${err}`);
|
|
346
|
+
}
|
|
347
|
+
try {
|
|
348
|
+
this.ev.off('_civReady', onCivReady);
|
|
349
|
+
}
|
|
350
|
+
catch (err) {
|
|
351
|
+
(0, debug_1.dbg)(`Warning: Failed to remove civReady listener: ${err}`);
|
|
352
|
+
}
|
|
353
|
+
try {
|
|
354
|
+
this.ev.off('_audioReady', onAudioReady);
|
|
355
|
+
}
|
|
356
|
+
catch (err) {
|
|
357
|
+
(0, debug_1.dbg)(`Warning: Failed to remove audioReady listener: ${err}`);
|
|
358
|
+
}
|
|
359
|
+
(0, debug_1.dbg)(`Cleanup complete for session ${sessionId}`);
|
|
313
360
|
}
|
|
314
361
|
};
|
|
315
362
|
}
|
|
@@ -376,11 +423,18 @@ class IcomControl {
|
|
|
376
423
|
(0, debug_1.dbg)('disconnect() called but already IDLE - no-op');
|
|
377
424
|
return;
|
|
378
425
|
}
|
|
379
|
-
// Abort any ongoing connection attempts
|
|
426
|
+
// Abort any ongoing connection attempts - wrap in try-catch for defensive programming
|
|
380
427
|
const currentSessionId = this.connectionSession.sessionId;
|
|
381
428
|
if (currentPhase === types_1.ConnectionPhase.CONNECTING || currentPhase === types_1.ConnectionPhase.RECONNECTING) {
|
|
382
|
-
|
|
383
|
-
|
|
429
|
+
try {
|
|
430
|
+
(0, debug_1.dbg)(`Aborting ongoing connection attempt (sessionId=${currentSessionId})`);
|
|
431
|
+
this.abortConnectionAttempt(currentSessionId, 'User disconnect()');
|
|
432
|
+
}
|
|
433
|
+
catch (abortErr) {
|
|
434
|
+
// Log but continue - abort failure shouldn't prevent disconnect
|
|
435
|
+
const errMsg = abortErr instanceof Error ? abortErr.message : String(abortErr);
|
|
436
|
+
(0, debug_1.dbg)(`Warning: Failed to abort connection attempt: ${errMsg} - continuing with disconnect`);
|
|
437
|
+
}
|
|
384
438
|
}
|
|
385
439
|
// Transition to DISCONNECTING state
|
|
386
440
|
this.transitionTo(types_1.ConnectionPhase.DISCONNECTING, 'User disconnect()');
|
|
@@ -1544,9 +1598,16 @@ class IcomControl {
|
|
|
1544
1598
|
(0, debug_1.dbg)(`Full reconnect attempt #${attempt} (delay: ${delay}ms)`);
|
|
1545
1599
|
await this.sleep(delay);
|
|
1546
1600
|
try {
|
|
1547
|
-
// Disconnect all sessions
|
|
1601
|
+
// Disconnect all sessions - wrap in try-catch to prevent disconnect errors from aborting reconnect
|
|
1548
1602
|
(0, debug_1.dbg)('Full reconnect: disconnecting all sessions');
|
|
1549
|
-
|
|
1603
|
+
try {
|
|
1604
|
+
await this.disconnect();
|
|
1605
|
+
}
|
|
1606
|
+
catch (disconnectErr) {
|
|
1607
|
+
// Log but don't fail - we still want to attempt reconnect even if disconnect fails
|
|
1608
|
+
const errMsg = disconnectErr instanceof Error ? disconnectErr.message : String(disconnectErr);
|
|
1609
|
+
(0, debug_1.dbg)(`Warning: Disconnect failed during reconnect: ${errMsg} - continuing with reconnect anyway`);
|
|
1610
|
+
}
|
|
1550
1611
|
// Wait longer before reconnecting to allow rig to fully clean up old connection
|
|
1551
1612
|
// This is critical - rig may report CONNINFO busy=true if we reconnect too quickly
|
|
1552
1613
|
(0, debug_1.dbg)('Full reconnect: waiting 5s for rig to clean up old session...');
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 全局错误处理工具函数
|
|
3
|
+
*
|
|
4
|
+
* 这个模块提供可选的全局错误处理器,帮助用户防止未捕获的 Promise rejection 和异常导致进程崩溃。
|
|
5
|
+
*
|
|
6
|
+
* 使用方式:
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { setupGlobalErrorHandlers } from 'icom-wlan-node/utils/errorHandling';
|
|
9
|
+
*
|
|
10
|
+
* // 在应用启动时调用(可选)
|
|
11
|
+
* setupGlobalErrorHandlers({
|
|
12
|
+
* onUnhandledRejection: (reason, promise) => {
|
|
13
|
+
* console.error('未处理的 Promise rejection:', reason);
|
|
14
|
+
* // 自定义处理逻辑
|
|
15
|
+
* },
|
|
16
|
+
* onUncaughtException: (error, origin) => {
|
|
17
|
+
* console.error('未捕获的异常:', error);
|
|
18
|
+
* // 自定义处理逻辑
|
|
19
|
+
* }
|
|
20
|
+
* });
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export interface GlobalErrorHandlerOptions {
|
|
24
|
+
/**
|
|
25
|
+
* 处理未捕获的 Promise rejection
|
|
26
|
+
* @param reason - rejection 的原因
|
|
27
|
+
* @param promise - 被 reject 的 Promise
|
|
28
|
+
*/
|
|
29
|
+
onUnhandledRejection?: (reason: any, promise: Promise<any>) => void;
|
|
30
|
+
/**
|
|
31
|
+
* 处理未捕获的异常
|
|
32
|
+
* @param error - 异常对象
|
|
33
|
+
* @param origin - 异常来源 ('uncaughtException' 或 'unhandledRejection')
|
|
34
|
+
*/
|
|
35
|
+
onUncaughtException?: (error: Error, origin: string) => void;
|
|
36
|
+
/**
|
|
37
|
+
* 是否在处理错误后阻止进程退出(默认 true)
|
|
38
|
+
* 设为 false 时,错误会被记录但进程仍可能退出
|
|
39
|
+
*/
|
|
40
|
+
preventExit?: boolean;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 设置全局错误处理器
|
|
44
|
+
*
|
|
45
|
+
* 注意:这是一个可选的工具函数,仅在需要时使用。
|
|
46
|
+
* 如果你的应用已经有全局错误处理逻辑,不需要调用此函数。
|
|
47
|
+
*
|
|
48
|
+
* @param options - 错误处理选项
|
|
49
|
+
* @returns cleanup 函数,用于移除错误处理器
|
|
50
|
+
*/
|
|
51
|
+
export declare function setupGlobalErrorHandlers(options?: GlobalErrorHandlerOptions): () => void;
|
|
52
|
+
/**
|
|
53
|
+
* 快速设置:仅防止进程崩溃,使用默认错误处理
|
|
54
|
+
*/
|
|
55
|
+
export declare function setupBasicErrorProtection(): () => void;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 全局错误处理工具函数
|
|
4
|
+
*
|
|
5
|
+
* 这个模块提供可选的全局错误处理器,帮助用户防止未捕获的 Promise rejection 和异常导致进程崩溃。
|
|
6
|
+
*
|
|
7
|
+
* 使用方式:
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { setupGlobalErrorHandlers } from 'icom-wlan-node/utils/errorHandling';
|
|
10
|
+
*
|
|
11
|
+
* // 在应用启动时调用(可选)
|
|
12
|
+
* setupGlobalErrorHandlers({
|
|
13
|
+
* onUnhandledRejection: (reason, promise) => {
|
|
14
|
+
* console.error('未处理的 Promise rejection:', reason);
|
|
15
|
+
* // 自定义处理逻辑
|
|
16
|
+
* },
|
|
17
|
+
* onUncaughtException: (error, origin) => {
|
|
18
|
+
* console.error('未捕获的异常:', error);
|
|
19
|
+
* // 自定义处理逻辑
|
|
20
|
+
* }
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.setupGlobalErrorHandlers = setupGlobalErrorHandlers;
|
|
26
|
+
exports.setupBasicErrorProtection = setupBasicErrorProtection;
|
|
27
|
+
/**
|
|
28
|
+
* 设置全局错误处理器
|
|
29
|
+
*
|
|
30
|
+
* 注意:这是一个可选的工具函数,仅在需要时使用。
|
|
31
|
+
* 如果你的应用已经有全局错误处理逻辑,不需要调用此函数。
|
|
32
|
+
*
|
|
33
|
+
* @param options - 错误处理选项
|
|
34
|
+
* @returns cleanup 函数,用于移除错误处理器
|
|
35
|
+
*/
|
|
36
|
+
function setupGlobalErrorHandlers(options = {}) {
|
|
37
|
+
const { onUnhandledRejection = defaultUnhandledRejectionHandler, onUncaughtException = defaultUncaughtExceptionHandler, preventExit = true } = options;
|
|
38
|
+
// 未处理的 Promise rejection 处理器
|
|
39
|
+
const unhandledRejectionHandler = (reason, promise) => {
|
|
40
|
+
console.error('⚠️ [icom-wlan-node] 检测到未处理的 Promise rejection:');
|
|
41
|
+
console.error('原因:', reason);
|
|
42
|
+
console.error('Promise:', promise);
|
|
43
|
+
if (reason instanceof Error) {
|
|
44
|
+
console.error('错误堆栈:', reason.stack);
|
|
45
|
+
}
|
|
46
|
+
// 调用用户自定义处理器
|
|
47
|
+
onUnhandledRejection(reason, promise);
|
|
48
|
+
};
|
|
49
|
+
// 未捕获的异常处理器
|
|
50
|
+
const uncaughtExceptionHandler = (error, origin) => {
|
|
51
|
+
console.error('⚠️ [icom-wlan-node] 检测到未捕获的异常:');
|
|
52
|
+
console.error('错误:', error);
|
|
53
|
+
console.error('来源:', origin);
|
|
54
|
+
console.error('堆栈:', error.stack);
|
|
55
|
+
// 调用用户自定义处理器
|
|
56
|
+
onUncaughtException(error, origin);
|
|
57
|
+
// 根据配置决定是否退出
|
|
58
|
+
if (!preventExit) {
|
|
59
|
+
console.error('进程即将退出...');
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
// 注册处理器
|
|
64
|
+
process.on('unhandledRejection', unhandledRejectionHandler);
|
|
65
|
+
process.on('uncaughtException', uncaughtExceptionHandler);
|
|
66
|
+
console.log('✓ [icom-wlan-node] 全局错误处理器已设置');
|
|
67
|
+
// 返回 cleanup 函数
|
|
68
|
+
return () => {
|
|
69
|
+
process.off('unhandledRejection', unhandledRejectionHandler);
|
|
70
|
+
process.off('uncaughtException', uncaughtExceptionHandler);
|
|
71
|
+
console.log('✓ [icom-wlan-node] 全局错误处理器已移除');
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* 默认的未处理 Promise rejection 处理器
|
|
76
|
+
*/
|
|
77
|
+
function defaultUnhandledRejectionHandler(reason, promise) {
|
|
78
|
+
// 检查是否是网络错误(可以优雅处理)
|
|
79
|
+
if (isNetworkError(reason)) {
|
|
80
|
+
console.warn('网络错误已被捕获,但未影响进程稳定性');
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
// 其他错误记录为警告
|
|
84
|
+
console.warn('检测到未处理的 Promise rejection,但进程继续运行');
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* 默认的未捕获异常处理器
|
|
88
|
+
*/
|
|
89
|
+
function defaultUncaughtExceptionHandler(error, origin) {
|
|
90
|
+
// 检查是否是可恢复的错误
|
|
91
|
+
if (isRecoverableError(error)) {
|
|
92
|
+
console.warn('可恢复的错误已被捕获,进程继续运行');
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
console.error('检测到严重错误,建议检查应用逻辑');
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* 判断是否是网络错误
|
|
99
|
+
*/
|
|
100
|
+
function isNetworkError(error) {
|
|
101
|
+
if (!error)
|
|
102
|
+
return false;
|
|
103
|
+
const networkErrorCodes = [
|
|
104
|
+
'EHOSTDOWN',
|
|
105
|
+
'EHOSTUNREACH',
|
|
106
|
+
'ENETDOWN',
|
|
107
|
+
'ENETUNREACH',
|
|
108
|
+
'ECONNREFUSED',
|
|
109
|
+
'ECONNRESET',
|
|
110
|
+
'ETIMEDOUT',
|
|
111
|
+
'ENOTFOUND'
|
|
112
|
+
];
|
|
113
|
+
// 检查错误码
|
|
114
|
+
if (error.code && networkErrorCodes.includes(error.code)) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
// 检查错误消息
|
|
118
|
+
if (error.message && typeof error.message === 'string') {
|
|
119
|
+
return networkErrorCodes.some(code => error.message.includes(code));
|
|
120
|
+
}
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* 判断是否是可恢复的错误
|
|
125
|
+
*/
|
|
126
|
+
function isRecoverableError(error) {
|
|
127
|
+
// 网络错误通常是可恢复的
|
|
128
|
+
if (isNetworkError(error)) {
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
// 连接相关的错误也是可恢复的
|
|
132
|
+
const recoverableMessages = [
|
|
133
|
+
'Connection failed',
|
|
134
|
+
'User disconnect',
|
|
135
|
+
'Connection timeout',
|
|
136
|
+
'CIV/Audio sessions timeout'
|
|
137
|
+
];
|
|
138
|
+
return recoverableMessages.some(msg => error.message.includes(msg));
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* 快速设置:仅防止进程崩溃,使用默认错误处理
|
|
142
|
+
*/
|
|
143
|
+
function setupBasicErrorProtection() {
|
|
144
|
+
return setupGlobalErrorHandlers({
|
|
145
|
+
preventExit: true
|
|
146
|
+
});
|
|
147
|
+
}
|