node-opcua-client 2.123.0 → 2.124.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/dist/alarms_and_conditions/client_alarm_tools.js.map +1 -1
- package/dist/alarms_and_conditions/client_tools.js.map +1 -1
- package/dist/client_monitored_item_toolbox.js.map +1 -1
- package/dist/client_session_keepalive_manager.js.map +1 -1
- package/dist/client_utils.js.map +1 -1
- package/dist/private/client_base_impl.d.ts +11 -4
- package/dist/private/client_base_impl.js +130 -70
- package/dist/private/client_base_impl.js.map +1 -1
- package/dist/private/client_monitored_item_group_impl.js.map +1 -1
- package/dist/private/client_monitored_item_impl.js.map +1 -1
- package/dist/private/client_publish_engine.d.ts +9 -4
- package/dist/private/client_publish_engine.js +5 -99
- package/dist/private/client_publish_engine.js.map +1 -1
- package/dist/private/client_session_impl.d.ts +20 -4
- package/dist/private/client_session_impl.js +5 -24
- package/dist/private/client_session_impl.js.map +1 -1
- package/dist/private/client_subscription_impl.d.ts +5 -8
- package/dist/private/client_subscription_impl.js +83 -174
- package/dist/private/client_subscription_impl.js.map +1 -1
- package/dist/private/i_private_client.d.ts +0 -1
- package/dist/private/opcua_client_impl.js +1 -1
- package/dist/private/opcua_client_impl.js.map +1 -1
- package/dist/private/performance.js.map +1 -1
- package/dist/private/reconnection/client_publish_engine_reconnection.d.ts +2 -0
- package/dist/private/reconnection/client_publish_engine_reconnection.js +118 -0
- package/dist/private/reconnection/client_publish_engine_reconnection.js.map +1 -0
- package/dist/private/reconnection/client_reconnection.d.ts +2 -0
- package/dist/private/reconnection/client_reconnection.js +20 -0
- package/dist/private/reconnection/client_reconnection.js.map +1 -0
- package/dist/private/reconnection/client_subscription_reconnection.d.ts +7 -0
- package/dist/private/reconnection/client_subscription_reconnection.js +124 -0
- package/dist/private/reconnection/client_subscription_reconnection.js.map +1 -0
- package/dist/private/reconnection/reconnection.d.ts +12 -0
- package/dist/private/reconnection/reconnection.js +564 -0
- package/dist/private/reconnection/reconnection.js.map +1 -0
- package/dist/tools/findservers.js.map +1 -1
- package/dist/tools/read_history_server_capabilities.js.map +1 -1
- package/dist/verify.js.map +1 -1
- package/package.json +8 -8
- package/source/private/client_base_impl.ts +136 -81
- package/source/private/client_publish_engine.ts +13 -129
- package/source/private/client_session_impl.ts +23 -30
- package/source/private/client_subscription_impl.ts +85 -207
- package/source/private/i_private_client.ts +0 -2
- package/source/private/opcua_client_impl.ts +1 -1
- package/source/private/reconnection/client_publish_engine_reconnection.ts +146 -0
- package/source/private/reconnection/client_reconnection.ts +17 -0
- package/source/private/reconnection/client_subscription_reconnection.ts +147 -0
- package/source/{reconnection.ts → private/reconnection/reconnection.ts} +120 -72
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-opcua-client",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.124.0",
|
|
4
4
|
"description": "pure nodejs OPCUA SDK - module client",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"clean": "npx rimraf node_modules dist *.tsbuildinfo certificates",
|
|
@@ -17,12 +17,12 @@
|
|
|
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.
|
|
20
|
+
"node-opcua-alarm-condition": "2.124.0",
|
|
21
21
|
"node-opcua-assert": "2.120.0",
|
|
22
22
|
"node-opcua-basic-types": "2.121.0",
|
|
23
23
|
"node-opcua-buffer-utils": "2.120.0",
|
|
24
24
|
"node-opcua-certificate-manager": "2.121.0",
|
|
25
|
-
"node-opcua-client-dynamic-extension-object": "2.
|
|
25
|
+
"node-opcua-client-dynamic-extension-object": "2.124.0",
|
|
26
26
|
"node-opcua-common": "2.123.0",
|
|
27
27
|
"node-opcua-constants": "2.121.0",
|
|
28
28
|
"node-opcua-crypto": "4.8.0",
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"node-opcua-nodeid": "2.121.0",
|
|
36
36
|
"node-opcua-object-registry": "2.121.0",
|
|
37
37
|
"node-opcua-pki": "4.10.0",
|
|
38
|
-
"node-opcua-pseudo-session": "2.
|
|
38
|
+
"node-opcua-pseudo-session": "2.124.0",
|
|
39
39
|
"node-opcua-schemas": "2.123.0",
|
|
40
|
-
"node-opcua-secure-channel": "2.
|
|
40
|
+
"node-opcua-secure-channel": "2.124.0",
|
|
41
41
|
"node-opcua-service-browse": "2.123.0",
|
|
42
42
|
"node-opcua-service-call": "2.123.0",
|
|
43
43
|
"node-opcua-service-discovery": "2.123.0",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"node-opcua-service-register-node": "2.123.0",
|
|
50
50
|
"node-opcua-service-secure-channel": "2.123.0",
|
|
51
51
|
"node-opcua-service-session": "2.123.0",
|
|
52
|
-
"node-opcua-service-subscription": "2.
|
|
52
|
+
"node-opcua-service-subscription": "2.124.0",
|
|
53
53
|
"node-opcua-service-translate-browse-path": "2.123.0",
|
|
54
54
|
"node-opcua-service-write": "2.123.0",
|
|
55
55
|
"node-opcua-status-code": "2.121.0",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"@types/underscore": "^1.11.15",
|
|
63
63
|
"dequeue": "^1.0.5",
|
|
64
64
|
"mocha": "^10.3.0",
|
|
65
|
-
"node-opcua-address-space": "2.
|
|
65
|
+
"node-opcua-address-space": "2.124.0",
|
|
66
66
|
"node-opcua-binary-stream": "2.120.0",
|
|
67
67
|
"node-opcua-factory": "2.121.0",
|
|
68
68
|
"node-opcua-leak-detector": "2.121.0",
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
"internet of things"
|
|
92
92
|
],
|
|
93
93
|
"homepage": "http://node-opcua.github.io/",
|
|
94
|
-
"gitHead": "
|
|
94
|
+
"gitHead": "75b5e34e797094a83833ea2d7c72ca3e5983d648",
|
|
95
95
|
"files": [
|
|
96
96
|
"dist",
|
|
97
97
|
"source"
|
|
@@ -66,6 +66,7 @@ import { UserIdentityInfo } from "../user_identity_info";
|
|
|
66
66
|
import { performCertificateSanityCheck } from "../verify";
|
|
67
67
|
import { ClientSessionImpl } from "./client_session_impl";
|
|
68
68
|
import { IClientBase } from "./i_private_client";
|
|
69
|
+
import { waitUntilReconnectionIsCanceled } from "./reconnection/client_reconnection";
|
|
69
70
|
|
|
70
71
|
const debugLog = make_debugLog(__filename);
|
|
71
72
|
const doDebug = checkDebugFlag(__filename);
|
|
@@ -80,13 +81,13 @@ const defaultConnectionStrategy: ConnectionStrategyOptions = {
|
|
|
80
81
|
randomisationFactor: 0.1
|
|
81
82
|
};
|
|
82
83
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const masterClient = this as
|
|
88
|
-
debugLog("findEndpoint : endpointUrl = ", endpointUrl);
|
|
89
|
-
debugLog(" params ", params);
|
|
84
|
+
function __findEndpoint(this: ClientBaseImpl, endpointUrl: string, params: FindEndpointOptions, _callback: FindEndpointCallback) {
|
|
85
|
+
if (this.isUnusable()) {
|
|
86
|
+
return _callback(new Error("Client is not usable"));
|
|
87
|
+
}
|
|
88
|
+
const masterClient = this as ClientBaseImpl;
|
|
89
|
+
doDebug && debugLog("findEndpoint : endpointUrl = ", endpointUrl);
|
|
90
|
+
doDebug && debugLog(" params ", params);
|
|
90
91
|
assert(!masterClient._tmpClient);
|
|
91
92
|
|
|
92
93
|
const callback = (err: Error | null, result?: FindEndpointResult) => {
|
|
@@ -104,11 +105,13 @@ function __findEndpoint(this: OPCUAClientBase, endpointUrl: string, params: Find
|
|
|
104
105
|
clientCertificateManager: params.clientCertificateManager,
|
|
105
106
|
|
|
106
107
|
clientName: "EndpointFetcher",
|
|
107
|
-
connectionStrategy: {
|
|
108
|
-
maxRetry: 0 /* no- retry */,
|
|
109
|
-
maxDelay: 2000
|
|
110
|
-
},
|
|
111
108
|
|
|
109
|
+
// use same connectionStrategy as parent
|
|
110
|
+
connectionStrategy: params.connectionStrategy,
|
|
111
|
+
// connectionStrategy: {
|
|
112
|
+
// maxRetry: 0 /* no- retry */,
|
|
113
|
+
// maxDelay: 2000
|
|
114
|
+
// },
|
|
112
115
|
privateKeyFile: params.privateKeyFile
|
|
113
116
|
};
|
|
114
117
|
|
|
@@ -323,7 +326,11 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
323
326
|
* true if the client is trying to reconnect to the server after a connection break.
|
|
324
327
|
*/
|
|
325
328
|
get isReconnecting(): boolean {
|
|
326
|
-
return
|
|
329
|
+
return (
|
|
330
|
+
!!(this._secureChannel && this._secureChannel.isConnecting) ||
|
|
331
|
+
this._internalState === "reconnecting_newchannel_connected" ||
|
|
332
|
+
this._internalState === "reconnecting"
|
|
333
|
+
);
|
|
327
334
|
}
|
|
328
335
|
|
|
329
336
|
/**
|
|
@@ -370,7 +377,6 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
370
377
|
public _sessions: ClientSessionImpl[];
|
|
371
378
|
protected _serverEndpoints: EndpointDescription[];
|
|
372
379
|
public _secureChannel: ClientSecureChannelLayer | null;
|
|
373
|
-
protected disconnecting: boolean;
|
|
374
380
|
|
|
375
381
|
// statistics...
|
|
376
382
|
private _byteRead: number;
|
|
@@ -381,7 +387,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
381
387
|
private _transactionsPerformed: number;
|
|
382
388
|
private _reconnectionIsCanceled: boolean;
|
|
383
389
|
private _clockAdjuster?: ClockAdjustment;
|
|
384
|
-
|
|
390
|
+
protected _tmpClient?: OPCUAClientBase;
|
|
385
391
|
private _instanceNumber: number;
|
|
386
392
|
private _transportSettings: TransportSettings;
|
|
387
393
|
private _transportTimeout?: number;
|
|
@@ -389,7 +395,12 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
389
395
|
public clientCertificateManager: OPCUACertificateManager;
|
|
390
396
|
|
|
391
397
|
public isUnusable() {
|
|
392
|
-
return
|
|
398
|
+
return (
|
|
399
|
+
this._internalState === "disconnected" ||
|
|
400
|
+
this._internalState === "disconnecting" ||
|
|
401
|
+
this._internalState === "panic" ||
|
|
402
|
+
this._internalState === "uninitialized"
|
|
403
|
+
);
|
|
393
404
|
}
|
|
394
405
|
|
|
395
406
|
protected _setInternalState(internalState: InternalClientState): void {
|
|
@@ -402,6 +413,12 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
402
413
|
chalk.yellow(internalState)
|
|
403
414
|
);
|
|
404
415
|
}
|
|
416
|
+
if (this._internalState === "disconnecting" || this._internalState === "disconnected") {
|
|
417
|
+
if (internalState === "reconnecting") {
|
|
418
|
+
errorLog("Internal error, cannot switch to reconnecting when already disconnecting");
|
|
419
|
+
} // when disconnecting, we cannot accept any other state
|
|
420
|
+
}
|
|
421
|
+
|
|
405
422
|
this._internalState = internalState;
|
|
406
423
|
}
|
|
407
424
|
public emit(eventName: string | symbol, ...others: any[]): boolean {
|
|
@@ -422,8 +439,10 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
422
439
|
|
|
423
440
|
super(options as IOPCUASecureObjectOptions);
|
|
424
441
|
|
|
442
|
+
this._setInternalState("uninitialized");
|
|
443
|
+
|
|
425
444
|
this._instanceNumber = g_ClientCounter++;
|
|
426
|
-
|
|
445
|
+
|
|
427
446
|
this.applicationName = options.applicationName || "NodeOPCUA-Client";
|
|
428
447
|
assert(!this.applicationName.match(/^locale=/), "applicationName badly converted from LocalizedText");
|
|
429
448
|
assert(!this.applicationName.match(/urn:/), "applicationName should not be a URI");
|
|
@@ -431,8 +450,6 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
431
450
|
// we need to delay _applicationUri initialization
|
|
432
451
|
this._applicationUri = options.applicationUri || this._getBuiltApplicationUri();
|
|
433
452
|
|
|
434
|
-
this.disconnecting = false;
|
|
435
|
-
|
|
436
453
|
this.clientCertificateManager = options.clientCertificateManager;
|
|
437
454
|
|
|
438
455
|
this._secureChannel = null;
|
|
@@ -491,13 +508,13 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
491
508
|
warningLog("internal error: _cancel_reconnection should only be used when reconnecting is in progress");
|
|
492
509
|
}
|
|
493
510
|
|
|
494
|
-
debugLog("canceling reconnection");
|
|
511
|
+
debugLog("canceling reconnection : ", this.clientName);
|
|
495
512
|
|
|
496
513
|
this._reconnectionIsCanceled = true;
|
|
497
514
|
|
|
498
515
|
// istanbul ignore next
|
|
499
516
|
if (!this._secureChannel) {
|
|
500
|
-
debugLog("_cancel_reconnection: Nothing to do !");
|
|
517
|
+
debugLog("_cancel_reconnection: Nothing to do for !", this.clientName, " because secure channel doesn't exist");
|
|
501
518
|
return callback(); // nothing to do
|
|
502
519
|
}
|
|
503
520
|
|
|
@@ -566,6 +583,12 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
566
583
|
if (this._reconnectionIsCanceled) {
|
|
567
584
|
return _when_reconnectionIsCanceled(callback);
|
|
568
585
|
}
|
|
586
|
+
if (this._secureChannel) {
|
|
587
|
+
doDebug && debugLog("attempt to recreate a new secure channel, while channel already exists");
|
|
588
|
+
// are we reentrant ?
|
|
589
|
+
const err = new Error("_internal_create_secure_channel failed, this._secureChannel is supposed to be null");
|
|
590
|
+
return _when_internal_error(err, callback);
|
|
591
|
+
}
|
|
569
592
|
assert(!this._secureChannel, "_attempt_to_recreate_secure_channel, expecting this._secureChannel not to exist");
|
|
570
593
|
|
|
571
594
|
this._internal_create_secure_channel(infiniteConnectionRetry, (err?: Error | null) => {
|
|
@@ -649,7 +672,11 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
649
672
|
assert(this._secureChannel === null);
|
|
650
673
|
assert(typeof this.endpointUrl === "string");
|
|
651
674
|
|
|
652
|
-
debugLog(
|
|
675
|
+
debugLog(
|
|
676
|
+
"_internal_create_secure_channel creating new ClientSecureChannelLayer _internalState =",
|
|
677
|
+
this._internalState,
|
|
678
|
+
this.clientName
|
|
679
|
+
);
|
|
653
680
|
const secureChannel = new ClientSecureChannelLayer({
|
|
654
681
|
connectionStrategy,
|
|
655
682
|
defaultSecureTokenLifetime: this.defaultSecureTokenLifetime,
|
|
@@ -683,7 +710,6 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
683
710
|
debugLog("_internal_create_secure_channel after secureChannel.create");
|
|
684
711
|
if (!this._secureChannel) {
|
|
685
712
|
debugLog("_secureChannel has been closed during the transaction !");
|
|
686
|
-
assert(this.disconnecting);
|
|
687
713
|
return innerCallback(new Error("Secure Channel Closed"));
|
|
688
714
|
}
|
|
689
715
|
if (!err) {
|
|
@@ -696,10 +722,11 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
696
722
|
(innerCallback: ErrorCallback) => {
|
|
697
723
|
assert(this._secureChannel !== null);
|
|
698
724
|
if (!this.knowsServerEndpoint) {
|
|
725
|
+
this._setInternalState("connecting");
|
|
726
|
+
|
|
699
727
|
this.getEndpoints((err: Error | null /*, endpoints?: EndpointDescription[]*/) => {
|
|
700
728
|
if (!this._secureChannel) {
|
|
701
729
|
debugLog("_secureChannel has been closed during the transaction ! (while getEndpoints)");
|
|
702
|
-
assert(this.disconnecting);
|
|
703
730
|
return innerCallback(new Error("Secure Channel Closed"));
|
|
704
731
|
}
|
|
705
732
|
innerCallback(err ? err : undefined);
|
|
@@ -712,7 +739,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
712
739
|
],
|
|
713
740
|
(err) => {
|
|
714
741
|
if (err) {
|
|
715
|
-
doDebug && debugLog("Inner create secure channel has failed", err.message);
|
|
742
|
+
doDebug && debugLog(this.clientName, " : Inner create secure channel has failed", err.message);
|
|
716
743
|
if (this._secureChannel) {
|
|
717
744
|
this._secureChannel!.abortConnection(() => {
|
|
718
745
|
this._destroy_secure_channel();
|
|
@@ -767,7 +794,6 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
767
794
|
return;
|
|
768
795
|
}
|
|
769
796
|
warningLog("Creating default certificate ... please wait");
|
|
770
|
-
if (this.disconnecting) return;
|
|
771
797
|
|
|
772
798
|
await ClientBaseImpl.createCertificate(
|
|
773
799
|
this.clientCertificateManager,
|
|
@@ -809,14 +835,14 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
809
835
|
if (!fs.existsSync(this.privateKeyFile)) {
|
|
810
836
|
throw new Error(" cannot locate private key file " + this.privateKeyFile);
|
|
811
837
|
}
|
|
812
|
-
if (this.
|
|
838
|
+
if (this.isUnusable()) return;
|
|
813
839
|
|
|
814
840
|
await this.clientCertificateManager.withLock2(async () => {
|
|
815
841
|
await performCertificateSanityCheck(this, "client", this.clientCertificateManager, this._getBuiltApplicationUri());
|
|
816
842
|
});
|
|
817
843
|
}
|
|
818
844
|
|
|
819
|
-
protected _internalState: InternalClientState;
|
|
845
|
+
protected _internalState: InternalClientState = "uninitialized";
|
|
820
846
|
|
|
821
847
|
protected _handleUnrecoverableConnectionFailure(err: Error, callback: ErrorCallback): void {
|
|
822
848
|
debugLog(err.message);
|
|
@@ -867,12 +893,11 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
867
893
|
}
|
|
868
894
|
|
|
869
895
|
this._setInternalState("connecting");
|
|
870
|
-
this.disconnecting = false;
|
|
871
896
|
|
|
872
897
|
this.initializeCM()
|
|
873
898
|
.then(() => {
|
|
874
|
-
debugLog("ClientBaseImpl#connect ", endpointUrl);
|
|
875
|
-
if (this.disconnecting) {
|
|
899
|
+
debugLog("ClientBaseImpl#connect ", endpointUrl, this.clientName);
|
|
900
|
+
if (this._internalState === "disconnecting" || this._internalState === "disconnected") {
|
|
876
901
|
return this._handleDisconnectionWhileConnecting(new Error("premature disconnection 1"), callback);
|
|
877
902
|
}
|
|
878
903
|
|
|
@@ -885,7 +910,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
885
910
|
if (err) {
|
|
886
911
|
return this._handleUnrecoverableConnectionFailure(err, callback);
|
|
887
912
|
}
|
|
888
|
-
if (this.
|
|
913
|
+
if (this.isUnusable()) {
|
|
889
914
|
return this._handleDisconnectionWhileConnecting(new Error("premature disconnection 2"), callback);
|
|
890
915
|
}
|
|
891
916
|
if (forceEndpointDiscoveryOnConnect) {
|
|
@@ -916,7 +941,8 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
916
941
|
this._clockAdjuster = this._clockAdjuster || new ClockAdjustment();
|
|
917
942
|
OPCUAClientBase.registry.register(this);
|
|
918
943
|
|
|
919
|
-
debugLog("__connectStep2");
|
|
944
|
+
debugLog("__connectStep2 ", this._internalState);
|
|
945
|
+
|
|
920
946
|
this._internal_create_secure_channel(this.connectionStrategy, (err: Error | null) => {
|
|
921
947
|
if (!err) {
|
|
922
948
|
this._handleSuccessfulConnection(callback);
|
|
@@ -958,16 +984,6 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
958
984
|
return this._secureChannel ? this._secureChannel.getClientNonce() : null;
|
|
959
985
|
}
|
|
960
986
|
|
|
961
|
-
public requestReconnection() {
|
|
962
|
-
if (this._secureChannel) {
|
|
963
|
-
this._secureChannel.abortConnection(() => {
|
|
964
|
-
errorLog("new connection requested");
|
|
965
|
-
/*
|
|
966
|
-
*/
|
|
967
|
-
});
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
|
-
|
|
971
987
|
public performMessageTransaction(request: Request, callback: ResponseCallback<Response>): void {
|
|
972
988
|
if (!this._secureChannel) {
|
|
973
989
|
// this may happen if the Server has closed the connection abruptly for some unknown reason
|
|
@@ -984,7 +1000,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
984
1000
|
) {
|
|
985
1001
|
return callback(
|
|
986
1002
|
new Error(
|
|
987
|
-
"performMessageTransaction: Invalid client state " +
|
|
1003
|
+
"performMessageTransaction: Invalid client state = " +
|
|
988
1004
|
this._internalState +
|
|
989
1005
|
" while performing a transaction " +
|
|
990
1006
|
request.schema.name
|
|
@@ -1173,11 +1189,6 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1173
1189
|
|
|
1174
1190
|
debugLog(chalk.bgWhite.green("_closeSession ") + this._secureChannel!.channelId);
|
|
1175
1191
|
|
|
1176
|
-
if (this.isReconnecting) {
|
|
1177
|
-
errorLog("OPCUAClientImpl#_closeSession called while reconnection in progress ! What shall we do");
|
|
1178
|
-
return callback(null);
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
1192
|
const request = new CloseSessionRequest({
|
|
1182
1193
|
deleteSubscriptions
|
|
1183
1194
|
});
|
|
@@ -1222,27 +1233,27 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1222
1233
|
public disconnect(...args: any[]): any {
|
|
1223
1234
|
const callback = args[0];
|
|
1224
1235
|
assert(typeof callback === "function", "expecting a callback function here");
|
|
1225
|
-
|
|
1226
|
-
if (this._internalState === "disconnected" || this._internalState === "disconnecting") {
|
|
1227
|
-
if (this._internalState === "disconnecting") {
|
|
1228
|
-
warningLog("[NODE-OPCUA-W26] OPCUAClient#disconnect called while already disconnecting");
|
|
1229
|
-
}
|
|
1230
|
-
return callback();
|
|
1231
|
-
}
|
|
1232
|
-
debugLog("disconnecting client! (will set reconnectionIsCanceled to true");
|
|
1233
1236
|
this._reconnectionIsCanceled = true;
|
|
1234
|
-
this.disconnecting = true;
|
|
1235
|
-
|
|
1236
1237
|
if (this._tmpClient) {
|
|
1238
|
+
warningLog("disconnecting client while tmpClient exists", this._tmpClient.clientName);
|
|
1237
1239
|
this._tmpClient.disconnect((err) => {
|
|
1238
1240
|
this._tmpClient = undefined;
|
|
1239
|
-
assert(!this._tmpClient);
|
|
1240
1241
|
// retry disconnect on main client
|
|
1241
1242
|
this.disconnect(callback);
|
|
1242
1243
|
});
|
|
1243
1244
|
return;
|
|
1244
1245
|
}
|
|
1246
|
+
if (this._internalState === "disconnected" || this._internalState === "disconnecting") {
|
|
1247
|
+
if (this._internalState === "disconnecting") {
|
|
1248
|
+
warningLog("[NODE-OPCUA-W26] OPCUAClient#disconnect called while already disconnecting");
|
|
1249
|
+
}
|
|
1250
|
+
return callback();
|
|
1251
|
+
}
|
|
1252
|
+
debugLog("disconnecting client! (will set reconnectionIsCanceled to true");
|
|
1253
|
+
this._reconnectionIsCanceled = true;
|
|
1254
|
+
|
|
1245
1255
|
debugLog("ClientBaseImpl#disconnect", this.endpointUrl);
|
|
1256
|
+
|
|
1246
1257
|
if (this.isReconnecting && !this._reconnectionIsCanceled) {
|
|
1247
1258
|
debugLog("ClientBaseImpl#disconnect called while reconnection is in progress");
|
|
1248
1259
|
// let's abort the reconnection process
|
|
@@ -1386,6 +1397,9 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1386
1397
|
const params = {
|
|
1387
1398
|
connectionStrategy: this.connectionStrategy,
|
|
1388
1399
|
endpointMustExist: false,
|
|
1400
|
+
|
|
1401
|
+
// Node: May be the discovery endpoint only support security mode NONE
|
|
1402
|
+
// what should we do ?
|
|
1389
1403
|
securityMode: this.securityMode,
|
|
1390
1404
|
securityPolicy: this.securityPolicy,
|
|
1391
1405
|
|
|
@@ -1593,21 +1607,25 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1593
1607
|
debugLog(chalk.yellow.bold(" ClientBaseImpl emitting close"), err?.message);
|
|
1594
1608
|
this._destroy_secure_channel();
|
|
1595
1609
|
if (!err || !this.reconnectOnFailure) {
|
|
1596
|
-
// this is a normal close operation initiated by us
|
|
1597
|
-
/**
|
|
1598
|
-
* @event close
|
|
1599
|
-
* @param error
|
|
1600
|
-
*/
|
|
1601
1610
|
if (err) {
|
|
1611
|
+
/**
|
|
1612
|
+
* @event connection_lost
|
|
1613
|
+
*/
|
|
1602
1614
|
this.emit("connection_lost", err?.message); // instead of "close"
|
|
1603
1615
|
}
|
|
1616
|
+
// this is a normal close operation initiated by us
|
|
1604
1617
|
this.emit("close", err); // instead of "close"
|
|
1605
1618
|
} else {
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1619
|
+
if (
|
|
1620
|
+
this.reconnectOnFailure &&
|
|
1621
|
+
this._internalState !== "reconnecting" &&
|
|
1622
|
+
this._internalState !== "reconnecting_newchannel_connected"
|
|
1623
|
+
) {
|
|
1610
1624
|
debugLog(" ClientBaseImpl emitting connection_lost");
|
|
1625
|
+
this._setInternalState("reconnecting");
|
|
1626
|
+
/**
|
|
1627
|
+
* @event connection_lost
|
|
1628
|
+
*/
|
|
1611
1629
|
this.emit("connection_lost", err?.message); // instead of "close"
|
|
1612
1630
|
this._repairConnection();
|
|
1613
1631
|
}
|
|
@@ -1624,14 +1642,44 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1624
1642
|
});
|
|
1625
1643
|
}
|
|
1626
1644
|
|
|
1627
|
-
|
|
1645
|
+
#insideRepairConnection = false;
|
|
1646
|
+
|
|
1647
|
+
#shouldRepairAgain = false;
|
|
1628
1648
|
|
|
1649
|
+
/**
|
|
1650
|
+
* @internal
|
|
1651
|
+
* @private
|
|
1652
|
+
*
|
|
1653
|
+
* timeout to wait before client attempt to reconnect in case of failure
|
|
1654
|
+
*
|
|
1655
|
+
*/
|
|
1656
|
+
static retryDelay = 1000;
|
|
1629
1657
|
private _repairConnection() {
|
|
1630
|
-
|
|
1631
|
-
|
|
1658
|
+
doDebug && debugLog("_repairConnection = ", this._internalState);
|
|
1659
|
+
if (this.isUnusable()) return;
|
|
1660
|
+
|
|
1661
|
+
const duration = ClientBaseImpl.retryDelay;
|
|
1662
|
+
if (duration) {
|
|
1663
|
+
this.emit("startingDelayBeforeReconnection", duration);
|
|
1664
|
+
setTimeout(() => {
|
|
1665
|
+
if (this.isUnusable()) return;
|
|
1666
|
+
this.__innerRepairConnection();
|
|
1667
|
+
}, duration);
|
|
1668
|
+
} else {
|
|
1669
|
+
this.__innerRepairConnection();
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
private __innerRepairConnection() {
|
|
1673
|
+
if (this.isUnusable()) return;
|
|
1674
|
+
|
|
1675
|
+
debugLog("Entering _repairConnection ", this._internalState);
|
|
1676
|
+
if (this.#insideRepairConnection) {
|
|
1677
|
+
errorLog("_repairConnection already in progress internal state = ", this._internalState);
|
|
1678
|
+
this.#shouldRepairAgain = true;
|
|
1632
1679
|
return;
|
|
1633
1680
|
}
|
|
1634
|
-
this.
|
|
1681
|
+
this.emit("repairConnectionStarted");
|
|
1682
|
+
this.#insideRepairConnection = true;
|
|
1635
1683
|
debugLog("recreating new secure channel ", this._internalState);
|
|
1636
1684
|
this._recreate_secure_channel((err1?: Error) => {
|
|
1637
1685
|
debugLog("secureChannel#on(close) => _recreate_secure_channel returns ", err1 ? err1.message : "OK");
|
|
@@ -1639,10 +1687,16 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1639
1687
|
if (err1) {
|
|
1640
1688
|
debugLog("_recreate_secure_channel has failed: err = ", err1.message);
|
|
1641
1689
|
this.emit("close", err1);
|
|
1642
|
-
this
|
|
1643
|
-
this
|
|
1690
|
+
this.#insideRepairConnection = false;
|
|
1691
|
+
if (this.#shouldRepairAgain) {
|
|
1692
|
+
this.#shouldRepairAgain = false;
|
|
1693
|
+
this._repairConnection();
|
|
1694
|
+
} else {
|
|
1695
|
+
this._setInternalState("disconnected");
|
|
1696
|
+
}
|
|
1644
1697
|
return;
|
|
1645
1698
|
} else {
|
|
1699
|
+
if (this.isUnusable()) return;
|
|
1646
1700
|
this._finalReconnectionStep((err2?: Error | null) => {
|
|
1647
1701
|
if (err2) {
|
|
1648
1702
|
// istanbul ignore next
|
|
@@ -1653,16 +1707,21 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1653
1707
|
// we still need to retry connecting here !!!
|
|
1654
1708
|
debugLog("Disconnected following reconnection failure", err2.message);
|
|
1655
1709
|
debugLog(`I will retry OPCUA client reconnection in ${OPCUAClientBase.retryDelay / 1000} seconds`);
|
|
1656
|
-
this
|
|
1710
|
+
this.#insideRepairConnection = false;
|
|
1711
|
+
this.#shouldRepairAgain = false;
|
|
1712
|
+
|
|
1657
1713
|
this._destroy_secure_channel();
|
|
1714
|
+
// this._setInternalState("reconnecting_failed");
|
|
1658
1715
|
setTimeout(() => this._repairConnection(), OPCUAClientBase.retryDelay);
|
|
1716
|
+
|
|
1659
1717
|
return;
|
|
1660
1718
|
} else {
|
|
1661
1719
|
/**
|
|
1662
1720
|
* @event connection_reestablished
|
|
1663
1721
|
* send when the connection is reestablished after a connection break
|
|
1664
1722
|
*/
|
|
1665
|
-
this
|
|
1723
|
+
this.#insideRepairConnection = false;
|
|
1724
|
+
this.#shouldRepairAgain = false;
|
|
1666
1725
|
this._setInternalState("connected");
|
|
1667
1726
|
this.emit("connection_reestablished");
|
|
1668
1727
|
}
|
|
@@ -1720,13 +1779,9 @@ class TmpClient extends ClientBaseImpl {
|
|
|
1720
1779
|
return;
|
|
1721
1780
|
}
|
|
1722
1781
|
|
|
1723
|
-
if (this.disconnecting) {
|
|
1724
|
-
return this._handleUnrecoverableConnectionFailure(new Error("premature disconnection 3"), callback!);
|
|
1725
|
-
}
|
|
1726
|
-
|
|
1727
1782
|
this._setInternalState("connecting");
|
|
1728
1783
|
this._connectStep2(endpoint, (err?: Error) => {
|
|
1729
|
-
if (this.
|
|
1784
|
+
if (this.isUnusable()) {
|
|
1730
1785
|
return this._handleUnrecoverableConnectionFailure(new Error("premature disconnection 4"), callback!);
|
|
1731
1786
|
}
|
|
1732
1787
|
callback!(err);
|