node-opcua-client 2.166.0 → 2.167.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.d.ts +1 -1
- package/dist/alarms_and_conditions/client_alarm_tools.js +2 -2
- package/dist/alarms_and_conditions/client_alarm_tools.js.map +1 -1
- package/dist/alarms_and_conditions/client_tools.d.ts +3 -0
- package/dist/alarms_and_conditions/client_tools.js +2 -2
- package/dist/alarms_and_conditions/client_tools.js.map +1 -1
- package/dist/client_base.d.ts +47 -40
- package/dist/client_base.js +5 -6
- package/dist/client_base.js.map +1 -1
- package/dist/client_monitored_item.d.ts +7 -7
- package/dist/client_monitored_item.js.map +1 -1
- package/dist/client_monitored_item_base.d.ts +12 -13
- package/dist/client_monitored_item_group.d.ts +5 -5
- package/dist/client_monitored_item_toolbox.d.ts +6 -7
- package/dist/client_monitored_item_toolbox.js.map +1 -1
- package/dist/client_session.d.ts +19 -23
- package/dist/client_session.js.map +1 -1
- package/dist/client_session_keepalive_manager.d.ts +1 -1
- package/dist/client_session_keepalive_manager.js +6 -6
- package/dist/client_session_keepalive_manager.js.map +1 -1
- package/dist/client_subscription.d.ts +11 -12
- package/dist/client_subscription.js.map +1 -1
- package/dist/client_utils.d.ts +3 -3
- package/dist/client_utils.js.map +1 -1
- package/dist/common.d.ts +12 -12
- package/dist/index.d.ts +26 -27
- package/dist/index.js +65 -66
- package/dist/index.js.map +1 -1
- package/dist/opcua_client.d.ts +17 -19
- package/dist/opcua_client.js.map +1 -1
- package/dist/private/client_base_impl.d.ts +19 -18
- package/dist/private/client_base_impl.js +140 -119
- package/dist/private/client_base_impl.js.map +1 -1
- package/dist/private/client_monitored_item_group_impl.d.ts +4 -5
- package/dist/private/client_monitored_item_group_impl.js +1 -1
- package/dist/private/client_monitored_item_group_impl.js.map +1 -1
- package/dist/private/client_monitored_item_impl.d.ts +9 -10
- package/dist/private/client_monitored_item_impl.js.map +1 -1
- package/dist/private/client_publish_engine.d.ts +3 -3
- package/dist/private/client_publish_engine.js +6 -7
- package/dist/private/client_publish_engine.js.map +1 -1
- package/dist/private/client_session_impl.d.ts +24 -25
- package/dist/private/client_session_impl.js +14 -10
- package/dist/private/client_session_impl.js.map +1 -1
- package/dist/private/client_subscription_impl.d.ts +10 -11
- package/dist/private/client_subscription_impl.js +12 -11
- package/dist/private/client_subscription_impl.js.map +1 -1
- package/dist/private/i_private_client.d.ts +7 -7
- package/dist/private/opcua_client_impl.d.ts +12 -9
- package/dist/private/opcua_client_impl.js +58 -48
- 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 +1 -1
- package/dist/private/reconnection/client_publish_engine_reconnection.js +4 -2
- package/dist/private/reconnection/client_publish_engine_reconnection.js.map +1 -1
- package/dist/private/reconnection/client_reconnection.d.ts +1 -1
- package/dist/private/reconnection/client_subscription_reconnection.d.ts +1 -1
- package/dist/private/reconnection/client_subscription_reconnection.js +2 -2
- package/dist/private/reconnection/client_subscription_reconnection.js.map +1 -1
- package/dist/private/reconnection/reconnection.d.ts +3 -3
- package/dist/private/reconnection/reconnection.js +1 -1
- package/dist/private/reconnection/reconnection.js.map +1 -1
- package/dist/tools/findservers.d.ts +7 -2
- package/dist/tools/findservers.js +41 -53
- package/dist/tools/findservers.js.map +1 -1
- package/dist/tools/read_history_server_capabilities.d.ts +1 -1
- package/dist/tools/read_history_server_capabilities.js +9 -8
- package/dist/tools/read_history_server_capabilities.js.map +1 -1
- package/dist/user_identity_info.d.ts +1 -1
- package/dist/verify.js.map +1 -1
- package/package.json +41 -40
- package/source/alarms_and_conditions/client_alarm_tools.ts +14 -8
- package/source/alarms_and_conditions/client_tools.ts +7 -6
- package/source/client_base.ts +93 -79
- package/source/client_monitored_item.ts +7 -8
- package/source/client_monitored_item_base.ts +12 -14
- package/source/client_monitored_item_group.ts +5 -5
- package/source/client_monitored_item_toolbox.ts +13 -14
- package/source/client_session.ts +37 -40
- package/source/client_session_keepalive_manager.ts +7 -10
- package/source/client_subscription.ts +11 -12
- package/source/client_utils.ts +6 -6
- package/source/common.ts +12 -12
- package/source/index.ts +44 -40
- package/source/opcua_client.ts +24 -23
- package/source/private/client_base_impl.ts +276 -186
- package/source/private/client_monitored_item_group_impl.ts +10 -14
- package/source/private/client_monitored_item_impl.ts +17 -17
- package/source/private/client_publish_engine.ts +11 -12
- package/source/private/client_session_impl.ts +85 -82
- package/source/private/client_subscription_impl.ts +42 -41
- package/source/private/i_private_client.ts +8 -8
- package/source/private/opcua_client_impl.ts +118 -97
- package/source/private/performance.ts +2 -3
- package/source/private/reconnection/client_publish_engine_reconnection.ts +16 -15
- package/source/private/reconnection/client_reconnection.ts +1 -1
- package/source/private/reconnection/client_subscription_reconnection.ts +16 -13
- package/source/private/reconnection/reconnection.ts +130 -33
- package/source/tools/findservers.ts +43 -62
- package/source/tools/read_history_server_capabilities.ts +20 -22
- package/source/user_identity_info.ts +5 -5
- package/source/verify.ts +25 -25
|
@@ -2,75 +2,107 @@
|
|
|
2
2
|
* @module node-opcua-client-private
|
|
3
3
|
*/
|
|
4
4
|
// tslint:disable:no-unused-expression
|
|
5
|
-
import fs from "fs";
|
|
6
|
-
import path from "path";
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
|
|
8
|
+
import { withLock } from "@ster5/global-mutex";
|
|
7
9
|
import async from "async";
|
|
8
10
|
import chalk from "chalk";
|
|
9
|
-
import { withLock } from "@ster5/global-mutex";
|
|
10
11
|
import { assert } from "node-opcua-assert";
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
import {
|
|
13
|
+
getDefaultCertificateManager,
|
|
14
|
+
makeSubject,
|
|
15
|
+
type OPCUACertificateManager
|
|
16
|
+
} from "node-opcua-certificate-manager";
|
|
17
|
+
import {
|
|
18
|
+
type IOPCUASecureObjectOptions,
|
|
19
|
+
makeApplicationUrn,
|
|
20
|
+
OPCUASecureObject
|
|
21
|
+
} from "node-opcua-common";
|
|
22
|
+
import {
|
|
23
|
+
type Certificate,
|
|
24
|
+
makeSHA1Thumbprint,
|
|
25
|
+
split_der
|
|
26
|
+
} from "node-opcua-crypto/web";
|
|
27
|
+
import {
|
|
28
|
+
installPeriodicClockAdjustment,
|
|
29
|
+
periodicClockAdjustment,
|
|
30
|
+
uninstallPeriodicClockAdjustment
|
|
31
|
+
} from "node-opcua-date-time";
|
|
32
|
+
import {
|
|
33
|
+
checkDebugFlag,
|
|
34
|
+
make_debugLog,
|
|
35
|
+
make_errorLog,
|
|
36
|
+
make_warningLog
|
|
37
|
+
} from "node-opcua-debug";
|
|
38
|
+
import {
|
|
39
|
+
getHostname
|
|
40
|
+
} from "node-opcua-hostname";
|
|
41
|
+
import type {
|
|
42
|
+
IBasicTransportSettings,
|
|
43
|
+
ResponseCallback
|
|
44
|
+
} from "node-opcua-pseudo-session";
|
|
19
45
|
import {
|
|
20
46
|
ClientSecureChannelLayer,
|
|
47
|
+
type ConnectionStrategy,
|
|
48
|
+
type ConnectionStrategyOptions,
|
|
21
49
|
coerceConnectionStrategy,
|
|
22
50
|
coerceSecurityPolicy,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
SecurityPolicy
|
|
51
|
+
type Request as Request1,
|
|
52
|
+
type Response as Response1,
|
|
53
|
+
type SecurityPolicy,
|
|
54
|
+
type PerformTransactionCallback
|
|
28
55
|
} from "node-opcua-secure-channel";
|
|
29
56
|
import {
|
|
30
57
|
FindServersOnNetworkRequest,
|
|
31
|
-
FindServersOnNetworkRequestOptions,
|
|
58
|
+
type FindServersOnNetworkRequestOptions,
|
|
32
59
|
FindServersOnNetworkResponse,
|
|
33
60
|
FindServersRequest,
|
|
34
61
|
FindServersResponse,
|
|
35
|
-
ServerOnNetwork
|
|
62
|
+
type ServerOnNetwork
|
|
36
63
|
} from "node-opcua-service-discovery";
|
|
37
64
|
import {
|
|
38
|
-
ApplicationDescription,
|
|
39
|
-
EndpointDescription,
|
|
65
|
+
type ApplicationDescription,
|
|
66
|
+
type EndpointDescription,
|
|
40
67
|
GetEndpointsRequest,
|
|
41
68
|
GetEndpointsResponse
|
|
42
69
|
} from "node-opcua-service-endpoints";
|
|
43
|
-
import { ChannelSecurityToken, coerceMessageSecurityMode, MessageSecurityMode } from "node-opcua-service-secure-channel";
|
|
44
|
-
import { ErrorCallback, StatusCode, StatusCodes } from "node-opcua-status-code";
|
|
45
|
-
import { matchUri, checkFileExistsAndIsNotEmpty } from "node-opcua-utils";
|
|
46
|
-
|
|
47
|
-
import { getDefaultCertificateManager, makeSubject, OPCUACertificateManager } from "node-opcua-certificate-manager";
|
|
48
|
-
import { VerificationStatus } from "node-opcua-pki";
|
|
49
|
-
import { CloseSessionRequest, CloseSessionResponse } from "node-opcua-service-session";
|
|
50
|
-
import { Request, Response } from "../common";
|
|
51
|
-
|
|
52
70
|
import {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
71
|
+
type ChannelSecurityToken,
|
|
72
|
+
coerceMessageSecurityMode, MessageSecurityMode
|
|
73
|
+
} from "node-opcua-service-secure-channel";
|
|
74
|
+
import { CloseSessionRequest, type CloseSessionResponse } from "node-opcua-service-session";
|
|
75
|
+
import { type ErrorCallback, StatusCodes } from "node-opcua-status-code";
|
|
76
|
+
import { checkFileExistsAndIsNotEmpty, matchUri } from "node-opcua-utils";
|
|
77
|
+
import {
|
|
78
|
+
type CreateSecureChannelCallbackFunc,
|
|
79
|
+
type FindEndpointCallback,
|
|
80
|
+
type FindEndpointOptions,
|
|
81
|
+
type FindEndpointResult,
|
|
82
|
+
type FindServersOnNetworkRequestLike,
|
|
83
|
+
type FindServersRequestLike,
|
|
84
|
+
type GetEndpointsOptions,
|
|
60
85
|
OPCUAClientBase,
|
|
61
|
-
|
|
62
|
-
|
|
86
|
+
type OPCUAClientBaseEvents,
|
|
87
|
+
type OPCUAClientBaseOptions,
|
|
88
|
+
type TransportSettings
|
|
63
89
|
} from "../client_base";
|
|
64
|
-
import {
|
|
90
|
+
import type { Request, Response } from "../common";
|
|
91
|
+
import type { UserIdentityInfo } from "../user_identity_info";
|
|
65
92
|
import { performCertificateSanityCheck } from "../verify";
|
|
66
|
-
import { ClientSessionImpl } from "./client_session_impl";
|
|
67
|
-
import { IClientBase } from "./i_private_client";
|
|
68
|
-
import { waitUntilReconnectionIsCanceled } from "./reconnection/client_reconnection";
|
|
93
|
+
import type { ClientSessionImpl } from "./client_session_impl";
|
|
94
|
+
import type { IClientBase } from "./i_private_client";
|
|
69
95
|
|
|
70
96
|
const debugLog = make_debugLog(__filename);
|
|
71
97
|
const doDebug = checkDebugFlag(__filename);
|
|
72
98
|
const errorLog = make_errorLog(__filename);
|
|
73
99
|
const warningLog = make_warningLog(__filename);
|
|
100
|
+
|
|
101
|
+
function makeCertificateThumbPrint(certificate: Certificate | Certificate[] | null | undefined): Buffer | null {
|
|
102
|
+
if (!certificate) return null;
|
|
103
|
+
return makeSHA1Thumbprint(Array.isArray(certificate) ? certificate[0] : certificate);
|
|
104
|
+
}
|
|
105
|
+
|
|
74
106
|
const traceInternalState = false;
|
|
75
107
|
|
|
76
108
|
const defaultConnectionStrategy: ConnectionStrategyOptions = {
|
|
@@ -96,7 +128,7 @@ function __findEndpoint(this: ClientBaseImpl, endpointUrl: string, params: FindE
|
|
|
96
128
|
|
|
97
129
|
const securityMode = params.securityMode;
|
|
98
130
|
const securityPolicy = params.securityPolicy;
|
|
99
|
-
const
|
|
131
|
+
const _connectionStrategy = params.connectionStrategy;
|
|
100
132
|
const options: OPCUAClientBaseOptions = {
|
|
101
133
|
applicationName: params.applicationName,
|
|
102
134
|
applicationUri: params.applicationUri,
|
|
@@ -122,7 +154,9 @@ function __findEndpoint(this: ClientBaseImpl, endpointUrl: string, params: FindE
|
|
|
122
154
|
const tasks = [
|
|
123
155
|
(innerCallback: ErrorCallback) => {
|
|
124
156
|
// rebind backoff handler
|
|
125
|
-
masterClient.listeners("backoff").forEach((handler
|
|
157
|
+
masterClient.listeners("backoff").forEach((handler) => {
|
|
158
|
+
client.on("backoff", handler as unknown as (retryCount: number, delay: number) => void);
|
|
159
|
+
});
|
|
126
160
|
|
|
127
161
|
// c8 ignore next
|
|
128
162
|
if (doDebug) {
|
|
@@ -157,7 +191,7 @@ function __findEndpoint(this: ClientBaseImpl, endpointUrl: string, params: FindE
|
|
|
157
191
|
(innerCallback: ErrorCallback) => {
|
|
158
192
|
client.getEndpoints((err: Error | null, endpoints?: EndpointDescription[]) => {
|
|
159
193
|
if (err) {
|
|
160
|
-
err.message =
|
|
194
|
+
err.message = `error in getEndpoints \n${err.message}`;
|
|
161
195
|
return innerCallback(err);
|
|
162
196
|
}
|
|
163
197
|
// c8 ignore next
|
|
@@ -223,9 +257,7 @@ function __findEndpoint(this: ClientBaseImpl, endpointUrl: string, params: FindE
|
|
|
223
257
|
/**
|
|
224
258
|
* check if certificate is trusted or untrusted
|
|
225
259
|
*/
|
|
226
|
-
async function _verify_serverCertificate(
|
|
227
|
-
certificateManager: OPCUACertificateManager,
|
|
228
|
-
serverCertificate: Certificate) {
|
|
260
|
+
async function _verify_serverCertificate(certificateManager: OPCUACertificateManager, serverCertificate: Certificate) {
|
|
229
261
|
const status = await certificateManager.checkCertificate(serverCertificate);
|
|
230
262
|
if (status !== StatusCodes.Good) {
|
|
231
263
|
// c8 ignore next
|
|
@@ -234,9 +266,9 @@ async function _verify_serverCertificate(
|
|
|
234
266
|
const status1 = await certificateManager.verifyCertificate(serverCertificate);
|
|
235
267
|
debugLog(status1);
|
|
236
268
|
}
|
|
237
|
-
warningLog("serverCertificate = ",
|
|
269
|
+
warningLog("serverCertificate = ", makeCertificateThumbPrint(serverCertificate)?.toString("hex") || "none");
|
|
238
270
|
warningLog("serverCertificate = ", serverCertificate.toString("base64"));
|
|
239
|
-
throw new Error(
|
|
271
|
+
throw new Error(`server Certificate verification failed with err ${status?.toString()}`);
|
|
240
272
|
}
|
|
241
273
|
}
|
|
242
274
|
|
|
@@ -290,7 +322,9 @@ let g_ClientCounter = 0;
|
|
|
290
322
|
* @internal
|
|
291
323
|
*/
|
|
292
324
|
// tslint:disable-next-line: max-classes-per-file
|
|
293
|
-
export class ClientBaseImpl extends
|
|
325
|
+
export class ClientBaseImpl<Events extends OPCUAClientBaseEvents = OPCUAClientBaseEvents>
|
|
326
|
+
extends OPCUASecureObject<Events>
|
|
327
|
+
implements OPCUAClientBase<Events>, IClientBase {
|
|
294
328
|
/**
|
|
295
329
|
* total number of requests that been canceled due to timeout
|
|
296
330
|
*/
|
|
@@ -317,7 +351,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
317
351
|
*/
|
|
318
352
|
get isReconnecting(): boolean {
|
|
319
353
|
return (
|
|
320
|
-
!!
|
|
354
|
+
!!this._secureChannel?.isConnecting ||
|
|
321
355
|
this._internalState === "reconnecting_newchannel_connected" ||
|
|
322
356
|
this._internalState === "reconnecting"
|
|
323
357
|
);
|
|
@@ -346,7 +380,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
346
380
|
|
|
347
381
|
public securityMode: MessageSecurityMode;
|
|
348
382
|
public securityPolicy: SecurityPolicy;
|
|
349
|
-
public serverCertificate?: Certificate;
|
|
383
|
+
public serverCertificate?: Certificate | Certificate[];
|
|
350
384
|
public clientName: string;
|
|
351
385
|
public protocolVersion: 0;
|
|
352
386
|
public defaultSecureTokenLifetime: number;
|
|
@@ -412,11 +446,15 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
412
446
|
|
|
413
447
|
this._internalState = internalState;
|
|
414
448
|
}
|
|
415
|
-
public emit(eventName:
|
|
449
|
+
public emit<K>(eventName: K, ...others: unknown[]): boolean {
|
|
416
450
|
// c8 ignore next
|
|
417
451
|
if (doDebug) {
|
|
418
|
-
debugLog(
|
|
452
|
+
debugLog(
|
|
453
|
+
chalk.cyan(` Client ${this._instanceNumber} ${this.clientName} emitting `),
|
|
454
|
+
chalk.magentaBright(eventName as string)
|
|
455
|
+
);
|
|
419
456
|
}
|
|
457
|
+
// @ts-expect-error
|
|
420
458
|
return super.emit(eventName, ...others);
|
|
421
459
|
}
|
|
422
460
|
constructor(options?: OPCUAClientBaseOptions) {
|
|
@@ -464,9 +502,10 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
464
502
|
this.defaultTransactionTimeout = options.defaultTransactionTimeout;
|
|
465
503
|
|
|
466
504
|
this.tokenRenewalInterval = options.tokenRenewalInterval || 0;
|
|
467
|
-
assert(isFinite(this.tokenRenewalInterval) && this.tokenRenewalInterval >= 0);
|
|
505
|
+
assert(Number.isFinite(this.tokenRenewalInterval) && this.tokenRenewalInterval >= 0);
|
|
468
506
|
this.securityMode = coerceMessageSecurityMode(options.securityMode);
|
|
469
507
|
this.securityPolicy = coerceSecurityPolicy(options.securityPolicy);
|
|
508
|
+
|
|
470
509
|
this.serverCertificate = options.serverCertificate;
|
|
471
510
|
|
|
472
511
|
this.keepSessionAlive = typeof options.keepSessionAlive === "boolean" ? options.keepSessionAlive : false;
|
|
@@ -517,9 +556,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
517
556
|
this._secureChannel = null;
|
|
518
557
|
callback();
|
|
519
558
|
});
|
|
520
|
-
|
|
521
|
-
/* empty */
|
|
522
|
-
});
|
|
559
|
+
|
|
523
560
|
}
|
|
524
561
|
|
|
525
562
|
public _recreate_secure_channel(callback: ErrorCallback): void {
|
|
@@ -527,7 +564,8 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
527
564
|
|
|
528
565
|
if (!this.knowsServerEndpoint) {
|
|
529
566
|
debugLog("Cannot reconnect , server endpoint is unknown");
|
|
530
|
-
|
|
567
|
+
callback(new Error("Cannot reconnect, server endpoint is unknown - this.knowsServerEndpoint = false"));
|
|
568
|
+
return;
|
|
531
569
|
}
|
|
532
570
|
assert(this.knowsServerEndpoint);
|
|
533
571
|
|
|
@@ -548,7 +586,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
548
586
|
const _when_reconnectionIsCanceled = (callback: ErrorCallback) => {
|
|
549
587
|
doDebug && debugLog("attempt to recreate a new secure channel : suspended because reconnection is canceled !");
|
|
550
588
|
this.emit("reconnection_canceled");
|
|
551
|
-
return callback(new Error(
|
|
589
|
+
return callback(new Error(`Reconnection has been canceled - ${this.clientName}`));
|
|
552
590
|
};
|
|
553
591
|
|
|
554
592
|
const _failAndRetry = (err: Error, message: string, callback: ErrorCallback) => {
|
|
@@ -597,20 +635,21 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
597
635
|
if (err.message.match(/ECONNREFUSED|ECONNABORTED|ETIMEDOUT/)) {
|
|
598
636
|
return _failAndRetry(
|
|
599
637
|
err,
|
|
600
|
-
|
|
638
|
+
`create secure channel failed with ECONNREFUSED|ECONNABORTED|ETIMEDOUT\n${err.message}`,
|
|
601
639
|
callback
|
|
602
640
|
);
|
|
603
641
|
}
|
|
604
642
|
|
|
605
643
|
if (err.message.match("Backoff aborted.")) {
|
|
606
|
-
|
|
644
|
+
_failAndRetry(err, "cannot create secure channel (backoff aborted)", callback);
|
|
645
|
+
return;
|
|
607
646
|
}
|
|
608
647
|
|
|
609
648
|
if (
|
|
610
|
-
err
|
|
611
|
-
err
|
|
649
|
+
err?.message.match("BadCertificateInvalid") ||
|
|
650
|
+
err?.message.match(/socket has been disconnected by third party/)
|
|
612
651
|
) {
|
|
613
|
-
// it is possible also that hte server has shutdown innapropriately the connection
|
|
652
|
+
// it is possible also that hte server has shutdown innapropriately the connection
|
|
614
653
|
warningLog(
|
|
615
654
|
"the server certificate has changed, we need to retrieve server certificate again: ",
|
|
616
655
|
err.message
|
|
@@ -618,7 +657,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
618
657
|
const oldServerCertificate = this.serverCertificate;
|
|
619
658
|
warningLog(
|
|
620
659
|
"old server certificate ",
|
|
621
|
-
|
|
660
|
+
makeCertificateThumbPrint(oldServerCertificate)?.toString("hex") || "undefined"
|
|
622
661
|
);
|
|
623
662
|
// the server may have shut down the channel because its certificate
|
|
624
663
|
// has changed ....
|
|
@@ -627,11 +666,14 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
627
666
|
if (err1) {
|
|
628
667
|
return _failAndRetry(err1, "Failing to fetch new server certificate", callback);
|
|
629
668
|
}
|
|
630
|
-
const newServerCertificate = this.serverCertificate
|
|
631
|
-
warningLog(
|
|
669
|
+
const newServerCertificate = this.serverCertificate;
|
|
670
|
+
warningLog(
|
|
671
|
+
"new server certificate ",
|
|
672
|
+
makeCertificateThumbPrint(newServerCertificate)?.toString("hex") || "none"
|
|
673
|
+
);
|
|
632
674
|
|
|
633
|
-
const sha1Old =
|
|
634
|
-
const sha1New =
|
|
675
|
+
const sha1Old = makeCertificateThumbPrint(oldServerCertificate)?.toString("hex") || null;
|
|
676
|
+
const sha1New = makeCertificateThumbPrint(newServerCertificate)?.toString("hex") || null;
|
|
635
677
|
if (sha1Old === sha1New) {
|
|
636
678
|
warningLog("server certificate has not changed, but was expected to have changed");
|
|
637
679
|
return _failAndRetry(
|
|
@@ -740,7 +782,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
740
782
|
if (err) {
|
|
741
783
|
doDebug && debugLog(this.clientName, " : Inner create secure channel has failed", err.message);
|
|
742
784
|
if (this._secureChannel) {
|
|
743
|
-
this._secureChannel
|
|
785
|
+
this._secureChannel.abortConnection(() => {
|
|
744
786
|
this._destroy_secure_channel();
|
|
745
787
|
callback(err);
|
|
746
788
|
});
|
|
@@ -776,19 +818,19 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
776
818
|
}
|
|
777
819
|
// c8 ignore next
|
|
778
820
|
if (!fs.existsSync(certificateFile)) {
|
|
779
|
-
throw new Error(
|
|
821
|
+
throw new Error(` cannot locate certificate file ${certificateFile}`);
|
|
780
822
|
}
|
|
781
823
|
}
|
|
782
824
|
|
|
783
825
|
public async createDefaultCertificate(): Promise<void> {
|
|
784
826
|
// c8 ignore next
|
|
785
|
-
if ((this as
|
|
827
|
+
if ((this as unknown as { _inCreateDefaultCertificate: boolean })._inCreateDefaultCertificate) {
|
|
786
828
|
errorLog("Internal error : re-entrancy in createDefaultCertificate!");
|
|
787
829
|
}
|
|
788
|
-
(this as
|
|
830
|
+
(this as unknown as { _inCreateDefaultCertificate: boolean })._inCreateDefaultCertificate = true;
|
|
789
831
|
|
|
790
832
|
if (!checkFileExistsAndIsNotEmpty(this.certificateFile)) {
|
|
791
|
-
await withLock({ fileToLock: this.certificateFile
|
|
833
|
+
await withLock({ fileToLock: `${this.certificateFile}.mutex` }, async () => {
|
|
792
834
|
if (checkFileExistsAndIsNotEmpty(this.certificateFile)) {
|
|
793
835
|
// the file may have been created in between
|
|
794
836
|
return;
|
|
@@ -804,11 +846,11 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
804
846
|
debugLog("privateKey = ", this.privateKeyFile);
|
|
805
847
|
debugLog(" = ", this.clientCertificateManager.privateKey);
|
|
806
848
|
debugLog("certificateFile = ", this.certificateFile);
|
|
807
|
-
const
|
|
808
|
-
const
|
|
849
|
+
const _certificate = this.getCertificate();
|
|
850
|
+
const _privateKey = this.getPrivateKey();
|
|
809
851
|
});
|
|
810
852
|
}
|
|
811
|
-
(this as
|
|
853
|
+
(this as unknown as { _inCreateDefaultCertificate: boolean })._inCreateDefaultCertificate = false;
|
|
812
854
|
}
|
|
813
855
|
|
|
814
856
|
protected _getBuiltApplicationUri(): string {
|
|
@@ -833,7 +875,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
833
875
|
await this.createDefaultCertificate();
|
|
834
876
|
// c8 ignore next
|
|
835
877
|
if (!fs.existsSync(this.privateKeyFile)) {
|
|
836
|
-
throw new Error(
|
|
878
|
+
throw new Error(` cannot locate private key file ${this.privateKeyFile}`);
|
|
837
879
|
}
|
|
838
880
|
if (this.isUnusable()) return;
|
|
839
881
|
|
|
@@ -850,13 +892,13 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
850
892
|
debugLog(err.message);
|
|
851
893
|
this.emit("connection_failed", err);
|
|
852
894
|
this._setInternalState("disconnected");
|
|
853
|
-
|
|
895
|
+
callback(err);
|
|
854
896
|
}
|
|
855
897
|
private _handleDisconnectionWhileConnecting(err: Error, callback: ErrorCallback) {
|
|
856
898
|
debugLog(err.message);
|
|
857
899
|
this.emit("connection_failed", err);
|
|
858
900
|
this._setInternalState("disconnected");
|
|
859
|
-
|
|
901
|
+
callback(err);
|
|
860
902
|
}
|
|
861
903
|
private _handleSuccessfulConnection(callback: ErrorCallback) {
|
|
862
904
|
debugLog(" Connected successfully to ", this.endpointUrl);
|
|
@@ -870,12 +912,12 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
870
912
|
*/
|
|
871
913
|
public connect(endpointUrl: string): Promise<void>;
|
|
872
914
|
public connect(endpointUrl: string, callback: ErrorCallback): void;
|
|
873
|
-
public connect(...args:
|
|
915
|
+
public connect(...args: unknown[]): Promise<void> | void {
|
|
874
916
|
const endpointUrl = args[0];
|
|
875
|
-
const callback = args[1];
|
|
917
|
+
const callback = args[1] as ErrorCallback;
|
|
876
918
|
assert(typeof callback === "function", "expecting a callback");
|
|
877
919
|
if (typeof endpointUrl !== "string" || endpointUrl.length <= 0) {
|
|
878
|
-
errorLog(
|
|
920
|
+
errorLog(`[NODE-OPCUA-E03] OPCUAClient#connect expects a valid endpoint : ${endpointUrl}`);
|
|
879
921
|
callback(new Error("Invalid endpoint"));
|
|
880
922
|
return;
|
|
881
923
|
}
|
|
@@ -916,7 +958,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
916
958
|
}
|
|
917
959
|
if (forceEndpointDiscoveryOnConnect) {
|
|
918
960
|
debugLog("connecting with adjusted endpoint : ", adjustedEndpointUrl, " was =", endpointUrl);
|
|
919
|
-
this._connectStep2(adjustedEndpointUrl
|
|
961
|
+
this._connectStep2(adjustedEndpointUrl || "", callback);
|
|
920
962
|
} else {
|
|
921
963
|
debugLog("connecting with endpoint : ", endpointUrl);
|
|
922
964
|
this._connectStep2(endpointUrl, callback);
|
|
@@ -955,15 +997,13 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
955
997
|
}
|
|
956
998
|
debugLog(chalk.red("SecureChannel creation has failed with error :", err.message));
|
|
957
999
|
if (err.message.match(/ECONNABORTED/)) {
|
|
958
|
-
debugLog(chalk.yellow(
|
|
1000
|
+
debugLog(chalk.yellow(`- The client cannot to :${endpointUrl}. Connection has been aborted.`));
|
|
959
1001
|
err = new Error("The connection has been aborted");
|
|
960
1002
|
this._handleUnrecoverableConnectionFailure(err, callback);
|
|
961
1003
|
} else if (err.message.match(/ECONNREF/)) {
|
|
962
|
-
debugLog(chalk.yellow(
|
|
1004
|
+
debugLog(chalk.yellow(`- The client cannot to :${endpointUrl}. Server is not reachable.`));
|
|
963
1005
|
err = new Error(
|
|
964
|
-
|
|
965
|
-
endpointUrl +
|
|
966
|
-
" .\n" +
|
|
1006
|
+
`The connection cannot be established with server ${endpointUrl} .\n` +
|
|
967
1007
|
"Please check that the server is up and running or your network configuration.\n" +
|
|
968
1008
|
"Err = (" +
|
|
969
1009
|
err.message +
|
|
@@ -974,20 +1014,24 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
974
1014
|
/* */
|
|
975
1015
|
this._handleDisconnectionWhileConnecting(err, callback);
|
|
976
1016
|
} else {
|
|
977
|
-
err = new Error(
|
|
1017
|
+
err = new Error(`The connection may have been rejected by server,\n Err = (${err.message})`);
|
|
978
1018
|
this._handleUnrecoverableConnectionFailure(err, callback);
|
|
979
1019
|
}
|
|
980
1020
|
}
|
|
981
1021
|
});
|
|
982
1022
|
}
|
|
983
1023
|
|
|
984
|
-
public performMessageTransaction(
|
|
1024
|
+
public performMessageTransaction(
|
|
1025
|
+
request: Request,
|
|
1026
|
+
callback: ResponseCallback<Response>
|
|
1027
|
+
): void {
|
|
985
1028
|
if (!this._secureChannel) {
|
|
986
1029
|
// this may happen if the Server has closed the connection abruptly for some unknown reason
|
|
987
1030
|
// or if the tcp connection has been broken.
|
|
988
|
-
|
|
1031
|
+
callback(
|
|
989
1032
|
new Error("performMessageTransaction: No SecureChannel , connection may have been canceled abruptly by server")
|
|
990
1033
|
);
|
|
1034
|
+
return;
|
|
991
1035
|
}
|
|
992
1036
|
if (
|
|
993
1037
|
this._internalState !== "connected" &&
|
|
@@ -995,7 +1039,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
995
1039
|
this._internalState !== "connecting" &&
|
|
996
1040
|
this._internalState !== "reconnecting"
|
|
997
1041
|
) {
|
|
998
|
-
|
|
1042
|
+
callback(
|
|
999
1043
|
new Error(
|
|
1000
1044
|
"performMessageTransaction: Invalid client state = " +
|
|
1001
1045
|
this._internalState +
|
|
@@ -1003,12 +1047,16 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1003
1047
|
request.schema.name
|
|
1004
1048
|
)
|
|
1005
1049
|
);
|
|
1050
|
+
return;
|
|
1006
1051
|
}
|
|
1007
1052
|
assert(this._secureChannel);
|
|
1008
1053
|
assert(request);
|
|
1009
1054
|
assert(request.requestHeader);
|
|
1010
1055
|
assert(typeof callback === "function");
|
|
1011
|
-
this._secureChannel.performMessageTransaction(
|
|
1056
|
+
this._secureChannel.performMessageTransaction(
|
|
1057
|
+
request,
|
|
1058
|
+
callback as unknown as PerformTransactionCallback
|
|
1059
|
+
);
|
|
1012
1060
|
}
|
|
1013
1061
|
|
|
1014
1062
|
/**
|
|
@@ -1054,9 +1102,13 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1054
1102
|
public async getEndpoints(options?: GetEndpointsOptions): Promise<EndpointDescription[]>;
|
|
1055
1103
|
public getEndpoints(options: GetEndpointsOptions, callback: ResponseCallback<EndpointDescription[]>): void;
|
|
1056
1104
|
public getEndpoints(callback: ResponseCallback<EndpointDescription[]>): void;
|
|
1057
|
-
public getEndpoints(...args:
|
|
1105
|
+
public getEndpoints(...args: unknown[]): Promise<EndpointDescription[]> | undefined {
|
|
1058
1106
|
if (args.length === 1) {
|
|
1059
|
-
|
|
1107
|
+
this.getEndpoints(
|
|
1108
|
+
{} as GetEndpointsOptions,
|
|
1109
|
+
args[0] as unknown as ResponseCallback<EndpointDescription[]>
|
|
1110
|
+
);
|
|
1111
|
+
return;
|
|
1060
1112
|
}
|
|
1061
1113
|
const options = args[0] as GetEndpointsOptions;
|
|
1062
1114
|
const callback = args[1] as ResponseCallback<EndpointDescription[]>;
|
|
@@ -1076,18 +1128,21 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1076
1128
|
|
|
1077
1129
|
this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
1078
1130
|
if (err) {
|
|
1079
|
-
|
|
1131
|
+
callback(err);
|
|
1132
|
+
return;
|
|
1080
1133
|
}
|
|
1081
1134
|
this._serverEndpoints = [];
|
|
1082
1135
|
// c8 ignore next
|
|
1083
1136
|
if (!response || !(response instanceof GetEndpointsResponse)) {
|
|
1084
|
-
|
|
1137
|
+
callback(new Error("Internal Error"));
|
|
1138
|
+
return;
|
|
1085
1139
|
}
|
|
1086
|
-
if (response
|
|
1140
|
+
if (response?.endpoints) {
|
|
1087
1141
|
this._serverEndpoints = response.endpoints;
|
|
1088
1142
|
}
|
|
1089
1143
|
callback(null, this._serverEndpoints);
|
|
1090
1144
|
});
|
|
1145
|
+
return;
|
|
1091
1146
|
}
|
|
1092
1147
|
|
|
1093
1148
|
/**
|
|
@@ -1095,18 +1150,33 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1095
1150
|
*/
|
|
1096
1151
|
public getEndpointsRequest(options: GetEndpointsOptions, callback: ResponseCallback<EndpointDescription[]>): void {
|
|
1097
1152
|
warningLog("note: ClientBaseImpl#getEndpointsRequest is deprecated, use ClientBaseImpl#getEndpoints instead");
|
|
1098
|
-
|
|
1153
|
+
this.getEndpoints(options, callback);
|
|
1099
1154
|
}
|
|
1100
1155
|
|
|
1101
1156
|
/**
|
|
1102
1157
|
|
|
1103
1158
|
*/
|
|
1104
|
-
public findServers(
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
public findServers(
|
|
1159
|
+
public findServers(
|
|
1160
|
+
options?: FindServersRequestLike
|
|
1161
|
+
): Promise<ApplicationDescription[]>;
|
|
1162
|
+
public findServers(
|
|
1163
|
+
options: FindServersRequestLike,
|
|
1164
|
+
callback: ResponseCallback<ApplicationDescription[]>
|
|
1165
|
+
): void;
|
|
1166
|
+
public findServers(
|
|
1167
|
+
callback: ResponseCallback<ApplicationDescription[]>
|
|
1168
|
+
): void;
|
|
1169
|
+
public findServers(
|
|
1170
|
+
...args: unknown[]
|
|
1171
|
+
): Promise<ApplicationDescription[]> | void {
|
|
1108
1172
|
if (args.length === 1) {
|
|
1109
|
-
|
|
1173
|
+
if (typeof args[0] === "function") {
|
|
1174
|
+
this.findServers(
|
|
1175
|
+
{} as FindServersRequestLike, args[0] as ResponseCallback<ApplicationDescription[]>);
|
|
1176
|
+
return void 0;
|
|
1177
|
+
} else {
|
|
1178
|
+
throw new Error("Invalid arguments");
|
|
1179
|
+
}
|
|
1110
1180
|
}
|
|
1111
1181
|
const options = args[0] as FindServersRequestLike;
|
|
1112
1182
|
const callback = args[1] as ResponseCallback<ApplicationDescription[]>;
|
|
@@ -1119,11 +1189,13 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1119
1189
|
|
|
1120
1190
|
this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
1121
1191
|
if (err) {
|
|
1122
|
-
|
|
1192
|
+
callback(err);
|
|
1193
|
+
return;
|
|
1123
1194
|
}
|
|
1124
1195
|
/* c8 ignore next */
|
|
1125
1196
|
if (!response || !(response instanceof FindServersResponse)) {
|
|
1126
|
-
|
|
1197
|
+
callback(new Error("Internal Error"));
|
|
1198
|
+
return;
|
|
1127
1199
|
}
|
|
1128
1200
|
response.servers = response.servers || [];
|
|
1129
1201
|
|
|
@@ -1134,9 +1206,13 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1134
1206
|
public findServersOnNetwork(options?: FindServersOnNetworkRequestLike): Promise<ServerOnNetwork[]>;
|
|
1135
1207
|
public findServersOnNetwork(callback: ResponseCallback<ServerOnNetwork[]>): void;
|
|
1136
1208
|
public findServersOnNetwork(options: FindServersOnNetworkRequestLike, callback: ResponseCallback<ServerOnNetwork[]>): void;
|
|
1137
|
-
public findServersOnNetwork(...args:
|
|
1209
|
+
public findServersOnNetwork(...args: unknown[]): Promise<ServerOnNetwork[]> | unknown {
|
|
1138
1210
|
if (args.length === 1) {
|
|
1139
|
-
|
|
1211
|
+
this.findServersOnNetwork(
|
|
1212
|
+
{} as FindServersOnNetworkRequestOptions,
|
|
1213
|
+
args[0] as ResponseCallback<ServerOnNetwork[]>
|
|
1214
|
+
);
|
|
1215
|
+
return;
|
|
1140
1216
|
}
|
|
1141
1217
|
const options = args[0] as FindServersOnNetworkRequestOptions;
|
|
1142
1218
|
const callback = args[1] as ResponseCallback<ServerOnNetwork[]>;
|
|
@@ -1144,21 +1220,24 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1144
1220
|
|
|
1145
1221
|
this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
1146
1222
|
if (err) {
|
|
1147
|
-
|
|
1223
|
+
callback(err);
|
|
1224
|
+
return;
|
|
1148
1225
|
}
|
|
1149
1226
|
/* c8 ignore next */
|
|
1150
1227
|
if (!response || !(response instanceof FindServersOnNetworkResponse)) {
|
|
1151
|
-
|
|
1228
|
+
callback(new Error("Internal Error"));
|
|
1229
|
+
return;
|
|
1152
1230
|
}
|
|
1153
1231
|
response.servers = response.servers || [];
|
|
1154
1232
|
callback(null, response.servers);
|
|
1155
1233
|
});
|
|
1234
|
+
return;
|
|
1156
1235
|
}
|
|
1157
1236
|
|
|
1158
1237
|
public _removeSession(session: ClientSessionImpl): void {
|
|
1159
1238
|
const index = this._sessions.indexOf(session);
|
|
1160
1239
|
if (index >= 0) {
|
|
1161
|
-
const
|
|
1240
|
+
const _s = this._sessions.splice(index, 1)[0];
|
|
1162
1241
|
// assert(s === session);
|
|
1163
1242
|
// assert(session._client === this);
|
|
1164
1243
|
session._client = null;
|
|
@@ -1183,7 +1262,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1183
1262
|
return callback(null);
|
|
1184
1263
|
}
|
|
1185
1264
|
|
|
1186
|
-
debugLog(chalk.bgWhite.green("_closeSession ") + this._secureChannel
|
|
1265
|
+
debugLog(chalk.bgWhite.green("_closeSession ") + this._secureChannel.channelId);
|
|
1187
1266
|
|
|
1188
1267
|
const request = new CloseSessionRequest({
|
|
1189
1268
|
deleteSubscriptions
|
|
@@ -1198,19 +1277,16 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1198
1277
|
});
|
|
1199
1278
|
}
|
|
1200
1279
|
|
|
1201
|
-
public closeSession(
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
const callback = args[2];
|
|
1205
|
-
|
|
1280
|
+
public closeSession(session: ClientSessionImpl, deleteSubscriptions: boolean): Promise<void>;
|
|
1281
|
+
public closeSession(session: ClientSessionImpl, deleteSubscriptions: boolean, callback: ErrorCallback): void;
|
|
1282
|
+
public closeSession(session: ClientSessionImpl, deleteSubscriptions: boolean, callback?: ErrorCallback): Promise<void> | void {
|
|
1206
1283
|
assert(typeof deleteSubscriptions === "boolean");
|
|
1207
|
-
assert(typeof callback === "function");
|
|
1208
1284
|
assert(session);
|
|
1209
1285
|
assert(session._client === this, "session must be attached to this");
|
|
1210
1286
|
session._closed = true;
|
|
1211
1287
|
|
|
1212
1288
|
// todo : send close session on secure channel
|
|
1213
|
-
this._closeSession(session, deleteSubscriptions, (err?: Error | null,
|
|
1289
|
+
this._closeSession(session, deleteSubscriptions, (err?: Error | null, _response?: CloseSessionResponse) => {
|
|
1214
1290
|
session.emitCloseEvent(StatusCodes.Good);
|
|
1215
1291
|
|
|
1216
1292
|
this._removeSession(session);
|
|
@@ -1219,34 +1295,38 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1219
1295
|
assert(this._sessions.indexOf(session) === -1);
|
|
1220
1296
|
assert(session._closed, "session must indicate it is closed");
|
|
1221
1297
|
|
|
1222
|
-
callback(err ? err : undefined);
|
|
1298
|
+
callback?.(err ? err : undefined);
|
|
1223
1299
|
});
|
|
1224
1300
|
}
|
|
1225
1301
|
|
|
1226
1302
|
public disconnect(): Promise<void>;
|
|
1227
1303
|
public disconnect(callback: ErrorCallback): void;
|
|
1228
1304
|
// eslint-disable-next-line max-statements
|
|
1229
|
-
public disconnect(...args:
|
|
1230
|
-
const callback = args[0];
|
|
1305
|
+
public disconnect(...args: unknown[]): undefined | Promise<void> {
|
|
1306
|
+
const callback = args[0] as ErrorCallback;
|
|
1231
1307
|
assert(typeof callback === "function", "expecting a callback function here");
|
|
1232
1308
|
this._reconnectionIsCanceled = true;
|
|
1233
1309
|
if (this._tmpClient) {
|
|
1234
1310
|
warningLog("disconnecting client while tmpClient exists", this._tmpClient.clientName);
|
|
1235
|
-
this._tmpClient.disconnect((
|
|
1311
|
+
this._tmpClient.disconnect((_err) => {
|
|
1236
1312
|
this._tmpClient = undefined;
|
|
1237
1313
|
// retry disconnect on main client
|
|
1238
1314
|
this.disconnect(callback);
|
|
1239
1315
|
});
|
|
1240
|
-
return;
|
|
1316
|
+
return undefined;
|
|
1241
1317
|
}
|
|
1242
1318
|
if (this._internalState === "disconnected" || this._internalState === "disconnecting") {
|
|
1243
1319
|
if (this._internalState === "disconnecting") {
|
|
1244
|
-
warningLog(
|
|
1320
|
+
warningLog(
|
|
1321
|
+
"[NODE-OPCUA-W26] OPCUAClient#disconnect called while already disconnecting. clientName=",
|
|
1322
|
+
this.clientName
|
|
1323
|
+
);
|
|
1245
1324
|
}
|
|
1246
1325
|
if (!this._reconnectionIsCanceled && this.isReconnecting) {
|
|
1247
1326
|
errorLog("Internal Error : _reconnectionIsCanceled should be true if isReconnecting is true");
|
|
1248
1327
|
}
|
|
1249
|
-
|
|
1328
|
+
callback();
|
|
1329
|
+
return undefined;
|
|
1250
1330
|
}
|
|
1251
1331
|
debugLog("disconnecting client! (will set reconnectionIsCanceled to true");
|
|
1252
1332
|
this._reconnectionIsCanceled = true;
|
|
@@ -1262,7 +1342,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1262
1342
|
// sessions cannot be cancelled properly and must be discarded.
|
|
1263
1343
|
this.disconnect(callback);
|
|
1264
1344
|
});
|
|
1265
|
-
return;
|
|
1345
|
+
return undefined;
|
|
1266
1346
|
}
|
|
1267
1347
|
|
|
1268
1348
|
if (this._sessions.length && !this.keepPendingSessionsOnDisconnect) {
|
|
@@ -1272,7 +1352,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1272
1352
|
this._close_pending_sessions((/*err*/) => {
|
|
1273
1353
|
this.disconnect(callback);
|
|
1274
1354
|
});
|
|
1275
|
-
return;
|
|
1355
|
+
return undefined;
|
|
1276
1356
|
}
|
|
1277
1357
|
|
|
1278
1358
|
debugLog("Disconnecting !");
|
|
@@ -1302,7 +1382,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1302
1382
|
}
|
|
1303
1383
|
|
|
1304
1384
|
if (this._secureChannel) {
|
|
1305
|
-
let tmpChannel:
|
|
1385
|
+
let tmpChannel: ClientSecureChannelLayer | null = this._secureChannel;
|
|
1306
1386
|
this._secureChannel = null;
|
|
1307
1387
|
debugLog("Closing channel");
|
|
1308
1388
|
tmpChannel.close(() => {
|
|
@@ -1317,6 +1397,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1317
1397
|
// this.emit("close", null);
|
|
1318
1398
|
callback();
|
|
1319
1399
|
}
|
|
1400
|
+
return undefined;
|
|
1320
1401
|
}
|
|
1321
1402
|
|
|
1322
1403
|
// override me !
|
|
@@ -1326,36 +1407,34 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1326
1407
|
|
|
1327
1408
|
public toString(): string {
|
|
1328
1409
|
let str = "\n";
|
|
1329
|
-
str +=
|
|
1330
|
-
str +=
|
|
1331
|
-
str +=
|
|
1332
|
-
str +=
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
(this.serverCertificate ? makeSHA1Thumbprint(this.serverCertificate).toString("hex") : "") +
|
|
1336
|
-
"\n";
|
|
1410
|
+
str += ` defaultSecureTokenLifetime.... ${this.defaultSecureTokenLifetime}\n`;
|
|
1411
|
+
str += ` securityMode.................. ${MessageSecurityMode[this.securityMode]}\n`;
|
|
1412
|
+
str += ` securityPolicy................ ${this.securityPolicy.toString()}\n`;
|
|
1413
|
+
str += ` certificate fingerprint....... ${makeCertificateThumbPrint(this.getCertificate())?.toString("hex") || "none"}\n`;
|
|
1414
|
+
|
|
1415
|
+
str += ` server certificate fingerprint ${makeCertificateThumbPrint(this.serverCertificate)?.toString("hex") || "none"}\n`;
|
|
1337
1416
|
// this.serverCertificate = options.serverCertificate || null + "\n";
|
|
1338
|
-
str +=
|
|
1339
|
-
str +=
|
|
1340
|
-
str +=
|
|
1341
|
-
str +=
|
|
1342
|
-
str +=
|
|
1417
|
+
str += ` keepSessionAlive.............. ${this.keepSessionAlive}\n`;
|
|
1418
|
+
str += ` bytesRead..................... ${this.bytesRead}\n`;
|
|
1419
|
+
str += ` bytesWritten.................. ${this.bytesWritten}\n`;
|
|
1420
|
+
str += ` transactionsPerformed......... ${this.transactionsPerformed}\n`;
|
|
1421
|
+
str += ` timedOutRequestCount.......... ${this.timedOutRequestCount}\n`;
|
|
1343
1422
|
str += " connectionStrategy." + "\n";
|
|
1344
|
-
str +=
|
|
1345
|
-
str +=
|
|
1346
|
-
str +=
|
|
1347
|
-
str +=
|
|
1348
|
-
str +=
|
|
1349
|
-
str +=
|
|
1350
|
-
str +=
|
|
1351
|
-
str +=
|
|
1352
|
-
str +=
|
|
1353
|
-
str +=
|
|
1354
|
-
str +=
|
|
1355
|
-
str +=
|
|
1423
|
+
str += ` .maxRetry............... ${this.connectionStrategy.maxRetry}\n`;
|
|
1424
|
+
str += ` .initialDelay........... ${this.connectionStrategy.initialDelay}\n`;
|
|
1425
|
+
str += ` .maxDelay............... ${this.connectionStrategy.maxDelay}\n`;
|
|
1426
|
+
str += ` .randomisationFactor.... ${this.connectionStrategy.randomisationFactor}\n`;
|
|
1427
|
+
str += ` keepSessionAlive.............. ${this.keepSessionAlive}\n`;
|
|
1428
|
+
str += ` applicationName............... ${this.applicationName}\n`;
|
|
1429
|
+
str += ` applicationUri................ ${this._getBuiltApplicationUri()}\n`;
|
|
1430
|
+
str += ` clientName.................... ${this.clientName}\n`;
|
|
1431
|
+
str += ` reconnectOnFailure............ ${this.reconnectOnFailure}\n`;
|
|
1432
|
+
str += ` isReconnecting................ ${this.isReconnecting}\n`;
|
|
1433
|
+
str += ` (internal state).............. ${this._internalState}\n`;
|
|
1434
|
+
str += ` sessions count................ ${this.getSessions().length}\n`;
|
|
1356
1435
|
|
|
1357
1436
|
if (this._secureChannel) {
|
|
1358
|
-
str +=
|
|
1437
|
+
str += `secureChannel:\n${this._secureChannel.toString()}`;
|
|
1359
1438
|
}
|
|
1360
1439
|
return str;
|
|
1361
1440
|
}
|
|
@@ -1365,7 +1444,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1365
1444
|
}
|
|
1366
1445
|
|
|
1367
1446
|
public getTransportSettings(): IBasicTransportSettings {
|
|
1368
|
-
return this._secureChannel
|
|
1447
|
+
return this._secureChannel?.getTransportSettings() || ({} as IBasicTransportSettings);
|
|
1369
1448
|
}
|
|
1370
1449
|
|
|
1371
1450
|
protected _addSession(session: ClientSessionImpl): void {
|
|
@@ -1412,15 +1491,17 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1412
1491
|
|
|
1413
1492
|
clientCertificateManager: this.clientCertificateManager
|
|
1414
1493
|
};
|
|
1415
|
-
|
|
1494
|
+
__findEndpoint.call(this, discoveryUrl, params, (err: Error | null, result?: FindEndpointResult) => {
|
|
1416
1495
|
if (err) {
|
|
1417
|
-
|
|
1496
|
+
callback(err);
|
|
1497
|
+
return;
|
|
1418
1498
|
}
|
|
1419
1499
|
|
|
1420
1500
|
// c8 ignore next
|
|
1421
1501
|
if (!result) {
|
|
1422
1502
|
const err1 = new Error("internal error");
|
|
1423
|
-
|
|
1503
|
+
callback(err1);
|
|
1504
|
+
return;
|
|
1424
1505
|
}
|
|
1425
1506
|
|
|
1426
1507
|
const endpoint = result.selectedEndpoint;
|
|
@@ -1432,7 +1513,8 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1432
1513
|
" policy = " +
|
|
1433
1514
|
this.securityPolicy
|
|
1434
1515
|
);
|
|
1435
|
-
|
|
1516
|
+
callback(err1);
|
|
1517
|
+
return;
|
|
1436
1518
|
}
|
|
1437
1519
|
|
|
1438
1520
|
assert(endpoint);
|
|
@@ -1440,20 +1522,20 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1440
1522
|
_verify_serverCertificate(this.clientCertificateManager, endpoint.serverCertificate)
|
|
1441
1523
|
.then(() => {
|
|
1442
1524
|
this.serverCertificate = endpoint.serverCertificate;
|
|
1443
|
-
callback(null, endpoint.endpointUrl
|
|
1525
|
+
callback(null, endpoint.endpointUrl || "");
|
|
1444
1526
|
})
|
|
1445
1527
|
.catch((err1: Error) => {
|
|
1446
1528
|
warningLog("[NODE-OPCUA-W25] client's server certificate verification has failed ", err1.message);
|
|
1447
1529
|
warningLog(" clientCertificateManager.rootDir = ", this.clientCertificateManager.rootDir);
|
|
1448
1530
|
|
|
1449
1531
|
const f = (b: Buffer) =>
|
|
1450
|
-
|
|
1532
|
+
` ${b.toString("base64").replace(/(.{80})/g, "$1\n ")}`;
|
|
1451
1533
|
|
|
1452
1534
|
const chain = split_der(endpoint.serverCertificate);
|
|
1453
1535
|
warningLog(` server certificate contains ${chain.length} elements`);
|
|
1454
1536
|
for (let i = 0; i < chain.length; i++) {
|
|
1455
1537
|
const c = chain[i];
|
|
1456
|
-
warningLog("certificate", i,
|
|
1538
|
+
warningLog("certificate", i, `\n${f(c)}`);
|
|
1457
1539
|
}
|
|
1458
1540
|
if (chain.length > 1) {
|
|
1459
1541
|
warningLog(
|
|
@@ -1466,7 +1548,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1466
1548
|
" verify that the server certificate is trusted or that server certificate issuer's certificate is present in the issuer folder"
|
|
1467
1549
|
);
|
|
1468
1550
|
}
|
|
1469
|
-
|
|
1551
|
+
callback(err1);
|
|
1470
1552
|
});
|
|
1471
1553
|
});
|
|
1472
1554
|
}
|
|
@@ -1525,7 +1607,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1525
1607
|
// in a attempt to preserve resources in the case of a DDOS attack for instance.
|
|
1526
1608
|
if (err) {
|
|
1527
1609
|
const msg = session.authenticationToken ? session.authenticationToken.toString() : "";
|
|
1528
|
-
debugLog(
|
|
1610
|
+
debugLog(` failing to close session ${msg}`);
|
|
1529
1611
|
}
|
|
1530
1612
|
next();
|
|
1531
1613
|
});
|
|
@@ -1540,7 +1622,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1540
1622
|
);
|
|
1541
1623
|
}
|
|
1542
1624
|
assert(this._sessions.length === 0, " failed to disconnect exiting sessions ");
|
|
1543
|
-
callback(err
|
|
1625
|
+
callback(err || undefined);
|
|
1544
1626
|
}
|
|
1545
1627
|
);
|
|
1546
1628
|
}
|
|
@@ -1572,7 +1654,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1572
1654
|
* @event send_request
|
|
1573
1655
|
* @param message
|
|
1574
1656
|
*/
|
|
1575
|
-
this.emit("send_request", message);
|
|
1657
|
+
this.emit("send_request", message as unknown as Request);
|
|
1576
1658
|
});
|
|
1577
1659
|
|
|
1578
1660
|
secureChannel.on("receive_response", (message: Response1) => {
|
|
@@ -1581,7 +1663,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1581
1663
|
* @event receive_response
|
|
1582
1664
|
* @param message
|
|
1583
1665
|
*/
|
|
1584
|
-
this.emit("receive_response", message);
|
|
1666
|
+
this.emit("receive_response", message as unknown as Response);
|
|
1585
1667
|
});
|
|
1586
1668
|
|
|
1587
1669
|
secureChannel.on("lifetime_75", (token: ChannelSecurityToken) => {
|
|
@@ -1594,7 +1676,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1594
1676
|
" is about to expired , it's time to request a new token"
|
|
1595
1677
|
);
|
|
1596
1678
|
// forward message to upper level
|
|
1597
|
-
this.emit("lifetime_75", token
|
|
1679
|
+
this.emit("lifetime_75", token);
|
|
1598
1680
|
});
|
|
1599
1681
|
|
|
1600
1682
|
secureChannel.on("security_token_renewed", (token: ChannelSecurityToken) => {
|
|
@@ -1613,7 +1695,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1613
1695
|
/**
|
|
1614
1696
|
* @event connection_lost
|
|
1615
1697
|
*/
|
|
1616
|
-
this.emit("connection_lost"
|
|
1698
|
+
this.emit("connection_lost"); // instead of "close"
|
|
1617
1699
|
}
|
|
1618
1700
|
// this is a normal close operation initiated by us
|
|
1619
1701
|
this.emit("close", err); // instead of "close"
|
|
@@ -1628,7 +1710,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1628
1710
|
/**
|
|
1629
1711
|
* @event connection_lost
|
|
1630
1712
|
*/
|
|
1631
|
-
this.emit("connection_lost"
|
|
1713
|
+
this.emit("connection_lost"); // instead of "close"
|
|
1632
1714
|
this._repairConnection();
|
|
1633
1715
|
}
|
|
1634
1716
|
}
|
|
@@ -1640,7 +1722,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1640
1722
|
* @event timed_out_request
|
|
1641
1723
|
* @param request
|
|
1642
1724
|
*/
|
|
1643
|
-
this.emit("timed_out_request", request);
|
|
1725
|
+
this.emit("timed_out_request", request as unknown as Request);
|
|
1644
1726
|
});
|
|
1645
1727
|
}
|
|
1646
1728
|
|
|
@@ -1676,7 +1758,12 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1676
1758
|
|
|
1677
1759
|
debugLog("Entering _repairConnection ", this._internalState);
|
|
1678
1760
|
if (this.#insideRepairConnection) {
|
|
1679
|
-
errorLog(
|
|
1761
|
+
errorLog(
|
|
1762
|
+
"_repairConnection already in progress internal state = ",
|
|
1763
|
+
this._internalState,
|
|
1764
|
+
"clientName =",
|
|
1765
|
+
this.clientName
|
|
1766
|
+
);
|
|
1680
1767
|
this.#shouldRepairAgain = true;
|
|
1681
1768
|
return;
|
|
1682
1769
|
}
|
|
@@ -1748,15 +1835,15 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1748
1835
|
* @private
|
|
1749
1836
|
*/
|
|
1750
1837
|
public __createSession_step2(
|
|
1751
|
-
|
|
1752
|
-
|
|
1838
|
+
_session: ClientSessionImpl,
|
|
1839
|
+
_callback: (err: Error | null, session?: ClientSessionImpl) => void
|
|
1753
1840
|
): void {
|
|
1754
1841
|
throw new Error("Please override");
|
|
1755
1842
|
}
|
|
1756
1843
|
public _activateSession(
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1844
|
+
_session: ClientSessionImpl,
|
|
1845
|
+
_userIdentity: UserIdentityInfo,
|
|
1846
|
+
_callback: (err: Error | null, session?: ClientSessionImpl) => void
|
|
1760
1847
|
): void {
|
|
1761
1848
|
throw new Error("Please override");
|
|
1762
1849
|
}
|
|
@@ -1765,27 +1852,29 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
|
|
|
1765
1852
|
// tslint:disable-next-line: max-classes-per-file
|
|
1766
1853
|
class TmpClient extends ClientBaseImpl {
|
|
1767
1854
|
constructor(options: OPCUAClientBaseOptions) {
|
|
1768
|
-
options.clientName =
|
|
1855
|
+
options.clientName = `${options.clientName || ""}_TmpClient`;
|
|
1769
1856
|
super(options);
|
|
1770
1857
|
}
|
|
1771
1858
|
|
|
1772
1859
|
async connect(endpoint: string): Promise<void>;
|
|
1773
1860
|
connect(endpoint: string, callback: ErrorCallback): void;
|
|
1774
|
-
connect(endpoint: string, callback?: ErrorCallback):
|
|
1861
|
+
connect(endpoint: string, callback?: ErrorCallback): Promise<void> | void {
|
|
1775
1862
|
debugLog("connecting to TmpClient");
|
|
1776
1863
|
|
|
1777
1864
|
// c8 ignore next
|
|
1778
1865
|
if (this._internalState !== "disconnected") {
|
|
1779
|
-
callback
|
|
1866
|
+
callback?.(
|
|
1867
|
+
new Error(`TmpClient#connect: invalid internal state = ${this._internalState}`));
|
|
1780
1868
|
return;
|
|
1781
1869
|
}
|
|
1782
1870
|
|
|
1783
1871
|
this._setInternalState("connecting");
|
|
1784
1872
|
this._connectStep2(endpoint, (err?: Error) => {
|
|
1785
1873
|
if (this.isUnusable()) {
|
|
1786
|
-
|
|
1874
|
+
this._handleUnrecoverableConnectionFailure(new Error("premature disconnection 4"), callback || (() => { }));
|
|
1875
|
+
return;
|
|
1787
1876
|
}
|
|
1788
|
-
callback
|
|
1877
|
+
callback?.(err);
|
|
1789
1878
|
});
|
|
1790
1879
|
}
|
|
1791
1880
|
}
|
|
@@ -1793,6 +1882,7 @@ class TmpClient extends ClientBaseImpl {
|
|
|
1793
1882
|
// tslint:disable:no-var-requires
|
|
1794
1883
|
// tslint:disable:max-line-length
|
|
1795
1884
|
import { withCallback } from "thenify-ex";
|
|
1885
|
+
|
|
1796
1886
|
ClientBaseImpl.prototype.connect = withCallback(ClientBaseImpl.prototype.connect);
|
|
1797
1887
|
ClientBaseImpl.prototype.disconnect = withCallback(ClientBaseImpl.prototype.disconnect);
|
|
1798
1888
|
ClientBaseImpl.prototype.getEndpoints = withCallback(ClientBaseImpl.prototype.getEndpoints);
|