node-opcua-client 2.163.1 → 2.164.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client_base.js +1 -1
- package/dist/client_base.js.map +1 -1
- package/dist/client_monitored_item.js +1 -1
- package/dist/client_monitored_item.js.map +1 -1
- package/dist/client_monitored_item_group.js +1 -1
- package/dist/client_monitored_item_group.js.map +1 -1
- package/dist/client_monitored_item_toolbox.js +4 -4
- package/dist/client_monitored_item_toolbox.js.map +1 -1
- package/dist/client_session_keepalive_manager.js +3 -3
- package/dist/client_session_keepalive_manager.js.map +1 -1
- package/dist/client_subscription.js +1 -1
- package/dist/client_subscription.js.map +1 -1
- package/dist/private/client_base_impl.js +33 -28
- package/dist/private/client_base_impl.js.map +1 -1
- package/dist/private/client_monitored_item_impl.js +1 -2
- package/dist/private/client_monitored_item_impl.js.map +1 -1
- package/dist/private/client_publish_engine.js +14 -3
- package/dist/private/client_publish_engine.js.map +1 -1
- package/dist/private/client_session_impl.js +58 -58
- package/dist/private/client_session_impl.js.map +1 -1
- package/dist/private/client_subscription_impl.js +11 -11
- package/dist/private/client_subscription_impl.js.map +1 -1
- package/dist/private/opcua_client_impl.js +15 -15
- package/dist/private/opcua_client_impl.js.map +1 -1
- package/dist/private/reconnection/client_publish_engine_reconnection.js +2 -2
- package/dist/private/reconnection/client_publish_engine_reconnection.js.map +1 -1
- package/dist/private/reconnection/client_subscription_reconnection.js +9 -9
- package/dist/private/reconnection/client_subscription_reconnection.js.map +1 -1
- package/dist/private/reconnection/reconnection.js +8 -8
- package/dist/private/reconnection/reconnection.js.map +1 -1
- package/dist/tools/read_history_server_capabilities.js +3 -3
- package/dist/tools/read_history_server_capabilities.js.map +1 -1
- package/dist/verify.js +14 -2
- package/dist/verify.js.map +1 -1
- package/package.json +46 -46
- package/source/client_base.ts +1 -1
- package/source/client_monitored_item.ts +1 -1
- package/source/client_monitored_item_group.ts +1 -1
- package/source/client_monitored_item_toolbox.ts +4 -4
- package/source/client_session_keepalive_manager.ts +3 -3
- package/source/client_subscription.ts +1 -1
- package/source/private/client_base_impl.ts +35 -29
- package/source/private/client_monitored_item_impl.ts +1 -2
- package/source/private/client_publish_engine.ts +18 -3
- package/source/private/client_session_impl.ts +58 -58
- package/source/private/client_subscription_impl.ts +11 -11
- package/source/private/opcua_client_impl.ts +15 -15
- package/source/private/reconnection/client_publish_engine_reconnection.ts +2 -2
- package/source/private/reconnection/client_subscription_reconnection.ts +6 -6
- package/source/private/reconnection/reconnection.ts +8 -8
- package/source/tools/read_history_server_capabilities.ts +3 -3
- package/source/verify.ts +37 -27
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
} from "node-opcua-service-endpoints";
|
|
43
43
|
import { ChannelSecurityToken, coerceMessageSecurityMode, MessageSecurityMode } from "node-opcua-service-secure-channel";
|
|
44
44
|
import { ErrorCallback, StatusCode, StatusCodes } from "node-opcua-status-code";
|
|
45
|
-
import { matchUri } from "node-opcua-utils";
|
|
45
|
+
import { matchUri, checkFileExistsAndIsNotEmpty } from "node-opcua-utils";
|
|
46
46
|
|
|
47
47
|
import { getDefaultCertificateManager, makeSubject, OPCUACertificateManager } from "node-opcua-certificate-manager";
|
|
48
48
|
import { VerificationStatus } from "node-opcua-pki";
|
|
@@ -124,7 +124,7 @@ function __findEndpoint(this: ClientBaseImpl, endpointUrl: string, params: FindE
|
|
|
124
124
|
// rebind backoff handler
|
|
125
125
|
masterClient.listeners("backoff").forEach((handler: any) => client.on("backoff", handler));
|
|
126
126
|
|
|
127
|
-
//
|
|
127
|
+
// c8 ignore next
|
|
128
128
|
if (doDebug) {
|
|
129
129
|
client.on("backoff", (retryCount: number, delay: number) => {
|
|
130
130
|
debugLog(
|
|
@@ -160,7 +160,7 @@ function __findEndpoint(this: ClientBaseImpl, endpointUrl: string, params: FindE
|
|
|
160
160
|
err.message = "error in getEndpoints \n" + err.message;
|
|
161
161
|
return innerCallback(err);
|
|
162
162
|
}
|
|
163
|
-
//
|
|
163
|
+
// c8 ignore next
|
|
164
164
|
if (!endpoints) {
|
|
165
165
|
return innerCallback(new Error("Internal Error"));
|
|
166
166
|
}
|
|
@@ -206,7 +206,7 @@ function __findEndpoint(this: ClientBaseImpl, endpointUrl: string, params: FindE
|
|
|
206
206
|
);
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
-
//
|
|
209
|
+
// c8 ignore next
|
|
210
210
|
if (doDebug) {
|
|
211
211
|
debugLog(chalk.bgWhite.red("xxxxxxxxxxxxxxxxxxxxx => selected EndPoint = "), selectedEndpoint.toString());
|
|
212
212
|
}
|
|
@@ -228,7 +228,7 @@ async function _verify_serverCertificate(
|
|
|
228
228
|
serverCertificate: Certificate) {
|
|
229
229
|
const status = await certificateManager.checkCertificate(serverCertificate);
|
|
230
230
|
if (status !== StatusCodes.Good) {
|
|
231
|
-
//
|
|
231
|
+
// c8 ignore next
|
|
232
232
|
if (doDebug) {
|
|
233
233
|
// do it again for debug purposes
|
|
234
234
|
const status1 = await certificateManager.verifyCertificate(serverCertificate);
|
|
@@ -413,7 +413,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
413
413
|
this._internalState = internalState;
|
|
414
414
|
}
|
|
415
415
|
public emit(eventName: string | symbol, ...others: any[]): boolean {
|
|
416
|
-
//
|
|
416
|
+
// c8 ignore next
|
|
417
417
|
if (doDebug) {
|
|
418
418
|
debugLog(chalk.cyan(` Client ${this._instanceNumber} ${this.clientName} emitting `), chalk.magentaBright(eventName));
|
|
419
419
|
}
|
|
@@ -442,6 +442,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
442
442
|
this._applicationUri = options.applicationUri || this._getBuiltApplicationUri();
|
|
443
443
|
|
|
444
444
|
this.clientCertificateManager = options.clientCertificateManager;
|
|
445
|
+
this.clientCertificateManager.referenceCounter++;
|
|
445
446
|
|
|
446
447
|
this._secureChannel = null;
|
|
447
448
|
|
|
@@ -497,7 +498,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
497
498
|
// _cancel_reconnection is invoked during disconnection
|
|
498
499
|
// when we detect that a reconnection is in progress...
|
|
499
500
|
|
|
500
|
-
//
|
|
501
|
+
// c8 ignore next
|
|
501
502
|
if (!this.isReconnecting) {
|
|
502
503
|
warningLog("internal error: _cancel_reconnection should only be used when reconnecting is in progress");
|
|
503
504
|
}
|
|
@@ -506,7 +507,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
506
507
|
|
|
507
508
|
this._reconnectionIsCanceled = true;
|
|
508
509
|
|
|
509
|
-
//
|
|
510
|
+
// c8 ignore next
|
|
510
511
|
if (!this._secureChannel) {
|
|
511
512
|
debugLog("_cancel_reconnection: Nothing to do for !", this.clientName, " because secure channel doesn't exist");
|
|
512
513
|
return callback(); // nothing to do
|
|
@@ -587,7 +588,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
587
588
|
|
|
588
589
|
this._internal_create_secure_channel(infiniteConnectionRetry, (err?: Error | null) => {
|
|
589
590
|
if (err) {
|
|
590
|
-
//
|
|
591
|
+
// c8 ignore next
|
|
591
592
|
if (this._secureChannel) {
|
|
592
593
|
const err = new Error("_internal_create_secure_channel failed, expecting this._secureChannel not to exist");
|
|
593
594
|
return _when_internal_error(err, callback);
|
|
@@ -773,21 +774,22 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
773
774
|
validity: 365 * 10 // 10 years
|
|
774
775
|
});
|
|
775
776
|
}
|
|
776
|
-
//
|
|
777
|
+
// c8 ignore next
|
|
777
778
|
if (!fs.existsSync(certificateFile)) {
|
|
778
779
|
throw new Error(" cannot locate certificate file " + certificateFile);
|
|
779
780
|
}
|
|
780
781
|
}
|
|
781
782
|
|
|
782
783
|
public async createDefaultCertificate(): Promise<void> {
|
|
783
|
-
//
|
|
784
|
+
// c8 ignore next
|
|
784
785
|
if ((this as any)._inCreateDefaultCertificate) {
|
|
785
786
|
errorLog("Internal error : re-entrancy in createDefaultCertificate!");
|
|
786
787
|
}
|
|
787
788
|
(this as any)._inCreateDefaultCertificate = true;
|
|
788
|
-
|
|
789
|
+
|
|
790
|
+
if (!checkFileExistsAndIsNotEmpty(this.certificateFile)) {
|
|
789
791
|
await withLock({ fileToLock: this.certificateFile + ".mutex" }, async () => {
|
|
790
|
-
if (
|
|
792
|
+
if (checkFileExistsAndIsNotEmpty(this.certificateFile)) {
|
|
791
793
|
// the file may have been created in between
|
|
792
794
|
return;
|
|
793
795
|
}
|
|
@@ -829,15 +831,17 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
829
831
|
}
|
|
830
832
|
await this.clientCertificateManager.initialize();
|
|
831
833
|
await this.createDefaultCertificate();
|
|
832
|
-
//
|
|
834
|
+
// c8 ignore next
|
|
833
835
|
if (!fs.existsSync(this.privateKeyFile)) {
|
|
834
836
|
throw new Error(" cannot locate private key file " + this.privateKeyFile);
|
|
835
837
|
}
|
|
836
838
|
if (this.isUnusable()) return;
|
|
837
839
|
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
840
|
+
// Note: do NOT wrap this in withLock2 — performCertificateSanityCheck
|
|
841
|
+
// calls trustCertificate and verifyCertificate which each acquire
|
|
842
|
+
// withLock2 internally, so an outer withLock2 would cause a deadlock
|
|
843
|
+
// on the same file-based mutex.
|
|
844
|
+
await performCertificateSanityCheck(this, "client", this.clientCertificateManager, this._getBuiltApplicationUri());
|
|
841
845
|
}
|
|
842
846
|
|
|
843
847
|
protected _internalState: InternalClientState = "uninitialized";
|
|
@@ -877,7 +881,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
877
881
|
}
|
|
878
882
|
assert(typeof endpointUrl === "string" && endpointUrl.length > 0);
|
|
879
883
|
|
|
880
|
-
//
|
|
884
|
+
// c8 ignore next
|
|
881
885
|
if (this._internalState !== "disconnected") {
|
|
882
886
|
callback(new Error(`client#connect failed, as invalid internal state = ${this._internalState}`));
|
|
883
887
|
return;
|
|
@@ -1075,7 +1079,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1075
1079
|
return callback(err);
|
|
1076
1080
|
}
|
|
1077
1081
|
this._serverEndpoints = [];
|
|
1078
|
-
//
|
|
1082
|
+
// c8 ignore next
|
|
1079
1083
|
if (!response || !(response instanceof GetEndpointsResponse)) {
|
|
1080
1084
|
return callback(new Error("Internal Error"));
|
|
1081
1085
|
}
|
|
@@ -1117,7 +1121,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1117
1121
|
if (err) {
|
|
1118
1122
|
return callback(err);
|
|
1119
1123
|
}
|
|
1120
|
-
/*
|
|
1124
|
+
/* c8 ignore next */
|
|
1121
1125
|
if (!response || !(response instanceof FindServersResponse)) {
|
|
1122
1126
|
return callback(new Error("Internal Error"));
|
|
1123
1127
|
}
|
|
@@ -1142,7 +1146,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1142
1146
|
if (err) {
|
|
1143
1147
|
return callback(err);
|
|
1144
1148
|
}
|
|
1145
|
-
/*
|
|
1149
|
+
/* c8 ignore next */
|
|
1146
1150
|
if (!response || !(response instanceof FindServersOnNetworkResponse)) {
|
|
1147
1151
|
return new Error("Internal Error");
|
|
1148
1152
|
}
|
|
@@ -1170,7 +1174,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1170
1174
|
assert(typeof callback === "function");
|
|
1171
1175
|
assert(typeof deleteSubscriptions === "boolean");
|
|
1172
1176
|
|
|
1173
|
-
//
|
|
1177
|
+
// c8 ignore next
|
|
1174
1178
|
if (!this._secureChannel) {
|
|
1175
1179
|
return callback(null); // new Error("no channel"));
|
|
1176
1180
|
}
|
|
@@ -1276,7 +1280,9 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1276
1280
|
if (this.clientCertificateManager) {
|
|
1277
1281
|
const tmp = this.clientCertificateManager;
|
|
1278
1282
|
// (this as any).clientCertificateManager = null;
|
|
1279
|
-
tmp.dispose()
|
|
1283
|
+
tmp.dispose().catch((err: Error) => {
|
|
1284
|
+
debugLog("Error disposing clientCertificateManager", err.message);
|
|
1285
|
+
});
|
|
1280
1286
|
}
|
|
1281
1287
|
|
|
1282
1288
|
if (this._sessions.length) {
|
|
@@ -1411,7 +1417,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1411
1417
|
return callback(err);
|
|
1412
1418
|
}
|
|
1413
1419
|
|
|
1414
|
-
//
|
|
1420
|
+
// c8 ignore next
|
|
1415
1421
|
if (!result) {
|
|
1416
1422
|
const err1 = new Error("internal error");
|
|
1417
1423
|
return callback(err1);
|
|
@@ -1471,7 +1477,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1471
1477
|
this._byteRead += this._secureChannel.bytesRead;
|
|
1472
1478
|
this._transactionsPerformed += this._secureChannel.transactionsPerformed;
|
|
1473
1479
|
this._timedOutRequestCount += this._secureChannel.timedOutRequestCount;
|
|
1474
|
-
//
|
|
1480
|
+
// c8 ignore next
|
|
1475
1481
|
if (doDebug) {
|
|
1476
1482
|
const h = `Client ${this._instanceNumber} ${this.clientName}`;
|
|
1477
1483
|
debugLog(chalk.cyan(`${h} byteWritten = `), this._byteWritten);
|
|
@@ -1483,7 +1489,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1483
1489
|
}
|
|
1484
1490
|
private _destroy_secure_channel() {
|
|
1485
1491
|
if (this._secureChannel) {
|
|
1486
|
-
//
|
|
1492
|
+
// c8 ignore next
|
|
1487
1493
|
if (doDebug) {
|
|
1488
1494
|
debugLog(
|
|
1489
1495
|
" DESTROYING SECURE CHANNEL (isTransactionInProgress ?",
|
|
@@ -1525,7 +1531,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1525
1531
|
});
|
|
1526
1532
|
},
|
|
1527
1533
|
(err) => {
|
|
1528
|
-
//
|
|
1534
|
+
// c8 ignore next
|
|
1529
1535
|
if (this._sessions.length > 0) {
|
|
1530
1536
|
debugLog(
|
|
1531
1537
|
this._sessions
|
|
@@ -1694,7 +1700,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1694
1700
|
if (this.isUnusable()) return;
|
|
1695
1701
|
this._finalReconnectionStep((err2?: Error | null) => {
|
|
1696
1702
|
if (err2) {
|
|
1697
|
-
//
|
|
1703
|
+
// c8 ignore next
|
|
1698
1704
|
if (doDebug) {
|
|
1699
1705
|
debugLog("connection_reestablished has failed");
|
|
1700
1706
|
debugLog("err= ", err2.message);
|
|
@@ -1768,7 +1774,7 @@ class TmpClient extends ClientBaseImpl {
|
|
|
1768
1774
|
connect(endpoint: string, callback?: ErrorCallback): any {
|
|
1769
1775
|
debugLog("connecting to TmpClient");
|
|
1770
1776
|
|
|
1771
|
-
//
|
|
1777
|
+
// c8 ignore next
|
|
1772
1778
|
if (this._internalState !== "disconnected") {
|
|
1773
1779
|
callback!(new Error("TmpClient#connect: invalid internal state = " + this._internalState));
|
|
1774
1780
|
return;
|
|
@@ -265,7 +265,7 @@ export class ClientMonitoredItemImpl extends EventEmitter implements ClientMonit
|
|
|
265
265
|
|
|
266
266
|
const filter = this.monitoringParameters.filter;
|
|
267
267
|
|
|
268
|
-
//
|
|
268
|
+
// c8 ignore next
|
|
269
269
|
if (!filter) {
|
|
270
270
|
return { error: "Internal Error" };
|
|
271
271
|
}
|
|
@@ -310,7 +310,6 @@ export class ClientMonitoredItemImpl extends EventEmitter implements ClientMonit
|
|
|
310
310
|
public _applyResult(monitoredItemResult: MonitoredItemCreateResult): void {
|
|
311
311
|
this.statusCode = monitoredItemResult.statusCode;
|
|
312
312
|
|
|
313
|
-
/* istanbul ignore else */
|
|
314
313
|
if (monitoredItemResult.statusCode.isGood()) {
|
|
315
314
|
this.result = monitoredItemResult;
|
|
316
315
|
this.monitoredItemId = monitoredItemResult.monitoredItemId;
|
|
@@ -281,7 +281,7 @@ export class ClientSidePublishEngine {
|
|
|
281
281
|
// There is no need to send more publish request for the time being until reconnection is completed
|
|
282
282
|
active = false;
|
|
283
283
|
}
|
|
284
|
-
//
|
|
284
|
+
// c8 ignore next
|
|
285
285
|
if (err.message.match(/BadNoSubscription/) && this.activeSubscriptionCount >= 1) {
|
|
286
286
|
// there is something wrong happening here.
|
|
287
287
|
// the server tells us that there is no subscription for this session
|
|
@@ -325,8 +325,23 @@ export class ClientSidePublishEngine {
|
|
|
325
325
|
warningLog(" => nbMaxPublishRequestsAcceptedByServer =", this.nbMaxPublishRequestsAcceptedByServer);
|
|
326
326
|
}
|
|
327
327
|
}
|
|
328
|
+
if (err.message.match(/BadSecureChannelIdInvalid/)) {
|
|
329
|
+
// This can happen transiently during session transfer to a new
|
|
330
|
+
// SecureChannel (e.g. after server certificate change). The
|
|
331
|
+
// PublishRequest arrived on the new channel before ActivateSession
|
|
332
|
+
// completed the session transfer. We should pause and let the
|
|
333
|
+
// reconnection flow replenish publish requests once the session
|
|
334
|
+
// transfer completes.
|
|
335
|
+
debugLog(
|
|
336
|
+
chalk.bgWhite.yellow(
|
|
337
|
+
" WARNING: BadSecureChannelIdInvalid on PublishRequest"
|
|
338
|
+
+ " - session transfer may be in progress"
|
|
339
|
+
)
|
|
340
|
+
);
|
|
341
|
+
active = false;
|
|
342
|
+
}
|
|
328
343
|
} else {
|
|
329
|
-
//
|
|
344
|
+
// c8 ignore next
|
|
330
345
|
if (doDebug) {
|
|
331
346
|
debugLog(chalk.cyan("ClientSidePublishEngine.prototype.internalSendPublishRequest callback "));
|
|
332
347
|
}
|
|
@@ -380,7 +395,7 @@ export class ClientSidePublishEngine {
|
|
|
380
395
|
// delegate notificationData to the subscription callback
|
|
381
396
|
subscription.onNotificationMessage(notificationMessage);
|
|
382
397
|
} catch (err) {
|
|
383
|
-
//
|
|
398
|
+
// c8 ignore next
|
|
384
399
|
if (doDebug) {
|
|
385
400
|
debugLog(err);
|
|
386
401
|
debugLog("Exception in onNotificationMessage");
|