node-opcua-client 2.123.0 → 2.125.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 (51) hide show
  1. package/dist/alarms_and_conditions/client_alarm_tools.js.map +1 -1
  2. package/dist/alarms_and_conditions/client_tools.js.map +1 -1
  3. package/dist/client_monitored_item_toolbox.js.map +1 -1
  4. package/dist/client_session_keepalive_manager.js.map +1 -1
  5. package/dist/client_utils.js.map +1 -1
  6. package/dist/private/client_base_impl.d.ts +11 -4
  7. package/dist/private/client_base_impl.js +130 -70
  8. package/dist/private/client_base_impl.js.map +1 -1
  9. package/dist/private/client_monitored_item_group_impl.js.map +1 -1
  10. package/dist/private/client_monitored_item_impl.js.map +1 -1
  11. package/dist/private/client_publish_engine.d.ts +9 -4
  12. package/dist/private/client_publish_engine.js +5 -99
  13. package/dist/private/client_publish_engine.js.map +1 -1
  14. package/dist/private/client_session_impl.d.ts +20 -4
  15. package/dist/private/client_session_impl.js +5 -24
  16. package/dist/private/client_session_impl.js.map +1 -1
  17. package/dist/private/client_subscription_impl.d.ts +5 -8
  18. package/dist/private/client_subscription_impl.js +83 -174
  19. package/dist/private/client_subscription_impl.js.map +1 -1
  20. package/dist/private/i_private_client.d.ts +0 -1
  21. package/dist/private/opcua_client_impl.js +1 -1
  22. package/dist/private/opcua_client_impl.js.map +1 -1
  23. package/dist/private/performance.js.map +1 -1
  24. package/dist/private/reconnection/client_publish_engine_reconnection.d.ts +2 -0
  25. package/dist/private/reconnection/client_publish_engine_reconnection.js +118 -0
  26. package/dist/private/reconnection/client_publish_engine_reconnection.js.map +1 -0
  27. package/dist/private/reconnection/client_reconnection.d.ts +2 -0
  28. package/dist/private/reconnection/client_reconnection.js +20 -0
  29. package/dist/private/reconnection/client_reconnection.js.map +1 -0
  30. package/dist/private/reconnection/client_subscription_reconnection.d.ts +7 -0
  31. package/dist/private/reconnection/client_subscription_reconnection.js +124 -0
  32. package/dist/private/reconnection/client_subscription_reconnection.js.map +1 -0
  33. package/dist/private/reconnection/reconnection.d.ts +12 -0
  34. package/dist/private/reconnection/reconnection.js +564 -0
  35. package/dist/private/reconnection/reconnection.js.map +1 -0
  36. package/dist/tools/findservers.js.map +1 -1
  37. package/dist/tools/read_history_server_capabilities.js.map +1 -1
  38. package/dist/verify.js.map +1 -1
  39. package/package.json +43 -43
  40. package/source/index.ts +4 -1
  41. package/source/opcua_client.ts +11 -5
  42. package/source/private/client_base_impl.ts +136 -81
  43. package/source/private/client_publish_engine.ts +13 -129
  44. package/source/private/client_session_impl.ts +56 -78
  45. package/source/private/client_subscription_impl.ts +85 -207
  46. package/source/private/i_private_client.ts +0 -2
  47. package/source/private/opcua_client_impl.ts +16 -149
  48. package/source/private/reconnection/client_publish_engine_reconnection.ts +146 -0
  49. package/source/private/reconnection/client_reconnection.ts +17 -0
  50. package/source/private/reconnection/client_subscription_reconnection.ts +124 -0
  51. package/source/{reconnection.ts → private/reconnection/reconnection.ts} +121 -76
@@ -3,7 +3,6 @@
3
3
  */
4
4
  // tslint:disable:unified-signatures
5
5
  import { EventEmitter } from "events";
6
- import async from "async";
7
6
  import chalk from "chalk";
8
7
 
9
8
  import { assert } from "node-opcua-assert";
@@ -13,14 +12,11 @@ import { resolveNodeId } from "node-opcua-nodeid";
13
12
 
14
13
  import { ReadValueIdOptions, TimestampsToReturn } from "node-opcua-service-read";
15
14
  import {
16
- CreateMonitoredItemsRequest,
17
- CreateMonitoredItemsResponse,
18
15
  CreateSubscriptionRequest,
19
16
  CreateSubscriptionResponse,
20
17
  DataChangeNotification,
21
18
  DeleteMonitoredItemsResponse,
22
19
  DeleteSubscriptionsResponse,
23
- MonitoredItemCreateRequestOptions,
24
20
  MonitoringParametersOptions,
25
21
  NotificationMessage,
26
22
  StatusChangeNotification,
@@ -37,9 +33,7 @@ import { StatusCode, StatusCodes } from "node-opcua-status-code";
37
33
  import { Callback, ErrorCallback } from "node-opcua-status-code";
38
34
  import { isNullOrUndefined } from "node-opcua-utils";
39
35
  import { promoteOpaqueStructureInNotificationData } from "node-opcua-client-dynamic-extension-object";
40
- import { createMonitoredItemsLimit, IBasicSessionReadAsync, readOperationLimits } from "node-opcua-pseudo-session";
41
36
 
42
- import { IBasicSessionWithSubscription } from "node-opcua-pseudo-session";
43
37
  import { ClientMonitoredItemBase } from "../client_monitored_item_base";
44
38
  import { ClientMonitoredItemGroup } from "../client_monitored_item_group";
45
39
  import { ClientSession, MonitoredItemData, SubscriptionId } from "../client_session";
@@ -59,13 +53,13 @@ import { ClientSidePublishEngine } from "./client_publish_engine";
59
53
  import { ClientSessionImpl } from "./client_session_impl";
60
54
  import { detectLongOperation } from "./performance";
61
55
 
62
- const debugLog = make_debugLog(__filename);
63
- const doDebug = checkDebugFlag(__filename);
64
- const warningLog = make_warningLog(__filename);
56
+ const debugLog = make_debugLog("CLIENT_SUBSCRIPTION");
57
+ const doDebug = checkDebugFlag("CLIENT_SUBSCRIPTION");
58
+ const warningLog = make_warningLog("CLIENT_SUBSCRIPTION");
65
59
 
66
- const PENDING_SUBSCRIPTION_ID = 0xc0cac01a;
67
- const TERMINATED_SUBSCRIPTION_ID = 0xc0cac01b;
68
- const TERMINATING_SUBSCRIPTION_ID = 0xc0cac01c;
60
+ export const PENDING_SUBSCRIPTION_ID = 0xc0cac01a;
61
+ export const TERMINATED_SUBSCRIPTION_ID = 0xc0cac01b;
62
+ export const TERMINATING_SUBSCRIPTION_ID = 0xc0cac01c;
69
63
 
70
64
  const minimumMaxKeepAliveCount = 3;
71
65
 
@@ -122,20 +116,6 @@ function displayKeepAliveWarning(sessionTimeout: number, maxKeepAliveCount: numb
122
116
  return false;
123
117
  }
124
118
 
125
- function createMonitoredItemsAndRespectOperationalLimits(
126
- session: IBasicSessionReadAsync & IBasicSessionWithSubscription,
127
- createMonitorItemsRequest: CreateMonitoredItemsRequest,
128
- callback: (err: Error | null, response?: CreateMonitoredItemsResponse) => void
129
- ) {
130
- readOperationLimits(session)
131
- .then((operationalLimits) => {
132
- createMonitoredItemsLimit(operationalLimits.maxMonitoredItemsPerCall || 0, session, createMonitorItemsRequest)
133
- .then((createMonitoredItemResponse) => callback(null, createMonitoredItemResponse))
134
- .catch(callback);
135
- })
136
- .catch(callback);
137
- }
138
-
139
119
  export class ClientSubscriptionImpl extends EventEmitter implements ClientSubscription {
140
120
  /**
141
121
  * the associated session
@@ -171,9 +151,8 @@ export class ClientSubscriptionImpl extends EventEmitter implements ClientSubscr
171
151
  public publishEngine: ClientSidePublishEngine;
172
152
 
173
153
  public lastSequenceNumber: number;
174
- private lastRequestSentTime: Date;
175
154
  private _nextClientHandle = 0;
176
- private hasTimedOut: boolean;
155
+ public hasTimedOut: boolean;
177
156
 
178
157
  constructor(session: ClientSession, options: ClientSubscriptionOptions) {
179
158
  super();
@@ -219,7 +198,7 @@ export class ClientSubscriptionImpl extends EventEmitter implements ClientSubscr
219
198
  this.lifetimeCount = options.requestedLifetimeCount;
220
199
  this.maxKeepAliveCount = options.requestedMaxKeepAliveCount;
221
200
  this.maxNotificationsPerPublish = options.maxNotificationsPerPublish || 0;
222
- this.publishingEnabled = options.publishingEnabled;
201
+ this.publishingEnabled = options.publishingEnabled === undefined ? true : options.publishingEnabled;
223
202
  this.priority = options.priority;
224
203
 
225
204
  this.subscriptionId = PENDING_SUBSCRIPTION_ID;
@@ -227,8 +206,6 @@ export class ClientSubscriptionImpl extends EventEmitter implements ClientSubscr
227
206
  this._nextClientHandle = 0;
228
207
  this.monitoredItems = {};
229
208
 
230
- this.lastRequestSentTime = new Date(1, 1, 1970);
231
-
232
209
  /**
233
210
  * set to True when the server has notified us that this subscription has timed out
234
211
  * ( maxLifeCounter x published interval without being able to process a PublishRequest
@@ -238,7 +215,7 @@ export class ClientSubscriptionImpl extends EventEmitter implements ClientSubscr
238
215
  this.hasTimedOut = false;
239
216
 
240
217
  setImmediate(() => {
241
- this.__create_subscription((err?: Error) => {
218
+ __create_subscription(this, (err?: Error) => {
242
219
  if (!err) {
243
220
  setImmediate(() => {
244
221
  /**
@@ -536,103 +513,6 @@ export class ClientSubscriptionImpl extends EventEmitter implements ClientSubscr
536
513
  this.session.getMonitoredItems(this.subscriptionId, args[0]);
537
514
  }
538
515
 
539
- /**
540
- * utility function to recreate new subscription
541
- * @method recreateSubscriptionAndMonitoredItem
542
- */
543
- public recreateSubscriptionAndMonitoredItem(callback: ErrorCallback): void {
544
- debugLog("ClientSubscription#recreateSubscriptionAndMonitoredItem");
545
-
546
- if (this.subscriptionId === TERMINATED_SUBSCRIPTION_ID) {
547
- debugLog("Subscription is not in a valid state");
548
- return callback();
549
- }
550
-
551
- const oldMonitoredItems = this.monitoredItems;
552
-
553
- this.publishEngine.unregisterSubscription(this.subscriptionId);
554
-
555
- async.series(
556
- [
557
- (innerCallback: ErrorCallback) => {
558
- this.__create_subscription(innerCallback);
559
- },
560
- (innerCallback: ErrorCallback) => {
561
- const test = this.publishEngine.getSubscription(this.subscriptionId);
562
-
563
- debugLog("recreating ", Object.keys(oldMonitoredItems).length, " monitored Items");
564
- // re-create monitored items
565
- const itemsToCreate: MonitoredItemCreateRequestOptions[] = [];
566
-
567
- for (const monitoredItem of Object.values(oldMonitoredItems)) {
568
- assert(monitoredItem.monitoringParameters.clientHandle > 0);
569
- itemsToCreate.push({
570
- itemToMonitor: monitoredItem.itemToMonitor,
571
- monitoringMode: monitoredItem.monitoringMode,
572
- requestedParameters: monitoredItem.monitoringParameters
573
- });
574
- }
575
-
576
- const createMonitorItemsRequest = new CreateMonitoredItemsRequest({
577
- itemsToCreate,
578
- subscriptionId: this.subscriptionId,
579
- timestampsToReturn: TimestampsToReturn.Both // this.timestampsToReturn,
580
- });
581
-
582
- const session = this.session;
583
- // istanbul ignore next
584
- if (!session) {
585
- return innerCallback(new Error("no session"));
586
- }
587
-
588
- debugLog("Recreating ", itemsToCreate.length, " monitored items");
589
-
590
- createMonitoredItemsAndRespectOperationalLimits(
591
- session,
592
- createMonitorItemsRequest,
593
- (err: Error | null, response?: CreateMonitoredItemsResponse) => {
594
- if (err) {
595
- debugLog("Recreating monitored item has failed with ", err.message);
596
- return innerCallback(err);
597
- }
598
- /* istanbul ignore next */
599
- if (!response) {
600
- return innerCallback(new Error("Internal Error"));
601
- }
602
- const monitoredItemResults = response.results || [];
603
-
604
- monitoredItemResults.forEach((monitoredItemResult, index) => {
605
- const itemToCreate = itemsToCreate[index];
606
- /* istanbul ignore next */
607
- if (!itemToCreate || !itemToCreate.requestedParameters) {
608
- throw new Error("Internal Error");
609
- }
610
- const clientHandle = itemToCreate.requestedParameters.clientHandle;
611
- /* istanbul ignore next */
612
- if (!clientHandle) {
613
- throw new Error("Internal Error");
614
- }
615
- const monitoredItem = this.monitoredItems[clientHandle] as ClientMonitoredItemImpl;
616
- if (monitoredItem) {
617
- monitoredItem._applyResult(monitoredItemResult);
618
- } else {
619
- warningLog("cannot find monitored item for clientHandle !:", clientHandle);
620
- }
621
- });
622
- innerCallback();
623
- }
624
- );
625
- }
626
- ],
627
- (err) => {
628
- if (err) {
629
- warningLog(err.message);
630
- }
631
- callback(err!);
632
- }
633
- );
634
- }
635
-
636
516
  public toString(): string {
637
517
  let str = "";
638
518
  str += "subscriptionId : " + this.subscriptionId + "\n";
@@ -642,9 +522,12 @@ export class ClientSubscriptionImpl extends EventEmitter implements ClientSubscr
642
522
  str += "hasTimedOut : " + this.hasTimedOut + "\n";
643
523
 
644
524
  const timeToLive = this.lifetimeCount * this.publishingInterval;
645
- str += "timeToLive : " + timeToLive + "\n";
646
- str += "lastRequestSentTime : " + this.lastRequestSentTime.toString() + "\n";
647
- const duration = Date.now() - this.lastRequestSentTime.getTime();
525
+ str += "(maxKeepAliveCount*publishingInterval: " + this.publishingInterval * this.maxKeepAliveCount + " ms)\n";
526
+ str += "(maxLifetimeCount*publishingInterval: " + timeToLive + " ms)\n";
527
+
528
+ const lastRequestSentTime = this.publishEngine.lastRequestSentTime;
529
+ str += "lastRequestSentTime : " + lastRequestSentTime.toString() + "\n";
530
+ const duration = Date.now() - lastRequestSentTime.getTime();
648
531
  const extra =
649
532
  duration - timeToLive > 0
650
533
  ? chalk.red(" expired since " + (duration - timeToLive) / 1000 + " seconds")
@@ -654,7 +537,6 @@ export class ClientSubscriptionImpl extends EventEmitter implements ClientSubscr
654
537
  str += "has expired : " + (duration > timeToLive) + "\n";
655
538
 
656
539
  str += "(session timeout : " + this.session.timeout + " ms)\n";
657
- str += "(maxKeepAliveCount*publishingInterval: " + this.publishingInterval * this.session.timeout + " ms)\n";
658
540
 
659
541
  return str;
660
542
  }
@@ -665,7 +547,8 @@ export class ClientSubscriptionImpl extends EventEmitter implements ClientSubscr
665
547
  public evaluateRemainingLifetime(): number {
666
548
  const now = Date.now();
667
549
  const timeout = this.publishingInterval * this.lifetimeCount;
668
- const expiryTime = this.lastRequestSentTime.getTime() + timeout;
550
+ const lastRequestSentTime = this.publishEngine.lastRequestSentTime;
551
+ const expiryTime = lastRequestSentTime.getTime() + timeout;
669
552
  return Math.max(0, expiryTime - now);
670
553
  }
671
554
 
@@ -710,75 +593,6 @@ export class ClientSubscriptionImpl extends EventEmitter implements ClientSubscr
710
593
  setImmediate(waitForSubscriptionAndMonitor);
711
594
  }
712
595
 
713
- private __create_subscription(callback: ErrorCallback) {
714
- assert(typeof callback === "function");
715
-
716
- // istanbul ignore next
717
- if (!this.hasSession) {
718
- return callback(new Error("No Session"));
719
- }
720
- const session = this.session;
721
-
722
- debugLog(chalk.yellow.bold("ClientSubscription created "));
723
-
724
- const request = new CreateSubscriptionRequest({
725
- maxNotificationsPerPublish: this.maxNotificationsPerPublish,
726
- priority: this.priority,
727
- publishingEnabled: this.publishingEnabled,
728
- requestedLifetimeCount: this.lifetimeCount,
729
- requestedMaxKeepAliveCount: this.maxKeepAliveCount,
730
- requestedPublishingInterval: this.publishingInterval
731
- });
732
-
733
- session.createSubscription(request, (err: Error | null, response?: CreateSubscriptionResponse) => {
734
- if (err) {
735
- /* istanbul ignore next */
736
- this.emit("internal_error", err);
737
- if (callback) {
738
- return callback(err);
739
- }
740
- return;
741
- }
742
-
743
- /* istanbul ignore next */
744
- if (!response) {
745
- return callback(new Error("internal error"));
746
- }
747
-
748
- if (!this.hasSession) {
749
- return callback(new Error("createSubscription has failed = > no session"));
750
- }
751
- assert(this.hasSession);
752
-
753
- this.subscriptionId = response.subscriptionId;
754
- this.publishingInterval = response.revisedPublishingInterval;
755
- this.lifetimeCount = response.revisedLifetimeCount;
756
- this.maxKeepAliveCount = response.revisedMaxKeepAliveCount;
757
-
758
- this.timeoutHint = Math.min((this.maxKeepAliveCount + 10) * this.publishingInterval * 2, 0x7ffff);
759
-
760
- displayKeepAliveWarning(this.session.timeout, this.maxKeepAliveCount, this.publishingInterval);
761
- ClientSubscription.ignoreNextWarning = false;
762
-
763
- // istanbul ignore next
764
- if (doDebug) {
765
- debugLog(chalk.yellow.bold("registering callback"));
766
- debugLog(chalk.yellow.bold("publishingInterval "), this.publishingInterval);
767
- debugLog(chalk.yellow.bold("lifetimeCount "), this.lifetimeCount);
768
- debugLog(chalk.yellow.bold("maxKeepAliveCount "), this.maxKeepAliveCount);
769
- debugLog(chalk.yellow.bold("publish request timeout hint = "), this.timeoutHint);
770
- debugLog(chalk.yellow.bold("hasTimedOut "), this.hasTimedOut);
771
- debugLog(chalk.yellow.bold("timeoutHint for publish request "), this.timeoutHint);
772
- }
773
-
774
- this.publishEngine.registerSubscription(this);
775
-
776
- if (callback) {
777
- callback();
778
- }
779
- });
780
- }
781
-
782
596
  private __on_publish_response_DataChangeNotification(notification: DataChangeNotification) {
783
597
  assert(notification.schema.name === "DataChangeNotification");
784
598
 
@@ -939,7 +753,7 @@ export class ClientSubscriptionImpl extends EventEmitter implements ClientSubscr
939
753
  warningLog(
940
754
  `[NODE-OPCUA-W32]}: monitored.item event handler takes too much time : operation duration ${duration} ms [repeated ${
941
755
  s(this).$_slowNotifCount
942
- } times]\n please ensure that your monitoreItem event handler is not blocking the event loop.`
756
+ } times]\n please ensure that your monitoredItem event handler is not blocking the event loop.`
943
757
  );
944
758
  }
945
759
  );
@@ -1057,12 +871,76 @@ ClientSubscriptionImpl.prototype.monitor = thenify.withCallback(ClientSubscripti
1057
871
  ClientSubscriptionImpl.prototype.monitorItems = thenify.withCallback(ClientSubscriptionImpl.prototype.monitorItems);
1058
872
  ClientSubscriptionImpl.prototype.setTriggering = thenify.withCallback(ClientSubscriptionImpl.prototype.setTriggering);
1059
873
  ClientSubscriptionImpl.prototype.modify = thenify.withCallback(ClientSubscriptionImpl.prototype.modify);
1060
- ClientSubscriptionImpl.prototype.recreateSubscriptionAndMonitoredItem = thenify.withCallback(
1061
- ClientSubscriptionImpl.prototype.recreateSubscriptionAndMonitoredItem
1062
- );
1063
874
  ClientSubscriptionImpl.prototype.terminate = thenify.withCallback(ClientSubscriptionImpl.prototype.terminate);
1064
875
  ClientSubscriptionImpl.prototype.getMonitoredItems = thenify.withCallback(ClientSubscriptionImpl.prototype.getMonitoredItems);
1065
876
 
1066
877
  ClientSubscription.create = (clientSession: ClientSession, options: ClientSubscriptionOptions) => {
1067
878
  return new ClientSubscriptionImpl(clientSession, options);
1068
879
  };
880
+
881
+ export function __create_subscription(subscription: ClientSubscriptionImpl, callback: ErrorCallback) {
882
+ // istanbul ignore next
883
+ if (!subscription.hasSession) {
884
+ return callback(new Error("__create_subscription: subscription has no Session"));
885
+ }
886
+ const session = subscription.session;
887
+
888
+ debugLog(chalk.yellow.bold("ClientSubscription created "));
889
+
890
+ const request = new CreateSubscriptionRequest({
891
+ maxNotificationsPerPublish: subscription.maxNotificationsPerPublish,
892
+ priority: subscription.priority,
893
+ publishingEnabled: subscription.publishingEnabled,
894
+ requestedLifetimeCount: subscription.lifetimeCount,
895
+ requestedMaxKeepAliveCount: subscription.maxKeepAliveCount,
896
+ requestedPublishingInterval: subscription.publishingInterval
897
+ });
898
+
899
+ session.createSubscription(request, (err: Error | null, response?: CreateSubscriptionResponse) => {
900
+ if (err) {
901
+ /* istanbul ignore next */
902
+ subscription.emit("internal_error", err);
903
+ if (callback) {
904
+ return callback(err);
905
+ }
906
+ return;
907
+ }
908
+
909
+ /* istanbul ignore next */
910
+ if (!response) {
911
+ return callback(new Error("internal error"));
912
+ }
913
+
914
+ if (!subscription.hasSession) {
915
+ return callback(new Error("createSubscription has failed = > no session"));
916
+ }
917
+ assert(subscription.hasSession);
918
+
919
+ subscription.subscriptionId = response.subscriptionId;
920
+ subscription.publishingInterval = response.revisedPublishingInterval;
921
+ subscription.lifetimeCount = response.revisedLifetimeCount;
922
+ subscription.maxKeepAliveCount = response.revisedMaxKeepAliveCount;
923
+
924
+ subscription.timeoutHint = Math.min((subscription.maxKeepAliveCount + 10) * subscription.publishingInterval * 2, 0x7ffff);
925
+
926
+ displayKeepAliveWarning(subscription.session.timeout, subscription.maxKeepAliveCount, subscription.publishingInterval);
927
+ ClientSubscription.ignoreNextWarning = false;
928
+
929
+ // istanbul ignore next
930
+ if (doDebug) {
931
+ debugLog(chalk.yellow.bold("registering callback"));
932
+ debugLog(chalk.yellow.bold("publishingInterval "), subscription.publishingInterval);
933
+ debugLog(chalk.yellow.bold("lifetimeCount "), subscription.lifetimeCount);
934
+ debugLog(chalk.yellow.bold("maxKeepAliveCount "), subscription.maxKeepAliveCount);
935
+ debugLog(chalk.yellow.bold("publish request timeout hint = "), subscription.timeoutHint);
936
+ debugLog(chalk.yellow.bold("hasTimedOut "), subscription.hasTimedOut);
937
+ debugLog(chalk.yellow.bold("timeoutHint for publish request "), subscription.timeoutHint);
938
+ }
939
+
940
+ subscription.publishEngine.registerSubscription(subscription);
941
+
942
+ if (callback) {
943
+ callback();
944
+ }
945
+ });
946
+ }
@@ -27,7 +27,5 @@ export interface IClientBase {
27
27
 
28
28
  getTransportSettings(): IBasicTransportSettings;
29
29
 
30
- requestReconnection(): void;
31
-
32
30
  isUnusable(): boolean;
33
31
  }
@@ -3,7 +3,6 @@
3
3
  */
4
4
  import { callbackify } from "util";
5
5
  import { randomBytes, createPublicKey } from "crypto";
6
- import async from "async";
7
6
  import chalk from "chalk";
8
7
 
9
8
  import { assert } from "node-opcua-assert";
@@ -38,6 +37,7 @@ import { ErrorCallback, Callback } from "node-opcua-status-code";
38
37
 
39
38
  import { SignatureDataOptions, UserIdentityToken } from "node-opcua-types";
40
39
  import { isNullOrUndefined, matchUri } from "node-opcua-utils";
40
+ import { readNamespaceArray } from "node-opcua-pseudo-session";
41
41
 
42
42
  import { ClientSession } from "../client_session";
43
43
  import { ClientSubscription, ClientSubscriptionOptions } from "../client_subscription";
@@ -51,7 +51,7 @@ import {
51
51
  } from "../opcua_client";
52
52
  import { AnonymousIdentity, UserIdentityInfo, UserIdentityInfoUserName, UserIdentityInfoX509 } from "../user_identity_info";
53
53
 
54
- import { repair_client_sessions } from "../reconnection";
54
+ import { repair_client_sessions } from "./reconnection/reconnection";
55
55
  import { ClientBaseImpl } from "./client_base_impl";
56
56
  import { ClientSessionImpl } from "./client_session_impl";
57
57
  import { ClientSubscriptionImpl } from "./client_subscription_impl";
@@ -603,151 +603,14 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
603
603
  });
604
604
  return session;
605
605
  }
606
+
606
607
  /**
607
- * @method withSession
608
- */
609
- public withSession<T>(
610
- endpointUrl: string | EndpointWithUserIdentity,
611
- inner_func: (session: ClientSession) => Promise<T>
612
- ): Promise<T>;
613
-
614
- public withSession(
615
- endpointUrl: string | EndpointWithUserIdentity,
616
- inner_func: (session: ClientSession, done: (err?: Error) => void) => void,
617
- callback: (err?: Error) => void
618
- ): void;
619
- /**
620
- * @internal
621
- * @param args
608
+ *
609
+ * @param connectionPoint
610
+ * @param func
611
+ * @returns
622
612
  */
623
- public withSession(
624
- connectionPoint: string | EndpointWithUserIdentity,
625
- inner_func: (session: ClientSession, done: (err?: Error) => void) => void,
626
- ...args: any[]
627
- ): any {
628
- const endpointUrl: string = typeof connectionPoint === "string" ? connectionPoint : connectionPoint.endpointUrl;
629
- const userIdentity: UserIdentityInfo =
630
- typeof connectionPoint === "string" ? { type: UserTokenType.Anonymous } : connectionPoint.userIdentity;
631
-
632
- const callback = args[0];
633
-
634
- assert(typeof inner_func === "function", "expecting inner function");
635
- assert(typeof callback === "function", "expecting callback function");
636
-
637
- let theSession: ClientSession;
638
- let the_error: Error | undefined;
639
-
640
- let need_disconnect = false;
641
- async.series(
642
- [
643
- // step 1 : connect to
644
- (innerCallback: ErrorCallback) => {
645
- this.connect(endpointUrl, (err?: Error) => {
646
- need_disconnect = true;
647
- if (err) {
648
- warningLog(err.message);
649
- errorLog(" cannot connect to endpoint :", endpointUrl);
650
- }
651
- innerCallback(err);
652
- });
653
- },
654
-
655
- // step 2 : createSession
656
- (innerCallback: ErrorCallback) => {
657
- this.createSession2(userIdentity, (err: Error | null, session?: ClientSession) => {
658
- if (err) {
659
- return innerCallback(err);
660
- }
661
- if (!session) {
662
- return innerCallback(new Error("internal error"));
663
- }
664
- theSession = session;
665
- innerCallback();
666
- });
667
- },
668
-
669
- (innerCallback: ErrorCallback) => {
670
- try {
671
- inner_func(theSession, (err?: Error) => {
672
- the_error = err;
673
- innerCallback();
674
- });
675
- } catch (err) {
676
- errorLog("Exception catch in inner function, check your code ", err);
677
- errorLog("OPCUAClientImpl#withClientSession", (<Error>err).message);
678
- the_error = err as Error;
679
- innerCallback();
680
- }
681
- },
682
-
683
- // close session
684
- (innerCallback: ErrorCallback) => {
685
- theSession.close(/*deleteSubscriptions=*/ true, (err?: Error) => {
686
- if (err) {
687
- debugLog("OPCUAClientImpl#withClientSession: session closed failed ?");
688
- }
689
- innerCallback();
690
- });
691
- },
692
-
693
- (innerCallback: ErrorCallback) => {
694
- this.disconnect((err?: Error) => {
695
- need_disconnect = false;
696
- if (err) {
697
- errorLog("OPCUAClientImpl#withClientSession: client disconnect failed ?");
698
- }
699
- innerCallback();
700
- });
701
- }
702
- ],
703
- (err1) => {
704
- if (err1) {
705
- errorLog("err", err1.message);
706
- }
707
- if (need_disconnect) {
708
- errorLog("Disconnecting client after failure");
709
- this.disconnect((err2) => {
710
- return callback(the_error || err1 || err2);
711
- });
712
- } else {
713
- return callback(the_error || err1);
714
- }
715
- }
716
- );
717
- }
718
-
719
- public withSubscription(
720
- endpointUrl: string | EndpointWithUserIdentity,
721
- subscriptionParameters: ClientSubscriptionOptions,
722
- innerFunc: (session: ClientSession, subscription: ClientSubscription, done: (err?: Error) => void) => void,
723
- callback: (err?: Error) => void
724
- ): void {
725
- assert(typeof innerFunc === "function");
726
- assert(typeof callback === "function");
727
-
728
- this.withSession(
729
- endpointUrl,
730
- (session: ClientSession, done: (err?: Error) => void) => {
731
- assert(typeof done === "function");
732
-
733
- const subscription = new ClientSubscriptionImpl(session as ClientSessionImpl, subscriptionParameters);
734
-
735
- try {
736
- innerFunc(session, subscription, (err?: Error) => {
737
- subscription.terminate((err1?: Error) => {
738
- done(err1);
739
- });
740
- });
741
- } catch (err) {
742
- debugLog(err);
743
- done(err as Error);
744
- }
745
- },
746
- callback
747
- );
748
- }
749
-
750
- public async withSessionAsync(connectionPoint: string | EndpointWithUserIdentity, func: WithSessionFuncP<any>): Promise<any> {
613
+ public async withSessionAsync<T>(connectionPoint: string | EndpointWithUserIdentity, func: WithSessionFuncP<T>): Promise<T> {
751
614
  assert(typeof func === "function");
752
615
  assert(func.length === 1, "expecting a single argument in func");
753
616
 
@@ -764,6 +627,10 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
764
627
  try {
765
628
  const session = await this.createSession2(userIdentity);
766
629
  let result;
630
+
631
+ // always need this
632
+ await readNamespaceArray(session);
633
+
767
634
  try {
768
635
  result = await func(session);
769
636
  return result;
@@ -781,12 +648,12 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
781
648
  }
782
649
  }
783
650
 
784
- public async withSubscriptionAsync(
651
+ public async withSubscriptionAsync<T>(
785
652
  connectionPoint: string | EndpointWithUserIdentity,
786
653
  parameters: ClientSubscriptionOptions,
787
- func: WithSubscriptionFuncP<any>
788
- ): Promise<any> {
789
- await this.withSessionAsync(connectionPoint, async (session: ClientSession) => {
654
+ func: WithSubscriptionFuncP<T>
655
+ ): Promise<T> {
656
+ return await this.withSessionAsync(connectionPoint, async (session: ClientSession) => {
790
657
  assert(session, " session must exist");
791
658
  const subscription = await session.createSubscription2(parameters);
792
659
  try {