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
|
@@ -1,28 +1,41 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module node-opcua-client-private
|
|
3
3
|
*/
|
|
4
|
-
|
|
5
|
-
import {
|
|
4
|
+
|
|
5
|
+
import { createPublicKey, randomBytes } from "node:crypto";
|
|
6
|
+
import { callbackify } from "node:util";
|
|
6
7
|
import chalk from "chalk";
|
|
7
8
|
|
|
8
9
|
import { assert } from "node-opcua-assert";
|
|
9
10
|
import { createFastUninitializedBuffer } from "node-opcua-buffer-utils";
|
|
11
|
+
import { DataTypeExtractStrategy } from "node-opcua-client-dynamic-extension-object";
|
|
10
12
|
import {
|
|
11
|
-
Certificate,
|
|
13
|
+
type Certificate,
|
|
12
14
|
exploreCertificate,
|
|
13
15
|
extractPublicKeyFromCertificateSync,
|
|
14
16
|
makePrivateKeyFromPem,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
type Nonce,
|
|
18
|
+
type PrivateKey,
|
|
17
19
|
toPem
|
|
18
20
|
} from "node-opcua-crypto/web";
|
|
19
|
-
|
|
20
21
|
import { LocalizedText } from "node-opcua-data-model";
|
|
21
22
|
import { checkDebugFlag, make_debugLog, make_errorLog, make_warningLog } from "node-opcua-debug";
|
|
22
23
|
import { extractFullyQualifiedDomainName } from "node-opcua-hostname";
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
|
|
24
|
+
import { readNamespaceArray } from "node-opcua-pseudo-session";
|
|
25
|
+
import {
|
|
26
|
+
type ClientSecureChannelLayer,
|
|
27
|
+
computeSignature,
|
|
28
|
+
fromURI,
|
|
29
|
+
getCryptoFactory,
|
|
30
|
+
SecurityPolicy
|
|
31
|
+
} from "node-opcua-secure-channel";
|
|
32
|
+
import {
|
|
33
|
+
type ApplicationDescriptionOptions,
|
|
34
|
+
ApplicationType,
|
|
35
|
+
EndpointDescription,
|
|
36
|
+
UserTokenType
|
|
37
|
+
} from "node-opcua-service-endpoints";
|
|
38
|
+
import { MessageSecurityMode, type UserTokenPolicy } from "node-opcua-service-secure-channel";
|
|
26
39
|
import {
|
|
27
40
|
ActivateSessionRequest,
|
|
28
41
|
ActivateSessionResponse,
|
|
@@ -32,30 +45,26 @@ import {
|
|
|
32
45
|
UserNameIdentityToken,
|
|
33
46
|
X509IdentityToken
|
|
34
47
|
} from "node-opcua-service-session";
|
|
35
|
-
import { CallbackT, StatusCode, StatusCodes } from "node-opcua-status-code";
|
|
36
|
-
import {
|
|
37
|
-
|
|
38
|
-
import { SignatureDataOptions, UserIdentityToken } from "node-opcua-types";
|
|
48
|
+
import { type Callback, type CallbackT, type StatusCode, StatusCodes } from "node-opcua-status-code";
|
|
49
|
+
import type { SignatureDataOptions, UserIdentityToken } from "node-opcua-types";
|
|
39
50
|
import { isNullOrUndefined, matchUri } from "node-opcua-utils";
|
|
40
|
-
import {
|
|
41
|
-
|
|
42
|
-
import { ClientSession } from "../client_session";
|
|
43
|
-
import {
|
|
44
|
-
import { Response } from "../common";
|
|
51
|
+
import type { NodeId } from "node-opcua-nodeid";
|
|
52
|
+
import type { OPCUAClientBaseEvents } from "../client_base";
|
|
53
|
+
import type { ClientSession } from "../client_session";
|
|
54
|
+
import type { ClientSubscriptionOptions } from "../client_subscription";
|
|
55
|
+
import type { Response } from "../common";
|
|
45
56
|
import {
|
|
57
|
+
type EndpointWithUserIdentity,
|
|
46
58
|
OPCUAClient,
|
|
47
|
-
OPCUAClientOptions,
|
|
48
|
-
WithSessionFuncP,
|
|
49
|
-
WithSubscriptionFuncP
|
|
50
|
-
EndpointWithUserIdentity
|
|
59
|
+
type OPCUAClientOptions,
|
|
60
|
+
type WithSessionFuncP,
|
|
61
|
+
type WithSubscriptionFuncP
|
|
51
62
|
} from "../opcua_client";
|
|
52
|
-
import { AnonymousIdentity, UserIdentityInfo, UserIdentityInfoUserName, UserIdentityInfoX509 } from "../user_identity_info";
|
|
53
|
-
|
|
54
|
-
import { repair_client_sessions } from "./reconnection/reconnection";
|
|
63
|
+
import type { AnonymousIdentity, UserIdentityInfo, UserIdentityInfoUserName, UserIdentityInfoX509 } from "../user_identity_info";
|
|
55
64
|
import { ClientBaseImpl } from "./client_base_impl";
|
|
56
65
|
import { ClientSessionImpl } from "./client_session_impl";
|
|
57
|
-
import { IClientBase } from "./i_private_client";
|
|
58
|
-
import {
|
|
66
|
+
import type { IClientBase } from "./i_private_client";
|
|
67
|
+
import { repair_client_sessions } from "./reconnection/reconnection";
|
|
59
68
|
|
|
60
69
|
interface TokenAndSignature {
|
|
61
70
|
userIdentityToken: UserIdentityToken | null;
|
|
@@ -71,7 +80,7 @@ function validateServerNonce(serverNonce: Nonce | null): boolean {
|
|
|
71
80
|
return !(serverNonce && serverNonce.length < 32) || (serverNonce && serverNonce.length === 0);
|
|
72
81
|
}
|
|
73
82
|
|
|
74
|
-
function verifyEndpointDescriptionMatches(
|
|
83
|
+
function verifyEndpointDescriptionMatches(_client: OPCUAClientImpl, _responseServerEndpoints: EndpointDescription[]): boolean {
|
|
75
84
|
// The Server returns its EndpointDescriptions in the response. Clients use this information to
|
|
76
85
|
// determine whether the list of EndpointDescriptions returned from the Discovery Endpoint matches
|
|
77
86
|
// the Endpoints that the Server has. If there is a difference then the Client shall close the
|
|
@@ -108,8 +117,6 @@ const ordered: string[] = [
|
|
|
108
117
|
SecurityPolicy.Basic256Rsa15,
|
|
109
118
|
SecurityPolicy.Basic256Sha256,
|
|
110
119
|
|
|
111
|
-
|
|
112
|
-
|
|
113
120
|
SecurityPolicy.Aes128_Sha256_RsaOaep,
|
|
114
121
|
SecurityPolicy.Aes256_Sha256_RsaPss
|
|
115
122
|
];
|
|
@@ -120,8 +127,8 @@ const _compareSecurityPolicy = (a: string | null, b: string | null) => {
|
|
|
120
127
|
}
|
|
121
128
|
if (!a && b) return 1;
|
|
122
129
|
if (a && !b) return -1;
|
|
123
|
-
const rankA = ordered.indexOf(a
|
|
124
|
-
const rankB = ordered.indexOf(b
|
|
130
|
+
const rankA = ordered.indexOf(a as string);
|
|
131
|
+
const rankB = ordered.indexOf(b as string);
|
|
125
132
|
return rankB - rankA;
|
|
126
133
|
};
|
|
127
134
|
const compareSecurityPolicy = (a: UserTokenPolicy, b: UserTokenPolicy) => {
|
|
@@ -254,7 +261,7 @@ function createX509IdentityToken(
|
|
|
254
261
|
// The data to sign is created by appending the last serverNonce to the serverCertificate
|
|
255
262
|
|
|
256
263
|
// The signature generated with private key associated with the User Certificate
|
|
257
|
-
const userTokenSignature
|
|
264
|
+
const userTokenSignature = computeSignature(serverCertificate, serverNonce, privateKey, securityPolicy) as SignatureDataOptions;
|
|
258
265
|
|
|
259
266
|
return { userIdentityToken, userTokenSignature };
|
|
260
267
|
}
|
|
@@ -292,14 +299,14 @@ function createUserNameIdentityToken(
|
|
|
292
299
|
securityPolicy = session.securityPolicy;
|
|
293
300
|
}
|
|
294
301
|
|
|
295
|
-
let identityToken;
|
|
302
|
+
let identityToken: UserNameIdentityToken;
|
|
296
303
|
let serverCertificate: Buffer | string | null = session.serverCertificate;
|
|
297
304
|
// if server does not provide certificate use unencrypted password
|
|
298
305
|
if (!serverCertificate || serverCertificate.length === 0) {
|
|
299
306
|
identityToken = new UserNameIdentityToken({
|
|
300
307
|
encryptionAlgorithm: null,
|
|
301
308
|
password: Buffer.from(password as string, "utf-8"),
|
|
302
|
-
policyId: userTokenPolicy
|
|
309
|
+
policyId: userTokenPolicy.policyId,
|
|
303
310
|
userName
|
|
304
311
|
});
|
|
305
312
|
return identityToken;
|
|
@@ -321,7 +328,7 @@ function createUserNameIdentityToken(
|
|
|
321
328
|
if (securityPolicy === SecurityPolicy.None) {
|
|
322
329
|
identityToken = new UserNameIdentityToken({
|
|
323
330
|
encryptionAlgorithm: null,
|
|
324
|
-
password: Buffer.from(password
|
|
331
|
+
password: Buffer.from(password as string, "utf-8"),
|
|
325
332
|
policyId: userTokenPolicy.policyId,
|
|
326
333
|
userName
|
|
327
334
|
});
|
|
@@ -333,7 +340,7 @@ function createUserNameIdentityToken(
|
|
|
333
340
|
|
|
334
341
|
// c8 ignore next
|
|
335
342
|
if (!cryptoFactory) {
|
|
336
|
-
throw new Error(
|
|
343
|
+
throw new Error(` Unsupported security Policy ${securityPolicy.toString()}`);
|
|
337
344
|
}
|
|
338
345
|
|
|
339
346
|
identityToken = new UserNameIdentityToken({
|
|
@@ -371,7 +378,7 @@ function _adjustRevisedSessionTimeout(revisedSessionTimeout: number, requestedTi
|
|
|
371
378
|
return revisedSessionTimeout;
|
|
372
379
|
}
|
|
373
380
|
|
|
374
|
-
export class OPCUAClientImpl extends ClientBaseImpl
|
|
381
|
+
export class OPCUAClientImpl extends ClientBaseImpl<OPCUAClientBaseEvents> {
|
|
375
382
|
public static minimumRevisedSessionTimeout = 100.0;
|
|
376
383
|
private _retryCreateSessionTimer?: NodeJS.Timeout;
|
|
377
384
|
|
|
@@ -399,8 +406,8 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
399
406
|
// if set to true , create Session will only accept connection from server which endpoint_url has been reported
|
|
400
407
|
// by GetEndpointsRequest.
|
|
401
408
|
// By default, the client is strict.
|
|
402
|
-
if (Object.
|
|
403
|
-
if (Object.
|
|
409
|
+
if (Object.hasOwn(options, "endpoint_must_exist")) {
|
|
410
|
+
if (Object.hasOwn(options, "endpointMustExist")) {
|
|
404
411
|
throw new Error(
|
|
405
412
|
"endpoint_must_exist is deprecated! you must now use endpointMustExist instead of endpoint_must_exist "
|
|
406
413
|
);
|
|
@@ -441,6 +448,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
441
448
|
* @param args
|
|
442
449
|
*
|
|
443
450
|
*/
|
|
451
|
+
// biome-ignore lint/suspicious/noExplicitAny: overload implementation
|
|
444
452
|
public createSession(...args: any[]): any {
|
|
445
453
|
if (args.length === 1) {
|
|
446
454
|
return this.createSession({ type: UserTokenType.Anonymous }, args[0]);
|
|
@@ -465,14 +473,16 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
465
473
|
session as ClientSessionImpl,
|
|
466
474
|
userIdentityInfo,
|
|
467
475
|
(err1: Error | null, session2?: ClientSessionImpl) => {
|
|
468
|
-
|
|
469
476
|
if (err1) {
|
|
470
|
-
session
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
477
|
+
session
|
|
478
|
+
.close(true)
|
|
479
|
+
.then(() => {
|
|
480
|
+
callback(err1, null);
|
|
481
|
+
})
|
|
482
|
+
.catch((err2) => {
|
|
483
|
+
err2;
|
|
484
|
+
callback(err1, null);
|
|
485
|
+
});
|
|
476
486
|
} else {
|
|
477
487
|
callback(null, session2);
|
|
478
488
|
}
|
|
@@ -494,6 +504,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
494
504
|
public async createSession2(userIdentityInfo?: UserIdentityInfo): Promise<ClientSession>;
|
|
495
505
|
public createSession2(userIdentityInfo: UserIdentityInfo, callback: Callback<ClientSession>): void;
|
|
496
506
|
public createSession2(callback: Callback<ClientSession>): void;
|
|
507
|
+
// biome-ignore lint/suspicious/noExplicitAny: overload implementation
|
|
497
508
|
public createSession2(...args: any[]): any {
|
|
498
509
|
if (args.length === 1) {
|
|
499
510
|
return this.createSession2({ type: UserTokenType.Anonymous }, args[0]);
|
|
@@ -508,7 +519,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
508
519
|
return callback(new Error(`disconnecting`));
|
|
509
520
|
}
|
|
510
521
|
return this.createSession(args[0], (err: Error | null, session?: ClientSession) => {
|
|
511
|
-
if (err
|
|
522
|
+
if (err?.message.match(/BadTooManySessions/)) {
|
|
512
523
|
const delayToRetry = 5; // seconds
|
|
513
524
|
errorLog(`TooManySession .... we need to retry later ... in ${delayToRetry} secondes ${this._internalState}`);
|
|
514
525
|
this._retryCreateSessionTimer = setTimeout(() => {
|
|
@@ -526,6 +537,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
526
537
|
*/
|
|
527
538
|
public async changeSessionIdentity(session: ClientSession, userIdentityInfo: UserIdentityInfo): Promise<StatusCode>;
|
|
528
539
|
public changeSessionIdentity(session: ClientSession, userIdentityInfo: UserIdentityInfo, callback: CallbackT<StatusCode>): void;
|
|
540
|
+
// biome-ignore lint/suspicious/noExplicitAny: overload implementation
|
|
529
541
|
public changeSessionIdentity(...args: any[]): any {
|
|
530
542
|
warningLog(
|
|
531
543
|
"[NODE-OPCUA-W34] OPCUAClient.changeSessionIdentity(session,userIdentity) is deprecated use ClientSession.changeUser(userIdentity) instead"
|
|
@@ -538,27 +550,31 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
538
550
|
}
|
|
539
551
|
|
|
540
552
|
/**
|
|
541
|
-
* close a session
|
|
553
|
+
* close a session, internal
|
|
542
554
|
*/
|
|
543
555
|
public closeSession(session: ClientSession, deleteSubscriptions: boolean): Promise<void>;
|
|
544
556
|
public closeSession(session: ClientSession, deleteSubscriptions: boolean, callback: (err?: Error) => void): void;
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
557
|
+
public closeSession(
|
|
558
|
+
session: ClientSession,
|
|
559
|
+
deleteSubscriptions: boolean,
|
|
560
|
+
callback?: (err?: Error) => void
|
|
561
|
+
): Promise<void> | void {
|
|
550
562
|
if (this._retryCreateSessionTimer) {
|
|
551
563
|
clearTimeout(this._retryCreateSessionTimer);
|
|
552
564
|
this._retryCreateSessionTimer = undefined;
|
|
553
565
|
}
|
|
554
|
-
super.closeSession(
|
|
566
|
+
super.closeSession(
|
|
567
|
+
session as unknown as ClientSessionImpl,
|
|
568
|
+
deleteSubscriptions,
|
|
569
|
+
callback as (err?: Error) => void
|
|
570
|
+
);
|
|
555
571
|
}
|
|
556
572
|
|
|
557
573
|
public toString(): string {
|
|
558
574
|
let str = ClientBaseImpl.prototype.toString.call(this);
|
|
559
|
-
str +=
|
|
560
|
-
str +=
|
|
561
|
-
str +=
|
|
575
|
+
str += ` requestedSessionTimeout....... ${this.requestedSessionTimeout}\n`;
|
|
576
|
+
str += ` endpointUrl................... ${this.endpointUrl}\n`;
|
|
577
|
+
str += ` serverUri..................... ${this.serverUri}\n`;
|
|
562
578
|
return str;
|
|
563
579
|
}
|
|
564
580
|
|
|
@@ -582,6 +598,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
582
598
|
*
|
|
583
599
|
* const create
|
|
584
600
|
*/
|
|
601
|
+
// biome-ignore lint/suspicious/useAdjacentOverloadSignatures: static vs instance method
|
|
585
602
|
public static async createSession(
|
|
586
603
|
endpointUrl: string,
|
|
587
604
|
userIdentity?: UserIdentityInfo,
|
|
@@ -592,7 +609,9 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
592
609
|
await client.connect(endpointUrl);
|
|
593
610
|
const session = await client.createSession2(userIdentity);
|
|
594
611
|
|
|
612
|
+
// biome-ignore lint/suspicious/noExplicitAny: monkey patch close
|
|
595
613
|
const oldClose = session.close as any;
|
|
614
|
+
// biome-ignore lint/suspicious/noExplicitAny: monkey patch close
|
|
596
615
|
(session as any).close = withCallback((...args: any[]): any => {
|
|
597
616
|
if (args.length === 1) {
|
|
598
617
|
return session.close(true, args[0]);
|
|
@@ -600,9 +619,9 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
600
619
|
const deleteSubscriptions = args[0] as boolean;
|
|
601
620
|
const callback = args[1] as Callback<void>;
|
|
602
621
|
session.close = oldClose;
|
|
603
|
-
oldClose.call(session, deleteSubscriptions, (
|
|
622
|
+
oldClose.call(session, deleteSubscriptions, (_err?: Error) => {
|
|
604
623
|
client.disconnect((err?: Error | null) => {
|
|
605
|
-
callback(err
|
|
624
|
+
callback(err as Error);
|
|
606
625
|
});
|
|
607
626
|
});
|
|
608
627
|
});
|
|
@@ -610,10 +629,10 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
610
629
|
}
|
|
611
630
|
|
|
612
631
|
/**
|
|
613
|
-
*
|
|
614
|
-
* @param connectionPoint
|
|
615
|
-
* @param func
|
|
616
|
-
* @returns
|
|
632
|
+
*
|
|
633
|
+
* @param connectionPoint
|
|
634
|
+
* @param func
|
|
635
|
+
* @returns
|
|
617
636
|
*/
|
|
618
637
|
public async withSessionAsync<T>(connectionPoint: string | EndpointWithUserIdentity, func: WithSessionFuncP<T>): Promise<T> {
|
|
619
638
|
assert(typeof func === "function");
|
|
@@ -624,16 +643,16 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
624
643
|
typeof connectionPoint === "string" ? { type: UserTokenType.Anonymous } : connectionPoint.userIdentity;
|
|
625
644
|
|
|
626
645
|
this.on("backoff", (count, delay) => {
|
|
627
|
-
warningLog("cannot connect to ", endpointUrl,
|
|
646
|
+
warningLog("cannot connect to ", endpointUrl, `attempt #${count}`, " retrying in ", delay);
|
|
628
647
|
});
|
|
629
648
|
|
|
630
649
|
await this.connect(endpointUrl);
|
|
631
650
|
|
|
632
651
|
try {
|
|
633
652
|
const session = await this.createSession2(userIdentity);
|
|
634
|
-
let result;
|
|
653
|
+
let result: T;
|
|
635
654
|
|
|
636
|
-
// always need this
|
|
655
|
+
// always need this
|
|
637
656
|
await readNamespaceArray(session);
|
|
638
657
|
|
|
639
658
|
try {
|
|
@@ -688,19 +707,20 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
688
707
|
*/
|
|
689
708
|
public async reactivateSession(session: ClientSession): Promise<void>;
|
|
690
709
|
public reactivateSession(session: ClientSession, callback: (err?: Error) => void): void;
|
|
710
|
+
// biome-ignore lint/suspicious/noExplicitAny: overload implementation
|
|
691
711
|
public reactivateSession(session: ClientSession, callback?: (err?: Error) => void): any {
|
|
692
712
|
const internalSession = session as ClientSessionImpl;
|
|
693
713
|
|
|
694
714
|
assert(typeof callback === "function");
|
|
695
715
|
if (!this._secureChannel) {
|
|
696
|
-
return callback
|
|
716
|
+
return callback?.(new Error(" client must be connected first"));
|
|
697
717
|
}
|
|
698
718
|
// c8 ignore next
|
|
699
719
|
if (!this.__resolveEndPoint() || !this.endpoint) {
|
|
700
|
-
return callback
|
|
720
|
+
return callback?.(
|
|
701
721
|
new Error(
|
|
702
722
|
" End point must exist " +
|
|
703
|
-
this._secureChannel
|
|
723
|
+
this._secureChannel?.endpointUrl +
|
|
704
724
|
" securityMode = " +
|
|
705
725
|
MessageSecurityMode[this.securityMode] +
|
|
706
726
|
" securityPolicy = " +
|
|
@@ -720,7 +740,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
720
740
|
|
|
721
741
|
this._activateSession(
|
|
722
742
|
internalSession,
|
|
723
|
-
internalSession.userIdentityInfo
|
|
743
|
+
internalSession.userIdentityInfo as UserIdentityInfo,
|
|
724
744
|
(err: Error | null /*, newSession?: ClientSessionImpl*/) => {
|
|
725
745
|
if (!err) {
|
|
726
746
|
if (old_client !== this) {
|
|
@@ -735,13 +755,13 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
735
755
|
assert(!internalSession._closed, "session should not vbe closed");
|
|
736
756
|
assert(this._sessions.indexOf(internalSession) !== -1);
|
|
737
757
|
}
|
|
738
|
-
callback
|
|
758
|
+
callback?.();
|
|
739
759
|
} else {
|
|
740
760
|
// c8 ignore next
|
|
741
761
|
if (doDebug) {
|
|
742
762
|
debugLog(chalk.red.bgWhite("reactivateSession has failed !"), err.message);
|
|
743
763
|
}
|
|
744
|
-
callback
|
|
764
|
+
callback?.(err);
|
|
745
765
|
}
|
|
746
766
|
}
|
|
747
767
|
);
|
|
@@ -762,18 +782,16 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
762
782
|
* @internal
|
|
763
783
|
* @private
|
|
764
784
|
*/
|
|
765
|
-
#createSession_step3(
|
|
766
|
-
session: ClientSessionImpl,
|
|
767
|
-
callback: (err: Error | null, session?: ClientSessionImpl) => void
|
|
768
|
-
): void {
|
|
785
|
+
#createSession_step3(session: ClientSessionImpl, callback: (err: Error | null, session?: ClientSessionImpl) => void): void {
|
|
769
786
|
assert(typeof callback === "function");
|
|
770
|
-
assert(this.serverUri !== undefined,
|
|
787
|
+
assert(this.serverUri !== undefined, ` must have a valid server URI ${this.serverUri}`);
|
|
771
788
|
assert(this.endpointUrl !== undefined, " must have a valid server endpointUrl");
|
|
772
789
|
assert(this.endpoint);
|
|
773
790
|
|
|
774
791
|
// c8 ignore next
|
|
775
792
|
if (!this._secureChannel) {
|
|
776
|
-
|
|
793
|
+
callback(new Error("Invalid channel"));
|
|
794
|
+
return;
|
|
777
795
|
}
|
|
778
796
|
|
|
779
797
|
const applicationUri = this._getApplicationUri();
|
|
@@ -834,7 +852,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
834
852
|
|
|
835
853
|
if (response.responseHeader.serviceResult !== StatusCodes.Good) {
|
|
836
854
|
err = new Error(
|
|
837
|
-
|
|
855
|
+
`Error ${response.responseHeader.serviceResult.name} ${response.responseHeader.serviceResult.description}`
|
|
838
856
|
);
|
|
839
857
|
return callback(err);
|
|
840
858
|
}
|
|
@@ -897,7 +915,8 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
897
915
|
|
|
898
916
|
// c8 ignore next
|
|
899
917
|
if (!this._secureChannel) {
|
|
900
|
-
|
|
918
|
+
callback(new Error(" No secure channel"));
|
|
919
|
+
return;
|
|
901
920
|
}
|
|
902
921
|
|
|
903
922
|
const serverCertificate = session.serverCertificate;
|
|
@@ -914,10 +933,10 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
914
933
|
session._client = this;
|
|
915
934
|
|
|
916
935
|
const context: IdentityTokenContext = {
|
|
917
|
-
endpoint: this.endpoint
|
|
936
|
+
endpoint: this.endpoint as EndpointDescription,
|
|
918
937
|
securityPolicy: this._secureChannel.securityPolicy,
|
|
919
938
|
serverCertificate,
|
|
920
|
-
serverNonce: serverNonce
|
|
939
|
+
serverNonce: serverNonce as Buffer // please check this !
|
|
921
940
|
};
|
|
922
941
|
|
|
923
942
|
this.createUserIdentityToken(context, userIdentityInfo, (err: Error | null, data?: TokenAndSignature | null) => {
|
|
@@ -926,9 +945,9 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
926
945
|
return callback(err);
|
|
927
946
|
}
|
|
928
947
|
|
|
929
|
-
data = data
|
|
930
|
-
const userIdentityToken: UserIdentityToken = data.userIdentityToken
|
|
931
|
-
const userTokenSignature: SignatureDataOptions = data.userTokenSignature
|
|
948
|
+
data = data as TokenAndSignature;
|
|
949
|
+
const userIdentityToken: UserIdentityToken = data.userIdentityToken as UserIdentityToken;
|
|
950
|
+
const userTokenSignature: SignatureDataOptions = data.userTokenSignature as SignatureDataOptions;
|
|
932
951
|
// TODO. fill the ActivateSessionRequest
|
|
933
952
|
// see 5.6.3.2 Parameters OPC Unified Architecture, Part 4 30 Release 1.02
|
|
934
953
|
const request = new ActivateSessionRequest({
|
|
@@ -936,7 +955,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
936
955
|
// clientCertificate. The SignatureAlgorithm shall be the AsymmetricSignatureAlgorithm
|
|
937
956
|
// specified in the SecurityPolicy for the Endpoint. The SignatureData type is defined in 7.30.
|
|
938
957
|
|
|
939
|
-
clientSignature: this.computeClientSignature(this._secureChannel
|
|
958
|
+
clientSignature: this.computeClientSignature(this._secureChannel as ClientSecureChannelLayer, serverCertificate, serverNonce) || undefined,
|
|
940
959
|
|
|
941
960
|
// These are the SoftwareCertificates which have been issued to the Client application.
|
|
942
961
|
// The productUri contained in the SoftwareCertificates shall match the productUri in the
|
|
@@ -977,7 +996,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
977
996
|
userTokenSignature
|
|
978
997
|
});
|
|
979
998
|
|
|
980
|
-
request.requestHeader.authenticationToken = session.authenticationToken
|
|
999
|
+
request.requestHeader.authenticationToken = session.authenticationToken as NodeId;
|
|
981
1000
|
session.lastRequestSentTime = new Date();
|
|
982
1001
|
|
|
983
1002
|
this.performMessageTransaction(request, (err1: Error | null, response?: Response) => {
|
|
@@ -1053,7 +1072,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
1053
1072
|
private __resolveEndPoint() {
|
|
1054
1073
|
this.securityPolicy = this.securityPolicy || SecurityPolicy.None;
|
|
1055
1074
|
|
|
1056
|
-
let endpoint = this.findEndpoint(this._secureChannel
|
|
1075
|
+
let endpoint = this.findEndpoint(this._secureChannel?.endpointUrl || "", this.securityMode, this.securityPolicy);
|
|
1057
1076
|
this.endpoint = endpoint;
|
|
1058
1077
|
|
|
1059
1078
|
// this is explained here : see OPCUA Part 4 Version 1.02 $5.4.1 page 12:
|
|
@@ -1065,7 +1084,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
1065
1084
|
if (this.endpointMustExist) {
|
|
1066
1085
|
warningLog(
|
|
1067
1086
|
"OPCUAClientImpl#endpointMustExist = true and endpoint with url ",
|
|
1068
|
-
this._secureChannel
|
|
1087
|
+
this._secureChannel?.endpointUrl,
|
|
1069
1088
|
" cannot be found"
|
|
1070
1089
|
);
|
|
1071
1090
|
const infos = this._serverEndpoints.map(
|
|
@@ -1073,7 +1092,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
1073
1092
|
`${endpoint.endpointUrl} ${MessageSecurityMode[endpoint.securityMode]}, ${endpoint.securityPolicyUri} `
|
|
1074
1093
|
);
|
|
1075
1094
|
warningLog("Valid endpoints are ");
|
|
1076
|
-
warningLog(
|
|
1095
|
+
warningLog(` ${infos.join("\n ")}`);
|
|
1077
1096
|
return false;
|
|
1078
1097
|
} else {
|
|
1079
1098
|
// fallback :
|
|
@@ -1120,7 +1139,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
1120
1139
|
return callback(
|
|
1121
1140
|
new Error(
|
|
1122
1141
|
" End point must exist " +
|
|
1123
|
-
this._secureChannel
|
|
1142
|
+
this._secureChannel?.endpointUrl +
|
|
1124
1143
|
" securityMode = " +
|
|
1125
1144
|
MessageSecurityMode[this.securityMode] +
|
|
1126
1145
|
" securityPolicy = " +
|
|
@@ -1129,7 +1148,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
1129
1148
|
);
|
|
1130
1149
|
}
|
|
1131
1150
|
this.serverUri = this.endpoint.server.applicationUri || "invalid application uri";
|
|
1132
|
-
this.endpointUrl = this._secureChannel
|
|
1151
|
+
this.endpointUrl = this._secureChannel?.endpointUrl || "";
|
|
1133
1152
|
|
|
1134
1153
|
const session = new ClientSessionImpl(this);
|
|
1135
1154
|
session.name = this._nextSessionName();
|
|
@@ -1152,18 +1171,19 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
1152
1171
|
userIdentityInfo: UserIdentityInfo,
|
|
1153
1172
|
callback: (err: Error | null, data?: TokenAndSignature) => void
|
|
1154
1173
|
) {
|
|
1174
|
+
// biome-ignore lint/suspicious/noExplicitAny: user provided object that needs soft type coercion
|
|
1155
1175
|
function coerceUserIdentityInfo(identityInfo: any): UserIdentityInfo {
|
|
1156
1176
|
if (!identityInfo) {
|
|
1157
1177
|
return { type: UserTokenType.Anonymous };
|
|
1158
1178
|
}
|
|
1159
|
-
if (Object.
|
|
1179
|
+
if (Object.hasOwn(identityInfo, "type")) {
|
|
1160
1180
|
return identityInfo as UserIdentityInfo;
|
|
1161
1181
|
}
|
|
1162
|
-
if (Object.
|
|
1182
|
+
if (Object.hasOwn(identityInfo, "userName")) {
|
|
1163
1183
|
identityInfo.type = UserTokenType.UserName;
|
|
1164
1184
|
return identityInfo as UserIdentityInfoUserName;
|
|
1165
1185
|
}
|
|
1166
|
-
if (Object.
|
|
1186
|
+
if (Object.hasOwn(identityInfo, "certificateData")) {
|
|
1167
1187
|
identityInfo.type = UserTokenType.Certificate;
|
|
1168
1188
|
return identityInfo as UserIdentityInfoX509;
|
|
1169
1189
|
}
|
|
@@ -1214,7 +1234,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
1214
1234
|
}
|
|
1215
1235
|
} catch (err) {
|
|
1216
1236
|
if (typeof err === "string") {
|
|
1217
|
-
return callback(new Error(
|
|
1237
|
+
return callback(new Error(`Create identity token failed ${userIdentityInfo.type} ${err}`));
|
|
1218
1238
|
}
|
|
1219
1239
|
return callback(err as Error);
|
|
1220
1240
|
}
|
|
@@ -1225,6 +1245,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
1225
1245
|
// tslint:disable:no-var-requires
|
|
1226
1246
|
// tslint:disable:max-line-length
|
|
1227
1247
|
import { withCallback } from "thenify-ex";
|
|
1248
|
+
|
|
1228
1249
|
/**
|
|
1229
1250
|
|
|
1230
1251
|
*
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
const LONG_EVENT_HANDLER = process.env.NODEOPCUA_LONG_EVENT_HANDLER ? parseFloat(process.env.NODEOPCUA_LONG_EVENT_HANDLER) : 100; // how long a write can take before we log a warning
|
|
1
|
+
const LONG_EVENT_HANDLER = process.env.NODEOPCUA_LONG_EVENT_HANDLER ? parseFloat(process.env.NODEOPCUA_LONG_EVENT_HANDLER) : 100; // how long a write can take before we log a warning
|
|
3
2
|
|
|
4
3
|
const convertHrtimeToMilliseconds = (hrtime: [number, number]) => {
|
|
5
4
|
const seconds = hrtime[0];
|
|
@@ -7,7 +6,7 @@ const convertHrtimeToMilliseconds = (hrtime: [number, number]) => {
|
|
|
7
6
|
return seconds * 1e3 + nanoseconds * 1e-6;
|
|
8
7
|
};
|
|
9
8
|
|
|
10
|
-
export function detectLongOperation(lambda: () => void, onLongOperation:(duration: number
|
|
9
|
+
export function detectLongOperation(lambda: () => void, onLongOperation: (duration: number) => void): void {
|
|
11
10
|
const start = process.hrtime();
|
|
12
11
|
lambda();
|
|
13
12
|
const duration = convertHrtimeToMilliseconds(process.hrtime(start));
|
|
@@ -1,26 +1,21 @@
|
|
|
1
|
-
import { types } from "util";
|
|
2
1
|
import async from "async";
|
|
3
2
|
import chalk from "chalk";
|
|
4
3
|
import assert from "node-opcua-assert";
|
|
5
4
|
import { checkDebugFlag, make_debugLog } from "node-opcua-debug";
|
|
6
5
|
import { StatusCodes } from "node-opcua-status-code";
|
|
7
|
-
import { RepublishRequest, RepublishResponse } from "node-opcua-types";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
6
|
+
import { RepublishRequest, type RepublishResponse } from "node-opcua-types";
|
|
7
|
+
import { types } from "util";
|
|
8
|
+
import type { SubscriptionId } from "../../client_session";
|
|
9
|
+
import type { ClientSidePublishEngine } from "../client_publish_engine";
|
|
10
|
+
import type { ClientSessionImpl } from "../client_session_impl";
|
|
11
|
+
import type { ClientSubscriptionImpl } from "../client_subscription_impl";
|
|
12
12
|
import { recreateSubscriptionAndMonitoredItem } from "./client_subscription_reconnection";
|
|
13
13
|
import { _shouldNotContinue2 } from "./reconnection";
|
|
14
14
|
|
|
15
15
|
const debugLog = make_debugLog("RECONNECTION");
|
|
16
16
|
const doDebug = checkDebugFlag("RECONNECTION");
|
|
17
17
|
|
|
18
|
-
function _republish(
|
|
19
|
-
engine: ClientSidePublishEngine,
|
|
20
|
-
subscription: ClientSubscriptionImpl,
|
|
21
|
-
callback: (err?: Error) => void
|
|
22
|
-
) {
|
|
23
|
-
|
|
18
|
+
function _republish(engine: ClientSidePublishEngine, subscription: ClientSubscriptionImpl, callback: (err?: Error) => void) {
|
|
24
19
|
let isDone = false;
|
|
25
20
|
const session = engine.session as ClientSessionImpl;
|
|
26
21
|
|
|
@@ -87,10 +82,14 @@ function __askSubscriptionRepublish(
|
|
|
87
82
|
subscription: ClientSubscriptionImpl,
|
|
88
83
|
callback: (err?: Error) => void
|
|
89
84
|
) {
|
|
90
|
-
|
|
91
85
|
_republish(engine, subscription, (err?: Error) => {
|
|
92
86
|
// prettier-ignore
|
|
93
|
-
{
|
|
87
|
+
{
|
|
88
|
+
const _err = _shouldNotContinue2(subscription);
|
|
89
|
+
if (_err) {
|
|
90
|
+
return callback(_err);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
94
93
|
|
|
95
94
|
assert(!err || types.isNativeError(err));
|
|
96
95
|
|
|
@@ -113,7 +112,9 @@ function __askSubscriptionRepublish(
|
|
|
113
112
|
debugLog(
|
|
114
113
|
chalk.bgWhite.red("__askSubscriptionRepublish failed " + " subscriptionId is not valid anymore on server side.")
|
|
115
114
|
);
|
|
116
|
-
return recreateSubscriptionAndMonitoredItem(subscription)
|
|
115
|
+
return recreateSubscriptionAndMonitoredItem(subscription)
|
|
116
|
+
.then(() => callback())
|
|
117
|
+
.catch((err) => callback(err));
|
|
117
118
|
}
|
|
118
119
|
if (err && err.message.match(/|MessageNotAvailable/)) {
|
|
119
120
|
// start engine and start monitoring
|