node-opcua-client 2.167.0 → 2.169.0

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 (41) hide show
  1. package/dist/client_monitored_item.d.ts +4 -4
  2. package/dist/client_monitored_item.js +6 -5
  3. package/dist/client_monitored_item.js.map +1 -1
  4. package/dist/client_monitored_item_base.d.ts +7 -7
  5. package/dist/client_monitored_item_toolbox.d.ts +5 -5
  6. package/dist/client_monitored_item_toolbox.js +26 -19
  7. package/dist/client_monitored_item_toolbox.js.map +1 -1
  8. package/dist/private/client_base_impl.js +116 -85
  9. package/dist/private/client_base_impl.js.map +1 -1
  10. package/dist/private/client_monitored_item_group_impl.d.ts +7 -6
  11. package/dist/private/client_monitored_item_group_impl.js +6 -8
  12. package/dist/private/client_monitored_item_group_impl.js.map +1 -1
  13. package/dist/private/client_monitored_item_impl.d.ts +10 -9
  14. package/dist/private/client_monitored_item_impl.js +40 -26
  15. package/dist/private/client_monitored_item_impl.js.map +1 -1
  16. package/dist/private/client_session_impl.d.ts +1 -0
  17. package/dist/private/client_session_impl.js +12 -0
  18. package/dist/private/client_session_impl.js.map +1 -1
  19. package/dist/private/client_subscription_impl.d.ts +7 -4
  20. package/dist/private/client_subscription_impl.js +101 -77
  21. package/dist/private/client_subscription_impl.js.map +1 -1
  22. package/dist/private/opcua_client_impl.d.ts +1 -0
  23. package/dist/private/opcua_client_impl.js +11 -0
  24. package/dist/private/opcua_client_impl.js.map +1 -1
  25. package/dist/private/reconnection/client_publish_engine_reconnection.js +54 -45
  26. package/dist/private/reconnection/client_publish_engine_reconnection.js.map +1 -1
  27. package/dist/private/reconnection/reconnection.d.ts +1 -1
  28. package/dist/private/reconnection/reconnection.js +199 -280
  29. package/dist/private/reconnection/reconnection.js.map +1 -1
  30. package/package.json +43 -44
  31. package/source/client_monitored_item.ts +5 -4
  32. package/source/client_monitored_item_base.ts +13 -8
  33. package/source/client_monitored_item_toolbox.ts +24 -20
  34. package/source/private/client_base_impl.ts +169 -199
  35. package/source/private/client_monitored_item_group_impl.ts +15 -16
  36. package/source/private/client_monitored_item_impl.ts +56 -38
  37. package/source/private/client_session_impl.ts +29 -14
  38. package/source/private/client_subscription_impl.ts +151 -91
  39. package/source/private/opcua_client_impl.ts +13 -0
  40. package/source/private/reconnection/client_publish_engine_reconnection.ts +67 -60
  41. package/source/private/reconnection/reconnection.ts +253 -344
@@ -3,16 +3,13 @@
3
3
  */
4
4
 
5
5
  // tslint:disable:only-arrow-functions
6
- import async from "async";
7
6
  import chalk from "chalk";
8
7
  import { assert } from "node-opcua-assert";
9
8
  import { invalidateExtraDataTypeManager } from "node-opcua-client-dynamic-extension-object";
10
9
  import { checkDebugFlag, make_debugLog, make_errorLog, make_warningLog } from "node-opcua-debug";
11
10
  import { TransferSubscriptionsRequest, type TransferSubscriptionsResponse } from "node-opcua-service-subscription";
12
- import { type CallbackT, type ErrorCallback, StatusCode, StatusCodes } from "node-opcua-status-code";
11
+ import { StatusCodes } from "node-opcua-status-code";
13
12
  import { CloseSessionRequest } from "node-opcua-types";
14
-
15
- import type { SubscriptionId } from "../../client_session";
16
13
  import type { ClientSessionImpl, Reconnectable } from "../client_session_impl";
17
14
  import type { ClientSubscriptionImpl } from "../client_subscription_impl";
18
15
  import type { IClientBase } from "../i_private_client";
@@ -43,6 +40,12 @@ export function _shouldNotContinue2(subscription: ClientSubscriptionImpl) {
43
40
  }
44
41
  return _shouldNotContinue(subscription.session);
45
42
  }
43
+
44
+ function _throwIfShouldNotContinue(session: ClientSessionImpl): void {
45
+ const err = _shouldNotContinue(session);
46
+ if (err) throw err;
47
+ }
48
+
46
49
  //
47
50
  // a new secure channel has be created, we need to reactivate the corresponding session,
48
51
  // and reestablish the subscription and restart the publish engine.
@@ -107,7 +110,7 @@ export function _shouldNotContinue2(subscription: ClientSubscriptionImpl) {
107
110
  // |
108
111
  // v +-------------------+ +----------------------+
109
112
  // / \ | CreateSession | | |
110
- // / SR? \______Bad_______>| ActivateSession |-----> | TransferSubscription |
113
+ // / SR? \______Bad_____> | ActivateSession |-----> | TransferSubscription |
111
114
  // \ / | | | | (1)
112
115
  // \ / +-------------------+ +----------------------+ ^
113
116
  // | Good | |
@@ -163,359 +166,264 @@ function _ask_for_subscription_republish(session: ClientSessionImpl, callback: (
163
166
  });
164
167
  }
165
168
 
166
- function create_session_and_repeat_if_failed(
167
- client: IClientBase,
168
- session: ClientSessionImpl,
169
- callback: CallbackT<ClientSessionImpl>
170
- ) {
171
- // prettier-ignore
172
- {
173
- const err = _shouldNotContinue(session);
174
- if (err) {
175
- return callback(err);
176
- }
177
- }
169
+ function create_session_and_repeat_if_failed(client: IClientBase, session: ClientSessionImpl): Promise<ClientSessionImpl> {
170
+ return new Promise<ClientSessionImpl>((resolve, reject) => {
171
+ _throwIfShouldNotContinue(session);
172
+
173
+ doDebug && debugLog(chalk.bgWhite.red(" => creating a new session ...."));
174
+ // create new session, based on old session,
175
+ // so we can reuse subscriptions data
176
+ client.__createSession_step2(session, (err: Error | null, session1?: ClientSessionImpl) => {
177
+ _throwIfShouldNotContinue(session);
178
+
179
+ if (!err && session1) {
180
+ assert(session === session1, "session should have been recycled");
181
+ resolve(session);
182
+ } else {
183
+ doDebug && debugLog("Cannot complete subscription republish err = ", err?.message);
184
+ reject(err || new Error("Failed to create session"));
185
+ }
186
+ });
187
+ });
188
+ }
178
189
 
179
- doDebug && debugLog(chalk.bgWhite.red(" => creating a new session ...."));
180
- // create new session, based on old session,
181
- // so we can reuse subscriptions data
182
- client.__createSession_step2(session, (err: Error | null, session1?: ClientSessionImpl) => {
183
- // prettier-ignore
184
- {
185
- const err = _shouldNotContinue(session);
190
+ function activate_session(client: IClientBase, session: ClientSessionImpl, newSession: ClientSessionImpl): Promise<void> {
191
+ return new Promise<void>((resolve, reject) => {
192
+ _throwIfShouldNotContinue(session);
193
+
194
+ doDebug && debugLog(chalk.bgWhite.red(" => activating a new session ...."));
195
+
196
+ client._activateSession(newSession, newSession.userIdentityInfo!, (err: Error | null, _session1?: ClientSessionImpl) => {
197
+ // c8 ignore next
198
+ doDebug && debugLog(" => activating a new session .... Done err=", err ? err.message : "null");
186
199
  if (err) {
187
- return callback(err);
200
+ doDebug &&
201
+ debugLog(
202
+ "reactivation of the new session has failed: let be smart and close it before failing this repair attempt"
203
+ );
204
+ // but just on the server side, not on the client side
205
+ const closeSessionRequest = new CloseSessionRequest({
206
+ requestHeader: {
207
+ authenticationToken: newSession.authenticationToken
208
+ },
209
+ deleteSubscriptions: true
210
+ });
211
+ newSession._client?.performMessageTransaction(closeSessionRequest, (err2?: Error | null) => {
212
+ if (err2) {
213
+ warningLog("closing session", err2.message);
214
+ }
215
+ // c8 ignore next
216
+ doDebug && debugLog("the temporary replacement session is now closed");
217
+ // c8 ignore next
218
+ doDebug && debugLog(" err ", err.message, "propagated upwards");
219
+ reject(err);
220
+ });
221
+ } else {
222
+ resolve();
188
223
  }
189
- }
190
-
191
- if (!err && session1) {
192
- assert(session === session1, "session should have been recycled");
193
- callback(err, session);
194
- return;
195
- } else {
196
- doDebug && debugLog("Cannot complete subscription republish err = ", err?.message);
197
- callback(err);
198
- }
224
+ });
199
225
  });
200
226
  }
201
227
 
202
- function repair_client_session_by_recreating_a_new_session(
203
- client: IClientBase,
228
+ async function recreateSubscriptions(
204
229
  session: ClientSessionImpl,
205
- callback: (err?: Error) => void
206
- ) {
207
- // prettier-ignore
208
- {
209
- const err = _shouldNotContinue(session);
210
- if (err) {
211
- return callback(err);
230
+ newSession: ClientSessionImpl,
231
+ subscriptionsToRecreate: number[]
232
+ ): Promise<void> {
233
+ for (const subscriptionId of subscriptionsToRecreate) {
234
+ _throwIfShouldNotContinue(session);
235
+
236
+ if (!session.getPublishEngine().hasSubscription(subscriptionId)) {
237
+ doDebug && debugLog(chalk.red(" => CANNOT RECREATE SUBSCRIPTION "), subscriptionId);
238
+ continue;
239
+ }
240
+ const subscription = session.getPublishEngine().getSubscription(subscriptionId);
241
+ doDebug && debugLog(chalk.red(" => RECREATING SUBSCRIPTION "), subscriptionId);
242
+ assert(subscription.session === newSession, "must have the new session");
243
+
244
+ try {
245
+ await recreateSubscriptionAndMonitoredItem(subscription);
246
+ doDebug &&
247
+ debugLog(
248
+ chalk.cyan(" => RECREATING SUBSCRIPTION AND MONITORED ITEM DONE subscriptionId="),
249
+ subscriptionId
250
+ );
251
+ } catch (err) {
252
+ doDebug && debugLog(`_recreateSubscription failed !${(err as Error).message}`);
212
253
  }
213
254
  }
255
+ _throwIfShouldNotContinue(session);
256
+ }
214
257
 
215
- // As we don"t know if server has been rebooted or not,
216
- // and may be upgraded in between, we have to invalidate the extra data type manager
217
- invalidateExtraDataTypeManager(session);
218
-
219
- // c8 ignore next
220
- if (doDebug) {
221
- debugLog(" repairing client session by_recreating a new session for old session ", session.sessionId.toString());
222
- }
223
-
224
- let newSession: ClientSessionImpl;
258
+ function attempt_subscription_transfer(
259
+ _client: IClientBase,
260
+ session: ClientSessionImpl,
261
+ newSession: ClientSessionImpl
262
+ ): Promise<void> {
263
+ return new Promise<void>((resolve, reject) => {
264
+ _throwIfShouldNotContinue(session);
265
+
266
+ // get the old subscriptions id from the old session
267
+ const subscriptionsIds = session.getPublishEngine().getSubscriptionIds();
268
+
269
+ doDebug && debugLog(" session subscriptionCount = ", newSession.getPublishEngine().subscriptionCount);
270
+ if (subscriptionsIds.length === 0) {
271
+ doDebug && debugLog(" No subscriptions => skipping transfer subscriptions");
272
+ return resolve(); // no need to transfer subscriptions
273
+ }
274
+ doDebug && debugLog(" => asking server to transfer subscriptions = [", subscriptionsIds.join(", "), "]");
225
275
 
226
- const listenerCountBefore = session.listenerCount("");
276
+ // Transfer subscriptions - ask for initial values....
277
+ const subscriptionsToTransfer = new TransferSubscriptionsRequest({
278
+ sendInitialValues: true,
279
+ subscriptionIds: subscriptionsIds
280
+ });
227
281
 
228
- function recreateSubscription(subscriptionsToRecreate: number[], innerCallback: ErrorCallback) {
229
- async.forEach(
230
- subscriptionsToRecreate,
231
- (subscriptionId: SubscriptionId, next: ErrorCallback) => {
232
- // prettier-ignore
233
- {
234
- const err = _shouldNotContinue(session);
235
- if (err) {
236
- return next(err);
237
- }
282
+ if (newSession.getPublishEngine().nbPendingPublishRequests !== 0) {
283
+ warningLog("Warning : we should not be publishing here");
284
+ }
285
+ newSession.transferSubscriptions(
286
+ subscriptionsToTransfer,
287
+ (err: Error | null, transferSubscriptionsResponse?: TransferSubscriptionsResponse) => {
288
+ // may be the connection with server has been disconnected
289
+ _throwIfShouldNotContinue(session);
290
+
291
+ if (err || !transferSubscriptionsResponse) {
292
+ warningLog(chalk.bgCyan("May be the server is not supporting this feature"));
293
+ // when transfer subscription has failed, we have no other choice but
294
+ // recreate the subscriptions on the server side
295
+ const subscriptionsToRecreate = [...(subscriptionsToTransfer.subscriptionIds || [])];
296
+ warningLog(chalk.bgCyan("We need to recreate entirely the subscription"));
297
+ recreateSubscriptions(session, newSession, subscriptionsToRecreate)
298
+ .then(() => resolve())
299
+ .catch((e) => reject(e));
300
+ return;
238
301
  }
239
302
 
240
- if (!session.getPublishEngine().hasSubscription(subscriptionId)) {
241
- doDebug && debugLog(chalk.red(" => CANNOT RECREATE SUBSCRIPTION "), subscriptionId);
242
- return next();
303
+ const results = transferSubscriptionsResponse.results || [];
304
+ // c8 ignore next
305
+ if (doDebug) {
306
+ debugLog(
307
+ chalk.cyan(" => transfer subscriptions done"),
308
+ results.map((x) => x.statusCode.toString()).join(" ")
309
+ );
243
310
  }
244
- const subscription = session.getPublishEngine().getSubscription(subscriptionId);
245
- doDebug && debugLog(chalk.red(" => RECREATING SUBSCRIPTION "), subscriptionId);
246
- assert(subscription.session === newSession, "must have the new session");
247
311
 
248
- recreateSubscriptionAndMonitoredItem(subscription)
249
- .then(() => {
312
+ const subscriptionsToRecreate = [];
313
+
314
+ // some subscriptions may be marked as invalid on the server side ..
315
+ // those one need to be recreated and repaired ....
316
+ for (let i = 0; i < results.length; i++) {
317
+ const statusCode = results[i].statusCode;
318
+ if (statusCode.equals(StatusCodes.BadSubscriptionIdInvalid)) {
319
+ // repair subscription
250
320
  doDebug &&
251
321
  debugLog(
252
- chalk.cyan(" => RECREATING SUBSCRIPTION AND MONITORED ITEM DONE subscriptionId="),
253
- subscriptionId
322
+ chalk.red(" WARNING SUBSCRIPTION "),
323
+ subscriptionsIds[i],
324
+ chalk.red(" SHOULD BE RECREATED")
254
325
  );
255
- next();
256
- })
257
- .catch((err) => {
258
- doDebug && debugLog("_recreateSubscription failed !" + (err as Error).message);
259
- next();
260
- });
261
- },
262
- (err1?: Error | null) => {
263
- // prettier-ignore
264
- {
265
- const err = _shouldNotContinue(session);
266
- if (err) {
267
- return innerCallback(err);
268
- }
269
- }
270
- if (!err1) {
271
- // prettier-ignore
272
- }
273
- innerCallback(err1!);
274
- }
275
- );
276
- }
277
-
278
- async.series(
279
- [
280
- function suspend_old_session_publish_engine(innerCallback: ErrorCallback) {
281
- // prettier-ignore
282
- {
283
- const err = _shouldNotContinue(session);
284
- if (err) {
285
- return innerCallback(err);
286
- }
287
- }
288
-
289
- // c8 ignore next
290
- doDebug && debugLog(chalk.bgWhite.red(" => suspend old session publish engine...."));
291
- session.getPublishEngine().suspend(true);
292
- innerCallback();
293
- },
294
-
295
- function create_new_session(innerCallback: ErrorCallback) {
296
- create_session_and_repeat_if_failed(client, session, (err?: Error | null, _newSession?: ClientSessionImpl) => {
297
- // prettier-ignore
298
- {
299
- const err = _shouldNotContinue(session);
300
- if (err) {
301
- return innerCallback(err);
302
- }
303
- }
304
326
 
305
- if (_newSession) {
306
- newSession = _newSession;
307
- }
308
- innerCallback(err || undefined);
309
- });
310
- },
311
-
312
- function activate_new_session(innerCallback: ErrorCallback) {
313
- // prettier-ignore
314
- {
315
- const err = _shouldNotContinue(session);
316
- if (err) {
317
- return innerCallback(err);
318
- }
319
- }
327
+ subscriptionsToRecreate.push(subscriptionsIds[i]);
328
+ } else {
329
+ const availableSequenceNumbers = results[i].availableSequenceNumbers;
320
330
 
321
- doDebug && debugLog(chalk.bgWhite.red(" => activating a new session ...."));
322
-
323
- client._activateSession(
324
- newSession,
325
- newSession.userIdentityInfo!,
326
- (err: Error | null, session1?: ClientSessionImpl) => {
327
- // c8 ignore next
328
- doDebug && debugLog(" => activating a new session .... Done err=", err ? err.message : "null");
329
- if (err) {
330
- doDebug &&
331
- debugLog(
332
- "reactivation of the new session has failed: let be smart and close it before failing this repair attempt"
333
- );
334
- // but just on the server side, not on the client side
335
- const closeSessionRequest = new CloseSessionRequest({
336
- requestHeader: {
337
- authenticationToken: newSession.authenticationToken
338
- },
339
- deleteSubscriptions: true
340
- });
341
- newSession._client!.performMessageTransaction(closeSessionRequest, (err2?: Error | null) => {
342
- if (err2) {
343
- warningLog("closing session", err2.message);
344
- }
345
- // c8 ignore next
346
- doDebug && debugLog("the temporary replacement session is now closed");
347
- // c8 ignore next
348
- doDebug && debugLog(" err ", err.message, "propagated upwards");
349
- innerCallback(err);
350
- });
351
- } else {
352
- innerCallback(err ? err : undefined);
353
- }
354
- }
355
- );
356
- },
357
-
358
- function beforeSubscriptionRepair(innerCallback: ErrorCallback) {
359
- if (!client.beforeSubscriptionRecreate) {
360
- innerCallback();
361
- return;
362
- }
363
- client
364
- .beforeSubscriptionRecreate(newSession)
365
- .then((err) => {
366
- {
367
- const err = _shouldNotContinue(session);
368
- if (err) {
369
- return innerCallback(err);
370
- }
371
- }
372
- if (!err) {
373
- innerCallback();
374
- } else {
375
- innerCallback(err);
376
- }
377
- })
378
- .catch((err) => {
379
- innerCallback(err);
380
- });
381
- },
382
-
383
- function attempt_subscription_transfer(innerCallback: ErrorCallback) {
384
- // prettier-ignore
385
- {
386
- const err = _shouldNotContinue(session);
387
- if (err) {
388
- return innerCallback(err);
331
+ doDebug &&
332
+ debugLog(
333
+ chalk.green(" SUBSCRIPTION "),
334
+ subscriptionsIds[i],
335
+ chalk.green(" CAN BE REPAIRED AND AVAILABLE "),
336
+ availableSequenceNumbers
337
+ );
338
+ // should be Good.
389
339
  }
390
340
  }
341
+ doDebug && debugLog(" new session subscriptionCount = ", newSession.getPublishEngine().subscriptionCount);
391
342
 
392
- // get the old subscriptions id from the old session
393
- const subscriptionsIds = session.getPublishEngine().getSubscriptionIds();
343
+ recreateSubscriptions(session, newSession, subscriptionsToRecreate)
344
+ .then(() => resolve())
345
+ .catch((e) => reject(e));
346
+ }
347
+ );
348
+ });
349
+ }
394
350
 
395
- doDebug && debugLog(" session subscriptionCount = ", newSession.getPublishEngine().subscriptionCount);
396
- if (subscriptionsIds.length === 0) {
397
- doDebug && debugLog(" No subscriptions => skipping transfer subscriptions");
398
- return innerCallback(); // no need to transfer subscriptions
399
- }
400
- doDebug && debugLog(" => asking server to transfer subscriptions = [", subscriptionsIds.join(", "), "]");
351
+ async function repair_client_session_by_recreating_a_new_session_async(
352
+ client: IClientBase,
353
+ session: ClientSessionImpl
354
+ ): Promise<void> {
355
+ _throwIfShouldNotContinue(session);
401
356
 
402
- // Transfer subscriptions - ask for initial values....
403
- const subscriptionsToTransfer = new TransferSubscriptionsRequest({
404
- sendInitialValues: true,
405
- subscriptionIds: subscriptionsIds
406
- });
357
+ // As we don't know if server has been rebooted or not,
358
+ // and may be upgraded in between, we have to invalidate the extra data type manager
359
+ invalidateExtraDataTypeManager(session);
407
360
 
408
- if (newSession.getPublishEngine().nbPendingPublishRequests !== 0) {
409
- warningLog("Warning : we should not be publishing here");
410
- }
411
- newSession.transferSubscriptions(
412
- subscriptionsToTransfer,
413
- (err: Error | null, transferSubscriptionsResponse?: TransferSubscriptionsResponse) => {
414
- // may be the connection with server has been disconnected
415
- // prettier-ignore
416
- {
417
- const err = _shouldNotContinue(session);
418
- if (err) {
419
- return innerCallback(err);
420
- }
421
- }
361
+ // c8 ignore next
362
+ if (doDebug) {
363
+ debugLog(" repairing client session by_recreating a new session for old session ", session.sessionId.toString());
364
+ }
422
365
 
423
- if (err || !transferSubscriptionsResponse) {
424
- warningLog(chalk.bgCyan("May be the server is not supporting this feature"));
425
- // when transfer subscription has failed, we have no other choice but
426
- // recreate the subscriptions on the server side
427
- const subscriptionsToRecreate = [...(subscriptionsToTransfer.subscriptionIds || [])];
428
- warningLog(chalk.bgCyan("We need to recreate entirely the subscription"));
429
- recreateSubscription(subscriptionsToRecreate, innerCallback);
430
- return;
431
- }
366
+ const listenerCountBefore = session.listenerCount("");
432
367
 
433
- const results = transferSubscriptionsResponse.results || [];
434
- // c8 ignore next
435
- if (doDebug) {
436
- debugLog(
437
- chalk.cyan(" => transfer subscriptions done"),
438
- results.map((x: any) => x.statusCode.toString()).join(" ")
439
- );
440
- }
368
+ // Step 1: suspend old session publish engine
369
+ _throwIfShouldNotContinue(session);
370
+ // c8 ignore next
371
+ doDebug && debugLog(chalk.bgWhite.red(" => suspend old session publish engine...."));
372
+ session.getPublishEngine().suspend(true);
373
+
374
+ // Step 2: create new session
375
+ const newSession = await create_session_and_repeat_if_failed(client, session);
376
+ _throwIfShouldNotContinue(session);
377
+
378
+ // Step 3: activate new session
379
+ await activate_session(client, session, newSession);
380
+ _throwIfShouldNotContinue(session);
381
+
382
+ // Step 4: before subscription repair hook
383
+ if (client.beforeSubscriptionRecreate) {
384
+ const hookErr = await client.beforeSubscriptionRecreate(newSession);
385
+ _throwIfShouldNotContinue(session);
386
+ if (hookErr) {
387
+ throw hookErr;
388
+ }
389
+ }
441
390
 
442
- const subscriptionsToRecreate = [];
443
-
444
- // some subscriptions may be marked as invalid on the server side ...
445
- // those one need to be recreated and repaired ....
446
- for (let i = 0; i < results.length; i++) {
447
- const statusCode = results[i].statusCode;
448
- if (statusCode.equals(StatusCodes.BadSubscriptionIdInvalid)) {
449
- // repair subscription
450
- doDebug &&
451
- debugLog(
452
- chalk.red(" WARNING SUBSCRIPTION "),
453
- subscriptionsIds[i],
454
- chalk.red(" SHOULD BE RECREATED")
455
- );
456
-
457
- subscriptionsToRecreate.push(subscriptionsIds[i]);
458
- } else {
459
- const availableSequenceNumbers = results[i].availableSequenceNumbers;
460
-
461
- doDebug &&
462
- debugLog(
463
- chalk.green(" SUBSCRIPTION "),
464
- subscriptionsIds[i],
465
- chalk.green(" CAN BE REPAIRED AND AVAILABLE "),
466
- availableSequenceNumbers
467
- );
468
- // should be Good.
469
- }
470
- }
471
- doDebug && debugLog(" new session subscriptionCount = ", newSession.getPublishEngine().subscriptionCount);
391
+ // Step 5: attempt subscription transfer
392
+ await attempt_subscription_transfer(client, session, newSession);
393
+ _throwIfShouldNotContinue(session);
472
394
 
473
- recreateSubscription(subscriptionsToRecreate, innerCallback);
474
- }
475
- );
476
- },
477
-
478
- function ask_for_subscription_republish(innerCallback: ErrorCallback) {
479
- // prettier-ignore
480
- {
481
- const err = _shouldNotContinue(session);
482
- if (err) {
483
- return innerCallback(err);
484
- }
485
- }
395
+ // Step 6: ask for subscription republish
396
+ await new Promise<void>((resolve, reject) => {
397
+ _ask_for_subscription_republish(newSession, (err) => {
398
+ if (err) {
399
+ warningLog("warning: Subscription republished has failed ", err.message);
400
+ reject(err);
401
+ } else {
402
+ resolve();
403
+ }
404
+ });
405
+ });
406
+ _throwIfShouldNotContinue(session);
486
407
 
487
- // assert(newSession.getPublishEngine().nbPendingPublishRequests === 0, "we should not be publishing here");
488
- // call Republish
489
- return _ask_for_subscription_republish(newSession, (err) => {
490
- if (err) {
491
- warningLog("warning: Subscription republished has failed ", err.message);
492
- }
493
- innerCallback(err);
494
- });
495
- },
496
-
497
- function start_publishing_as_normal(innerCallback: ErrorCallback) {
498
- // prettier-ignore
499
- {
500
- const err = _shouldNotContinue(session);
501
- if (err) {
502
- return innerCallback(err);
503
- }
504
- }
408
+ // Step 7: start publishing as normal
409
+ newSession.getPublishEngine().suspend(false);
505
410
 
506
- newSession.getPublishEngine().suspend(false);
411
+ const listenerCountAfter = session.listenerCount("");
412
+ assert(newSession === session);
413
+ doDebug && debugLog("listenerCountBefore =", listenerCountBefore, "listenerCountAfter = ", listenerCountAfter);
414
+ }
507
415
 
508
- const listenerCountAfter = session.listenerCount("");
509
- assert(newSession === session);
510
- doDebug && debugLog("listenerCountBefore =", listenerCountBefore, "listenerCountAfter = ", listenerCountAfter);
511
- innerCallback();
512
- }
513
- ],
514
- (err) => {
515
- doDebug && err && debugLog("repair_client_session_by_recreating_a_new_session failed with ", err.message);
516
- callback(err!);
517
- }
518
- );
416
+ function repair_client_session_by_recreating_a_new_session(
417
+ client: IClientBase,
418
+ session: ClientSessionImpl,
419
+ callback: (err?: Error) => void
420
+ ) {
421
+ repair_client_session_by_recreating_a_new_session_async(client, session)
422
+ .then(() => callback())
423
+ .catch((err) => {
424
+ doDebug && debugLog("repair_client_session_by_recreating_a_new_session failed with ", err.message);
425
+ callback(err);
426
+ });
519
427
  }
520
428
 
521
429
  function _repair_client_session(client: IClientBase, session: ClientSessionImpl, callback: (err?: Error) => void): void {
@@ -543,7 +451,7 @@ function _repair_client_session(client: IClientBase, session: ClientSessionImpl,
543
451
  }
544
452
  }
545
453
 
546
- client._activateSession(session, session.userIdentityInfo!, (err: Error | null, session2?: ClientSessionImpl) => {
454
+ client._activateSession(session, session.userIdentityInfo!, (err: Error | null, _session2?: ClientSessionImpl) => {
547
455
  // prettier-ignore
548
456
  {
549
457
  const err = _shouldNotContinue(session);
@@ -575,7 +483,7 @@ export function repair_client_session(client: IClientBase, session: ClientSessio
575
483
  }
576
484
  doDebug && debugLog(chalk.yellow("Starting client session repair"));
577
485
 
578
- const privateSession = session as any as Reconnectable;
486
+ const privateSession = session as unknown as Reconnectable;
579
487
  privateSession._reconnecting = privateSession._reconnecting || { reconnecting: false, pendingCallbacks: [] };
580
488
 
581
489
  if (session.hasBeenClosed()) {
@@ -656,35 +564,36 @@ export function repair_client_session(client: IClientBase, session: ClientSessio
656
564
  // c8 ignore next
657
565
  if (transactionQueue.length > 0) {
658
566
  doDebug && debugLog(chalk.yellow("re-injecting transaction queue"), transactionQueue.length);
659
- transactionQueue.forEach((e: any) => privateSession._reconnecting.pendingTransactions.push(e));
567
+ transactionQueue.forEach((e) => privateSession._reconnecting.pendingTransactions.push(e));
660
568
  }
661
569
  otherCallbacks.forEach((c: EmptyCallback) => c(err));
662
570
  callback(err);
663
571
  });
664
572
  }
665
573
 
666
- export function repair_client_sessions(client: IClientBase, callback: (err?: Error) => void): void {
574
+ export async function repair_client_sessions(client: IClientBase, callback: (err?: Error) => void): Promise<void> {
667
575
  // repair session
668
576
  const sessions = client.getSessions();
669
577
  doDebug && debugLog(chalk.red.bgWhite(" Starting sessions reactivation", sessions.length));
670
- async.map(
671
- sessions,
672
- (session, next: (err: Error | null, err2: Error | null | undefined) => void) => {
578
+
579
+ const allErrors: (Error | undefined)[] = [];
580
+ for (const session of sessions) {
581
+ await new Promise<void>((resolve) => {
673
582
  repair_client_session(client, session as ClientSessionImpl, (err) => {
674
- next(null, err);
583
+ allErrors.push(err);
584
+ resolve();
675
585
  });
676
- },
677
- (err, allErrors: (undefined | Error | null)[] | undefined) => {
678
- err && errorLog("sessions reactivation completed with err: err ", err ? err.message : "null");
679
- // prettier-ignore
680
- {
681
- const err = _shouldNotContinue3(client);
682
- if (err) {
683
- return callback(err);
684
- }
685
- }
586
+ });
587
+ }
686
588
 
687
- return callback(err!);
589
+ // prettier-ignore
590
+ {
591
+ const err = _shouldNotContinue3(client);
592
+ if (err) {
593
+ return callback(err);
688
594
  }
689
- );
595
+ }
596
+
597
+ const firstError = allErrors.find((e) => e != null);
598
+ callback(firstError);
690
599
  }