node-opcua-client 2.124.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-opcua-client",
3
- "version": "2.124.0",
3
+ "version": "2.125.0",
4
4
  "description": "pure nodejs OPCUA SDK - module client",
5
5
  "scripts": {
6
6
  "clean": "npx rimraf node_modules dist *.tsbuildinfo certificates",
@@ -17,58 +17,58 @@
17
17
  "@types/async": "^3.2.24",
18
18
  "async": "^3.2.5",
19
19
  "chalk": "4.1.2",
20
- "node-opcua-alarm-condition": "2.124.0",
20
+ "node-opcua-alarm-condition": "2.125.0",
21
21
  "node-opcua-assert": "2.120.0",
22
- "node-opcua-basic-types": "2.121.0",
23
- "node-opcua-buffer-utils": "2.120.0",
24
- "node-opcua-certificate-manager": "2.121.0",
25
- "node-opcua-client-dynamic-extension-object": "2.124.0",
26
- "node-opcua-common": "2.123.0",
27
- "node-opcua-constants": "2.121.0",
22
+ "node-opcua-basic-types": "2.125.0",
23
+ "node-opcua-buffer-utils": "2.125.0",
24
+ "node-opcua-certificate-manager": "2.125.0",
25
+ "node-opcua-client-dynamic-extension-object": "2.125.0",
26
+ "node-opcua-common": "2.125.0",
27
+ "node-opcua-constants": "2.125.0",
28
28
  "node-opcua-crypto": "4.8.0",
29
- "node-opcua-data-model": "2.121.0",
30
- "node-opcua-data-value": "2.121.0",
31
- "node-opcua-date-time": "2.121.0",
32
- "node-opcua-debug": "2.121.0",
33
- "node-opcua-extension-object": "2.121.0",
29
+ "node-opcua-data-model": "2.125.0",
30
+ "node-opcua-data-value": "2.125.0",
31
+ "node-opcua-date-time": "2.125.0",
32
+ "node-opcua-debug": "2.125.0",
33
+ "node-opcua-extension-object": "2.125.0",
34
34
  "node-opcua-hostname": "2.120.0",
35
- "node-opcua-nodeid": "2.121.0",
36
- "node-opcua-object-registry": "2.121.0",
35
+ "node-opcua-nodeid": "2.125.0",
36
+ "node-opcua-object-registry": "2.125.0",
37
37
  "node-opcua-pki": "4.10.0",
38
- "node-opcua-pseudo-session": "2.124.0",
39
- "node-opcua-schemas": "2.123.0",
40
- "node-opcua-secure-channel": "2.124.0",
41
- "node-opcua-service-browse": "2.123.0",
42
- "node-opcua-service-call": "2.123.0",
43
- "node-opcua-service-discovery": "2.123.0",
44
- "node-opcua-service-endpoints": "2.123.0",
45
- "node-opcua-service-filter": "2.123.0",
46
- "node-opcua-service-history": "2.123.0",
47
- "node-opcua-service-query": "2.123.0",
48
- "node-opcua-service-read": "2.123.0",
49
- "node-opcua-service-register-node": "2.123.0",
50
- "node-opcua-service-secure-channel": "2.123.0",
51
- "node-opcua-service-session": "2.123.0",
52
- "node-opcua-service-subscription": "2.124.0",
53
- "node-opcua-service-translate-browse-path": "2.123.0",
54
- "node-opcua-service-write": "2.123.0",
55
- "node-opcua-status-code": "2.121.0",
56
- "node-opcua-types": "2.123.0",
57
- "node-opcua-utils": "2.120.0",
58
- "node-opcua-variant": "2.121.0",
38
+ "node-opcua-pseudo-session": "2.125.0",
39
+ "node-opcua-schemas": "2.125.0",
40
+ "node-opcua-secure-channel": "2.125.0",
41
+ "node-opcua-service-browse": "2.125.0",
42
+ "node-opcua-service-call": "2.125.0",
43
+ "node-opcua-service-discovery": "2.125.0",
44
+ "node-opcua-service-endpoints": "2.125.0",
45
+ "node-opcua-service-filter": "2.125.0",
46
+ "node-opcua-service-history": "2.125.0",
47
+ "node-opcua-service-query": "2.125.0",
48
+ "node-opcua-service-read": "2.125.0",
49
+ "node-opcua-service-register-node": "2.125.0",
50
+ "node-opcua-service-secure-channel": "2.125.0",
51
+ "node-opcua-service-session": "2.125.0",
52
+ "node-opcua-service-subscription": "2.125.0",
53
+ "node-opcua-service-translate-browse-path": "2.125.0",
54
+ "node-opcua-service-write": "2.125.0",
55
+ "node-opcua-status-code": "2.125.0",
56
+ "node-opcua-types": "2.125.0",
57
+ "node-opcua-utils": "2.125.0",
58
+ "node-opcua-variant": "2.125.0",
59
59
  "thenify": "^3.3.1"
60
60
  },
61
61
  "devDependencies": {
62
62
  "@types/underscore": "^1.11.15",
63
63
  "dequeue": "^1.0.5",
64
- "mocha": "^10.3.0",
65
- "node-opcua-address-space": "2.124.0",
66
- "node-opcua-binary-stream": "2.120.0",
67
- "node-opcua-factory": "2.121.0",
68
- "node-opcua-leak-detector": "2.121.0",
64
+ "mocha": "^10.4.0",
65
+ "node-opcua-address-space": "2.125.0",
66
+ "node-opcua-binary-stream": "2.125.0",
67
+ "node-opcua-factory": "2.125.0",
68
+ "node-opcua-leak-detector": "2.125.0",
69
69
  "node-opcua-nodesets": "2.121.0",
70
70
  "should": "^13.2.3",
71
- "sinon": "^17.0.1",
71
+ "sinon": "^18.0.0",
72
72
  "underscore": "^1.13.6"
73
73
  },
74
74
  "eslintConfig": {
@@ -91,7 +91,7 @@
91
91
  "internet of things"
92
92
  ],
93
93
  "homepage": "http://node-opcua.github.io/",
94
- "gitHead": "75b5e34e797094a83833ea2d7c72ca3e5983d648",
94
+ "gitHead": "a0e0a2f1045e6e402dd4619c625c90008f0617ed",
95
95
  "files": [
96
96
  "dist",
97
97
  "source"
package/source/index.ts CHANGED
@@ -45,9 +45,10 @@ export {
45
45
  sameNodeId,
46
46
  ExpandedNodeId,
47
47
  makeExpandedNodeId,
48
+ NodeIdLike,
48
49
  coerceExpandedNodeId
49
50
  } from "node-opcua-nodeid";
50
- export { StatusCode, StatusCodes } from "node-opcua-status-code";
51
+ export { StatusCode, StatusCodes, ErrorCallback } from "node-opcua-status-code";
51
52
  export * from "node-opcua-variant";
52
53
  export * from "node-opcua-data-value";
53
54
  export * from "node-opcua-data-model";
@@ -71,3 +72,5 @@ export * from "node-opcua-service-write";
71
72
  export * from "node-opcua-service-filter";
72
73
  export * from "node-opcua-pseudo-session";
73
74
  export * from "node-opcua-client-dynamic-extension-object";
75
+ export { DataTypeDefinition } from "node-opcua-types";
76
+ export { checkDebugFlag, make_debugLog, make_warningLog } from "node-opcua-debug";
@@ -97,14 +97,20 @@ export type WithSubscriptionFunc = (session: ClientSession, subscription: Client
97
97
  export type WithSubscriptionFuncP<T> = (session: ClientSession, subscription: ClientSubscription) => Promise<T>;
98
98
 
99
99
  export interface OPCUAClient {
100
+ /**
101
+ *
102
+ * @param endpointUrl
103
+ * @param inner_func
104
+ */
100
105
  withSessionAsync<T>(endpointUrl: string | EndpointWithUserIdentity, inner_func: WithSessionFuncP<T>): Promise<T>;
101
106
 
102
- withSession(
103
- endpointUrl: string | EndpointWithUserIdentity,
104
- inner_func: (session: ClientSession, done: (err?: Error) => void) => void,
105
- callback: (err?: Error) => void
106
- ): void;
107
107
 
108
+ /**
109
+ *
110
+ * @param endpointUrl
111
+ * @param parameters
112
+ * @param inner_func
113
+ */
108
114
  withSubscriptionAsync<T>(
109
115
  endpointUrl: string | EndpointWithUserIdentity,
110
116
  parameters: ClientSubscriptionOptions,
@@ -29,7 +29,8 @@ import {
29
29
  NodeAttributes,
30
30
  ResponseCallback,
31
31
  BrowseDescriptionLike,
32
- IBasicSessionAsync2
32
+ IBasicSessionAsync2,
33
+ readNamespaceArray
33
34
  } from "node-opcua-pseudo-session";
34
35
  import { AnyConstructorFunc } from "node-opcua-schemas";
35
36
  import { ClientSecureChannelLayer, requestHandleNotSetValue, SignatureData } from "node-opcua-secure-channel";
@@ -221,7 +222,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
221
222
  public _closeEventHasBeenEmitted: boolean;
222
223
  private _publishEngine: ClientSidePublishEngine | null;
223
224
  private _keepAliveManager?: ClientSessionKeepAliveManager;
224
- private _namespaceArray?: any;
225
+ private $$namespaceArray?: string[];
225
226
  private recursive_repair_detector = 0;
226
227
 
227
228
  constructor(client: IClientBase) {
@@ -270,6 +271,9 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
270
271
  return this._client ? this._client.isReconnecting || this._reconnecting?.reconnecting : false;
271
272
  }
272
273
 
274
+ protected resolveNodeId(nodeId: NodeIdLike): NodeIdLike {
275
+ return resolveNodeId(nodeId);
276
+ }
273
277
  public getPublishEngine(): ClientSidePublishEngine {
274
278
  if (!this._publishEngine) {
275
279
  this._publishEngine = new ClientSidePublishEngine(this);
@@ -406,8 +410,8 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
406
410
  if (r.references && r.references.length > this.requestedMaxReferencesPerNode) {
407
411
  warningLog(
408
412
  chalk.yellow("warning") +
409
- " BrowseResponse : the server didn't take into" +
410
- " account our requestedMaxReferencesPerNode "
413
+ " BrowseResponse : the server didn't take into" +
414
+ " account our requestedMaxReferencesPerNode "
411
415
  );
412
416
  warningLog(" this.requestedMaxReferencesPerNode= " + this.requestedMaxReferencesPerNode);
413
417
  warningLog(" got " + r.references.length + "for " + nodesToBrowse[i].nodeId.toString());
@@ -416,7 +420,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
416
420
  }
417
421
  }
418
422
  for (const r of results) {
419
- r.references = r.references || /* istanbul ignore next */ [];
423
+ r.references = r.references || /* istanbul ignore next */[];
420
424
  }
421
425
  assert(results[0] instanceof BrowseResult);
422
426
  return callback(null, isArray ? results : results[0]);
@@ -652,7 +656,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
652
656
  continuationPoint: undefined,
653
657
  dataEncoding: undefined, // {namespaceIndex: 0, name: undefined},
654
658
  indexRange: undefined,
655
- nodeId: resolveNodeId(node as NodeIdLike)
659
+ nodeId: this.resolveNodeId(node as NodeIdLike)
656
660
  });
657
661
  } else {
658
662
  nodesToRead.push(node as HistoryReadValueIdOptions);
@@ -715,7 +719,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
715
719
  return callback(new Error(response.responseHeader.serviceResult.toString()));
716
720
  }
717
721
 
718
- response.results = response.results || /* istanbul ignore next */ [];
722
+ response.results = response.results || /* istanbul ignore next */[];
719
723
  callback(null, response);
720
724
  });
721
725
  }
@@ -847,7 +851,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
847
851
  return callback(new Error(response.responseHeader.serviceResult.toString()));
848
852
  }
849
853
 
850
- response.results = response.results || /* istanbul ignore next */ [];
854
+ response.results = response.results || /* istanbul ignore next */[];
851
855
 
852
856
  assert(nodesToRead.length === response.results.length);
853
857
 
@@ -990,7 +994,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
990
994
  if (response.responseHeader.serviceResult.isNot(StatusCodes.Good)) {
991
995
  return callback(new Error(response.responseHeader.serviceResult.toString()));
992
996
  }
993
- response.results = response.results || /* istanbul ignore next */ [];
997
+ response.results = response.results || /* istanbul ignore next */[];
994
998
  assert(nodesToWrite.length === response.results.length);
995
999
  callback(null, isArray ? response.results : response.results[0]);
996
1000
  });
@@ -1046,7 +1050,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
1046
1050
  const nodeToWrite = new WriteValue({
1047
1051
  attributeId: AttributeIds.Value,
1048
1052
  indexRange: undefined,
1049
- nodeId: resolveNodeId(nodeId),
1053
+ nodeId: this.resolveNodeId(nodeId),
1050
1054
  value: new DataValue({ value })
1051
1055
  });
1052
1056
 
@@ -1162,6 +1166,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
1162
1166
  * @param args
1163
1167
  */
1164
1168
  public read(...args: any[]): any {
1169
+
1165
1170
  if (args.length === 2) {
1166
1171
  return this.read(args[0], 0, args[1]);
1167
1172
  }
@@ -1193,7 +1198,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
1193
1198
  warningLog(
1194
1199
  chalk.yellow(
1195
1200
  "please make sure to refactor your code and check that " +
1196
- "the second argument of your callback function is named"
1201
+ "the second argument of your callback function is named"
1197
1202
  ),
1198
1203
  chalk.cyan("dataValue" + (isArray ? "s" : ""))
1199
1204
  );
@@ -1204,7 +1209,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
1204
1209
 
1205
1210
  // coerce nodeIds
1206
1211
  for (const node of nodesToRead) {
1207
- node.nodeId = resolveNodeId(node.nodeId);
1212
+ node.nodeId = this.resolveNodeId(node.nodeId);
1208
1213
  }
1209
1214
 
1210
1215
  const request = new ReadRequest({
@@ -1226,7 +1231,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
1226
1231
 
1227
1232
  // perform ExtensionObject resolution
1228
1233
  promoteOpaqueStructureWithCallback(this, response.results!, () => {
1229
- response.results = response.results || /* istanbul ignore next */ [];
1234
+ response.results = response.results || /* istanbul ignore next */[];
1230
1235
  return callback(null, isArray ? response.results : response.results[0]);
1231
1236
  });
1232
1237
  });
@@ -1427,7 +1432,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
1427
1432
  if (!response) {
1428
1433
  return callback(new Error("Internal Error"));
1429
1434
  }
1430
- response.results = response.results || /* istanbul ignore next */ [];
1435
+ response.results = response.results || /* istanbul ignore next */[];
1431
1436
  callback(err, isArray ? response.results : response.results[0]);
1432
1437
  }
1433
1438
  );
@@ -1472,7 +1477,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
1472
1477
  if (!response || !(response instanceof TranslateBrowsePathsToNodeIdsResponse)) {
1473
1478
  return callback(new Error("Internal Error"));
1474
1479
  }
1475
- response.results = response.results || /* istanbul ignore next */ [];
1480
+ response.results = response.results || /* istanbul ignore next */[];
1476
1481
 
1477
1482
  callback(null, isArray ? response.results : response.results[0]);
1478
1483
  });
@@ -1615,9 +1620,9 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
1615
1620
  if (response.responseHeader.serviceResult.isNot(StatusCodes.Good)) {
1616
1621
  err = new Error(
1617
1622
  " ServiceResult is " +
1618
- response.responseHeader.serviceResult.toString() +
1619
- " request was " +
1620
- request.constructor.name
1623
+ response.responseHeader.serviceResult.toString() +
1624
+ " request was " +
1625
+ request.constructor.name
1621
1626
  );
1622
1627
 
1623
1628
  if (response && response.responseHeader.serviceDiagnostics) {
@@ -1857,7 +1862,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
1857
1862
  assert(Array.isArray(nodesToRegister));
1858
1863
 
1859
1864
  const request = new RegisterNodesRequest({
1860
- nodesToRegister: nodesToRegister.map(resolveNodeId)
1865
+ nodesToRegister: nodesToRegister.map((n) => this.resolveNodeId(n))
1861
1866
  });
1862
1867
 
1863
1868
  this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
@@ -1870,7 +1875,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
1870
1875
  return callback(new Error("Internal Error"));
1871
1876
  }
1872
1877
 
1873
- response.registeredNodeIds = response.registeredNodeIds || /* istanbul ignore next */ [];
1878
+ response.registeredNodeIds = response.registeredNodeIds || /* istanbul ignore next */[];
1874
1879
 
1875
1880
  callback(null, response.registeredNodeIds);
1876
1881
  });
@@ -1886,7 +1891,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
1886
1891
  assert(Array.isArray(nodesToUnregister));
1887
1892
 
1888
1893
  const request = new UnregisterNodesRequest({
1889
- nodesToUnregister: nodesToUnregister.map(resolveNodeId)
1894
+ nodesToUnregister: nodesToUnregister.map((n) => this.resolveNodeId(n))
1890
1895
  });
1891
1896
 
1892
1897
  this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
@@ -2020,36 +2025,16 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
2020
2025
  public readNamespaceArray(callback: (err: Error | null, namespaceArray?: string[]) => void): void;
2021
2026
  public readNamespaceArray(...args: any[]): any {
2022
2027
  const callback = args[0];
2023
-
2024
- this.read(
2025
- {
2026
- attributeId: AttributeIds.Value,
2027
- nodeId: resolveNodeId("Server_NamespaceArray")
2028
- },
2029
- (err: Error | null, dataValue?: DataValue) => {
2030
- /* istanbul ignore next */
2031
- if (err) {
2032
- return callback(err);
2033
- }
2034
- /* istanbul ignore next */
2035
- if (!dataValue) {
2036
- return callback(new Error("Internal Error"));
2037
- }
2038
-
2039
- /* istanbul ignore next */
2040
- if (dataValue.statusCode.isNotGood()) {
2041
- return callback(new Error("readNamespaceArray : " + dataValue.statusCode.toString()));
2042
- }
2043
- assert(dataValue.value.value instanceof Array);
2044
- this._namespaceArray = dataValue.value.value; // keep a cache
2045
- callback(null, this._namespaceArray);
2046
- }
2047
- );
2028
+ readNamespaceArray(this)
2029
+ .then((namespaceArray) => callback(null, namespaceArray))
2030
+ .catch((err) => {
2031
+ callback(err);
2032
+ });
2048
2033
  }
2049
2034
 
2050
2035
  public getNamespaceIndex(namespaceUri: string): number {
2051
- assert(this._namespaceArray, "please make sure that readNamespaceArray has been called");
2052
- return this._namespaceArray.indexOf(namespaceUri);
2036
+ assert(this.$$namespaceArray, "please make sure that readNamespaceArray has been called");
2037
+ return this.$$namespaceArray!.indexOf(namespaceUri);
2053
2038
  }
2054
2039
 
2055
2040
  // tslint:disable:no-empty
@@ -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";
@@ -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 {
@@ -87,7 +87,7 @@ function __askSubscriptionRepublish(
87
87
  subscription: ClientSubscriptionImpl,
88
88
  callback: (err?: Error) => void
89
89
  ) {
90
-
90
+
91
91
  _republish(engine, subscription, (err?: Error) => {
92
92
  // prettier-ignore
93
93
  { const _err = _shouldNotContinue2(subscription); if (_err) { return callback(_err); } }
@@ -113,7 +113,7 @@ function __askSubscriptionRepublish(
113
113
  debugLog(
114
114
  chalk.bgWhite.red("__askSubscriptionRepublish failed " + " subscriptionId is not valid anymore on server side.")
115
115
  );
116
- return recreateSubscriptionAndMonitoredItem(subscription, callback);
116
+ return recreateSubscriptionAndMonitoredItem(subscription).then(() => callback()).catch(err => callback(err));
117
117
  }
118
118
  if (err && err.message.match(/|MessageNotAvailable/)) {
119
119
  // start engine and start monitoring
@@ -1,10 +1,9 @@
1
- import async from "async";
1
+ import { promisify } from "util";
2
2
  import assert from "node-opcua-assert";
3
3
  import { TimestampsToReturn } from "node-opcua-data-value";
4
4
  import { make_debugLog, checkDebugFlag } from "node-opcua-debug";
5
5
  import { warningLog } from "node-opcua-pki";
6
6
  import { MonitoredItemCreateRequestOptions, CreateMonitoredItemsRequest, CreateMonitoredItemsResponse } from "node-opcua-types";
7
- import { ErrorCallback } from "node-opcua-status-code";
8
7
 
9
8
  import {
10
9
  IBasicSessionReadAsync,
@@ -20,128 +19,106 @@ import { _shouldNotContinue } from "./reconnection";
20
19
  const debugLog = make_debugLog("RECONNECTION");
21
20
  const doDebug = checkDebugFlag("RECONNECTION");
22
21
 
23
- function createMonitoredItemsAndRespectOperationalLimits(
22
+ async function createMonitoredItemsAndRespectOperationalLimits(
24
23
  session: IBasicSessionReadAsync & IBasicSessionWithSubscription,
25
- createMonitorItemsRequest: CreateMonitoredItemsRequest,
26
- callback: (err: Error | null, response?: CreateMonitoredItemsResponse) => void
27
- ) {
28
- readOperationLimits(session)
29
- .then((operationalLimits) => {
30
- createMonitoredItemsLimit(operationalLimits.maxMonitoredItemsPerCall || 0, session, createMonitorItemsRequest)
31
- .then((createMonitoredItemResponse) => callback(null, createMonitoredItemResponse))
32
- .catch(callback);
33
- })
34
- .catch(callback);
24
+ createMonitorItemsRequest: CreateMonitoredItemsRequest
25
+ ): Promise<CreateMonitoredItemsResponse> {
26
+ const operationalLimits = await readOperationLimits(session);
27
+ const createMonitoredItemResponse = await createMonitoredItemsLimit(
28
+ operationalLimits.maxMonitoredItemsPerCall || 0,
29
+ session,
30
+ createMonitorItemsRequest
31
+ );
32
+ return createMonitoredItemResponse;
35
33
  }
36
34
 
35
+ async function adjustMonitoredItemNodeIds(subscription: ClientSubscription, oldMonitoredItems: any) {
36
+ // to Do
37
+ }
37
38
  /**
38
39
  * utility function to recreate new subscription
39
40
  * @method recreateSubscriptionAndMonitoredItem
40
41
  */
41
- export function recreateSubscriptionAndMonitoredItem(_subscription: ClientSubscription, callback: ErrorCallback): void {
42
+ export async function recreateSubscriptionAndMonitoredItem(_subscription: ClientSubscription): Promise<void>
43
+ {
42
44
  debugLog("recreateSubscriptionAndMonitoredItem", _subscription.subscriptionId.toString());
43
45
 
44
46
  const subscription = _subscription as ClientSubscriptionImpl;
45
47
  if (subscription.subscriptionId === TERMINATED_SUBSCRIPTION_ID) {
46
48
  debugLog("Subscription is not in a valid state");
47
- return callback();
49
+ return;
48
50
  }
49
51
 
50
52
  const oldMonitoredItems = subscription.monitoredItems;
51
53
  const oldSubscriptionId = subscription.subscriptionId;
52
54
 
53
-
54
-
55
55
  subscription.publishEngine.unregisterSubscription(oldSubscriptionId);
56
56
 
57
- async.series(
58
- [
59
- (innerCallback: ErrorCallback) => {
60
- __create_subscription(subscription, innerCallback);
61
- },
62
- (innerCallback: ErrorCallback) => {
63
- // prettier-ignore
64
- { const _err = _shouldNotContinue(subscription.session); if (_err) { return innerCallback(_err); } }
57
+ await promisify(__create_subscription)(subscription);
58
+
59
+ const _err = _shouldNotContinue(subscription.session);
60
+ if (_err) { throw _err; }
65
61
 
66
- const test = subscription.publishEngine.getSubscription(subscription.subscriptionId);
62
+ const test = subscription.publishEngine.getSubscription(subscription.subscriptionId);
67
63
 
68
- debugLog("recreating ", Object.keys(oldMonitoredItems).length, " monitored Items");
64
+ debugLog("recreating ", Object.keys(oldMonitoredItems).length, " monitored Items");
69
65
  // re-create monitored items
70
- const itemsToCreate: MonitoredItemCreateRequestOptions[] = [];
71
-
72
- for (const monitoredItem of Object.values(oldMonitoredItems)) {
73
- assert(monitoredItem.monitoringParameters.clientHandle > 0);
74
- itemsToCreate.push({
75
- itemToMonitor: monitoredItem.itemToMonitor,
76
- monitoringMode: monitoredItem.monitoringMode,
77
- requestedParameters: monitoredItem.monitoringParameters
78
- });
79
- }
80
-
81
- const createMonitorItemsRequest = new CreateMonitoredItemsRequest({
82
- itemsToCreate,
83
- subscriptionId: subscription.subscriptionId,
84
- timestampsToReturn: TimestampsToReturn.Both // this.timestampsToReturn,
85
- });
86
-
87
- const session = subscription.session;
88
- // istanbul ignore next
89
- if (!session) {
90
- return innerCallback(new Error("no session"));
91
- }
92
-
93
- debugLog("Recreating ", itemsToCreate.length, " monitored items");
94
-
95
- createMonitoredItemsAndRespectOperationalLimits(
96
- session,
97
- createMonitorItemsRequest,
98
- (err: Error | null, response?: CreateMonitoredItemsResponse) => {
99
- if (err) {
100
- debugLog("Recreating monitored item has failed with ", err.message);
101
- return innerCallback(err);
102
- }
103
- /* istanbul ignore next */
104
- if (!response) {
105
- return innerCallback(new Error("Internal Error"));
106
- }
107
- const monitoredItemResults = response.results || [];
108
-
109
- let _errCount = 0;
110
- monitoredItemResults.forEach((monitoredItemResult, index) => {
111
- const itemToCreate = itemsToCreate[index];
112
- /* istanbul ignore next */
113
- if (!itemToCreate || !itemToCreate.requestedParameters) {
114
- _errCount++;
115
- return;
116
- }
117
- const clientHandle = itemToCreate.requestedParameters.clientHandle;
118
- /* istanbul ignore next */
119
- if (!clientHandle) {
120
- _errCount++;
121
- return;
122
- }
123
- const monitoredItem = subscription.monitoredItems[clientHandle] as ClientMonitoredItemImpl;
124
- if (monitoredItem) {
125
- monitoredItem._applyResult(monitoredItemResult);
126
- } else {
127
- _errCount++;
128
- warningLog("cannot find monitored item for clientHandle !:", clientHandle);
129
- warningLog("itemsToCreate = ", itemsToCreate[index].toString());
130
- }
131
- });
132
- if (_errCount > 0) {
133
- warningLog("Warning: some monitored items have not been recreated properly");
134
- }
135
- innerCallback();
136
- }
137
- );
138
- }
139
- ],
140
- (err) => {
141
- if (err) {
142
- warningLog("!!recreateSubscriptionAndMonitoredItem has failed", err.message);
143
- }
144
- callback(err!);
66
+ const itemsToCreate: MonitoredItemCreateRequestOptions[] = [];
67
+
68
+ await adjustMonitoredItemNodeIds(subscription, oldMonitoredItems);
69
+
70
+ for (const monitoredItem of Object.values(oldMonitoredItems)) {
71
+ assert(monitoredItem.monitoringParameters.clientHandle > 0);
72
+ itemsToCreate.push({
73
+ itemToMonitor: monitoredItem.itemToMonitor,
74
+ monitoringMode: monitoredItem.monitoringMode,
75
+ requestedParameters: monitoredItem.monitoringParameters
76
+ });
77
+ }
78
+
79
+ const createMonitorItemsRequest = new CreateMonitoredItemsRequest({
80
+ itemsToCreate,
81
+ subscriptionId: subscription.subscriptionId,
82
+ timestampsToReturn: TimestampsToReturn.Both // this.timestampsToReturn,
83
+ });
84
+
85
+ const session = subscription.session;
86
+ // istanbul ignore next
87
+ if (!session) {
88
+ throw new Error("no session");
89
+ }
90
+
91
+ debugLog("Recreating ", itemsToCreate.length, " monitored items");
92
+
93
+ const response = await createMonitoredItemsAndRespectOperationalLimits(
94
+ session,
95
+ createMonitorItemsRequest);
96
+ const monitoredItemResults = response.results || [];
97
+
98
+ let _errCount = 0;
99
+ monitoredItemResults.forEach((monitoredItemResult, index) => {
100
+ const itemToCreate = itemsToCreate[index];
101
+ /* istanbul ignore next */
102
+ if (!itemToCreate || !itemToCreate.requestedParameters) {
103
+ _errCount++;
104
+ return;
145
105
  }
146
- );
106
+ const clientHandle = itemToCreate.requestedParameters.clientHandle;
107
+ /* istanbul ignore next */
108
+ if (!clientHandle) {
109
+ _errCount++;
110
+ return;
111
+ }
112
+ const monitoredItem = subscription.monitoredItems[clientHandle] as ClientMonitoredItemImpl;
113
+ if (monitoredItem) {
114
+ monitoredItem._applyResult(monitoredItemResult);
115
+ } else {
116
+ _errCount++;
117
+ warningLog("cannot find monitored item for clientHandle !:", clientHandle);
118
+ warningLog("itemsToCreate = ", itemsToCreate[index].toString());
119
+ }
120
+ });
121
+ if (_errCount > 0) {
122
+ warningLog("Warning: some monitored items have not been recreated properly");
123
+ }
147
124
  }
@@ -216,22 +216,19 @@ function repair_client_session_by_recreating_a_new_session(
216
216
  doDebug && debugLog(chalk.red(" => RECREATING SUBSCRIPTION "), subscriptionId);
217
217
  assert(subscription.session === newSession, "must have the new session");
218
218
 
219
- recreateSubscriptionAndMonitoredItem(subscription, (err1?: Error) => {
220
- // prettier-ignore
221
- { const err = _shouldNotContinue(session); if (err) { return next(err); } }
222
-
223
- if (err1) {
224
- doDebug && debugLog("_recreateSubscription failed !" + err1.message);
225
- }
226
-
219
+ recreateSubscriptionAndMonitoredItem(subscription).then(() => {
227
220
  doDebug &&
228
221
  debugLog(
229
222
  chalk.cyan(" => RECREATING SUBSCRIPTION AND MONITORED ITEM DONE subscriptionId="),
230
223
  subscriptionId
231
224
  );
225
+ next();
232
226
 
227
+ }).catch((err) => {
228
+ doDebug && debugLog("_recreateSubscription failed !" + (err as Error).message);
233
229
  next();
234
230
  });
231
+
235
232
  },
236
233
  (err1?: Error | null) => {
237
234
  // prettier-ignore
@@ -495,7 +492,7 @@ export function repair_client_session(client: IClientBase, session: ClientSessio
495
492
 
496
493
  const repeatedAction = (callback: EmptyCallback) => {
497
494
  // prettier-ignore
498
- { const err = _shouldNotContinue(session); if (err) { return callback(err); }}
495
+ { const err = _shouldNotContinue(session); if (err) { return callback(err); } }
499
496
 
500
497
  _repair_client_session(client, session, (err) => {
501
498
  // prettier-ignore