@zhin.js/adapter 1.2.1 → 1.2.2
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.
|
@@ -41,7 +41,7 @@ export interface EndpointConnectHandle {
|
|
|
41
41
|
* 初始连接失败由 start() 的拒绝路径复位,不武装重连。
|
|
42
42
|
*/
|
|
43
43
|
notifyClosed(reason?: unknown): void;
|
|
44
|
-
/**
|
|
44
|
+
/** 注册当前连接的强制关闭函数;同代已 stop 时立即关闭,旧代句柄忽略。 */
|
|
45
45
|
onForceClose(close: () => void): void;
|
|
46
46
|
}
|
|
47
47
|
export type EndpointConnectFn = (handle: EndpointConnectHandle) => Promise<void>;
|
|
@@ -102,19 +102,20 @@ class EndpointLifecycleImpl {
|
|
|
102
102
|
this.#connect = connect;
|
|
103
103
|
this.#state = 'connecting';
|
|
104
104
|
this.#attempt = 0;
|
|
105
|
+
const generation = this.#generation + 1;
|
|
105
106
|
try {
|
|
106
107
|
await this.#runConnect(connect);
|
|
107
108
|
}
|
|
108
109
|
catch (err) {
|
|
109
110
|
// 注意:stop() 可能在 await 期间并发改写 #state,必须经 getter 读取避免 TS 窄化误判
|
|
110
|
-
if (this.#currentState() === 'stopped')
|
|
111
|
-
return;
|
|
111
|
+
if (generation !== this.#generation || this.#currentState() === 'stopped')
|
|
112
|
+
return;
|
|
112
113
|
// start 失败复位:回 idle、不武装重连,允许调用方重试
|
|
113
114
|
this.#state = 'idle';
|
|
114
115
|
throw err;
|
|
115
116
|
}
|
|
116
|
-
if (this.#currentState() === 'stopped')
|
|
117
|
-
return;
|
|
117
|
+
if (generation !== this.#generation || this.#currentState() === 'stopped')
|
|
118
|
+
return;
|
|
118
119
|
this.#state = 'open';
|
|
119
120
|
}
|
|
120
121
|
async stop() {
|
|
@@ -220,8 +221,18 @@ class EndpointLifecycleImpl {
|
|
|
220
221
|
this.#scheduleReconnect();
|
|
221
222
|
},
|
|
222
223
|
onForceClose: (close) => {
|
|
223
|
-
if (generation
|
|
224
|
-
|
|
224
|
+
if (generation !== this.#generation)
|
|
225
|
+
return;
|
|
226
|
+
if (this.#state === 'stopped') {
|
|
227
|
+
try {
|
|
228
|
+
close();
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
/* same best-effort cleanup as stop() */
|
|
232
|
+
}
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
this.#forceClose = close;
|
|
225
236
|
},
|
|
226
237
|
};
|
|
227
238
|
}
|
|
@@ -231,7 +242,11 @@ class EndpointLifecycleImpl {
|
|
|
231
242
|
this.#forceClose = undefined;
|
|
232
243
|
const handle = this.#createHandle(generation);
|
|
233
244
|
// Promise.resolve().then 兜底同步抛错;额外 catch 防止 stop 竞态后迟到拒绝变 unhandled
|
|
234
|
-
const connecting = Promise.resolve().then(() =>
|
|
245
|
+
const connecting = Promise.resolve().then(() => {
|
|
246
|
+
if (generation !== this.#generation || this.#state === 'stopped')
|
|
247
|
+
return;
|
|
248
|
+
return connect(handle);
|
|
249
|
+
});
|
|
235
250
|
connecting.catch(() => { });
|
|
236
251
|
let wake;
|
|
237
252
|
const stopped = new Promise((resolve) => {
|
|
@@ -285,11 +300,12 @@ class EndpointLifecycleImpl {
|
|
|
285
300
|
const elapsed = await this.#sleep(delay);
|
|
286
301
|
if (!elapsed || this.#currentState() !== 'reconnecting')
|
|
287
302
|
return;
|
|
303
|
+
const generation = this.#generation + 1;
|
|
288
304
|
try {
|
|
289
305
|
await this.#runConnect(connect);
|
|
290
306
|
}
|
|
291
307
|
catch (err) {
|
|
292
|
-
if (this.#currentState() === 'stopped')
|
|
308
|
+
if (generation !== this.#generation || this.#currentState() === 'stopped')
|
|
293
309
|
return;
|
|
294
310
|
this.#attempt += 1;
|
|
295
311
|
logger.debug(formatCompact({
|
|
@@ -301,7 +317,7 @@ class EndpointLifecycleImpl {
|
|
|
301
317
|
}));
|
|
302
318
|
continue;
|
|
303
319
|
}
|
|
304
|
-
if (this.#currentState() === 'stopped')
|
|
320
|
+
if (generation !== this.#generation || this.#currentState() === 'stopped')
|
|
305
321
|
return;
|
|
306
322
|
this.#state = 'open';
|
|
307
323
|
this.#attempt = 0;
|
package/package.json
CHANGED
|
@@ -99,7 +99,7 @@ export interface EndpointConnectHandle {
|
|
|
99
99
|
* 初始连接失败由 start() 的拒绝路径复位,不武装重连。
|
|
100
100
|
*/
|
|
101
101
|
notifyClosed(reason?: unknown): void;
|
|
102
|
-
/**
|
|
102
|
+
/** 注册当前连接的强制关闭函数;同代已 stop 时立即关闭,旧代句柄忽略。 */
|
|
103
103
|
onForceClose(close: () => void): void;
|
|
104
104
|
}
|
|
105
105
|
|
|
@@ -197,16 +197,17 @@ class EndpointLifecycleImpl implements EndpointLifecycle {
|
|
|
197
197
|
this.#connect = connect;
|
|
198
198
|
this.#state = 'connecting';
|
|
199
199
|
this.#attempt = 0;
|
|
200
|
+
const generation = this.#generation + 1;
|
|
200
201
|
try {
|
|
201
202
|
await this.#runConnect(connect);
|
|
202
203
|
} catch (err) {
|
|
203
204
|
// 注意:stop() 可能在 await 期间并发改写 #state,必须经 getter 读取避免 TS 窄化误判
|
|
204
|
-
if (this.#currentState() === 'stopped') return;
|
|
205
|
+
if (generation !== this.#generation || this.#currentState() === 'stopped') return;
|
|
205
206
|
// start 失败复位:回 idle、不武装重连,允许调用方重试
|
|
206
207
|
this.#state = 'idle';
|
|
207
208
|
throw err;
|
|
208
209
|
}
|
|
209
|
-
if (this.#currentState() === 'stopped') return;
|
|
210
|
+
if (generation !== this.#generation || this.#currentState() === 'stopped') return;
|
|
210
211
|
this.#state = 'open';
|
|
211
212
|
}
|
|
212
213
|
|
|
@@ -310,7 +311,16 @@ class EndpointLifecycleImpl implements EndpointLifecycle {
|
|
|
310
311
|
this.#scheduleReconnect();
|
|
311
312
|
},
|
|
312
313
|
onForceClose: (close) => {
|
|
313
|
-
if (generation
|
|
314
|
+
if (generation !== this.#generation) return;
|
|
315
|
+
if (this.#state === 'stopped') {
|
|
316
|
+
try {
|
|
317
|
+
close();
|
|
318
|
+
} catch {
|
|
319
|
+
/* same best-effort cleanup as stop() */
|
|
320
|
+
}
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
this.#forceClose = close;
|
|
314
324
|
},
|
|
315
325
|
};
|
|
316
326
|
}
|
|
@@ -321,7 +331,10 @@ class EndpointLifecycleImpl implements EndpointLifecycle {
|
|
|
321
331
|
this.#forceClose = undefined;
|
|
322
332
|
const handle = this.#createHandle(generation);
|
|
323
333
|
// Promise.resolve().then 兜底同步抛错;额外 catch 防止 stop 竞态后迟到拒绝变 unhandled
|
|
324
|
-
const connecting = Promise.resolve().then(() =>
|
|
334
|
+
const connecting = Promise.resolve().then(() => {
|
|
335
|
+
if (generation !== this.#generation || this.#state === 'stopped') return;
|
|
336
|
+
return connect(handle);
|
|
337
|
+
});
|
|
325
338
|
connecting.catch(() => { /* settled via race; late rejection ignored */ });
|
|
326
339
|
let wake!: () => void;
|
|
327
340
|
const stopped = new Promise<void>((resolve) => {
|
|
@@ -375,10 +388,11 @@ class EndpointLifecycleImpl implements EndpointLifecycle {
|
|
|
375
388
|
}));
|
|
376
389
|
const elapsed = await this.#sleep(delay);
|
|
377
390
|
if (!elapsed || this.#currentState() !== 'reconnecting') return;
|
|
391
|
+
const generation = this.#generation + 1;
|
|
378
392
|
try {
|
|
379
393
|
await this.#runConnect(connect);
|
|
380
394
|
} catch (err) {
|
|
381
|
-
if (this.#currentState() === 'stopped') return;
|
|
395
|
+
if (generation !== this.#generation || this.#currentState() === 'stopped') return;
|
|
382
396
|
this.#attempt += 1;
|
|
383
397
|
logger.debug(formatCompact({
|
|
384
398
|
op: 'reconnect',
|
|
@@ -389,7 +403,7 @@ class EndpointLifecycleImpl implements EndpointLifecycle {
|
|
|
389
403
|
}));
|
|
390
404
|
continue;
|
|
391
405
|
}
|
|
392
|
-
if (this.#currentState() === 'stopped') return;
|
|
406
|
+
if (generation !== this.#generation || this.#currentState() === 'stopped') return;
|
|
393
407
|
this.#state = 'open';
|
|
394
408
|
this.#attempt = 0;
|
|
395
409
|
logger.info(formatCompact({ op: 'reconnect', endpoint: this.#name, ok: true }));
|