node-opcua-client 2.178.0 → 2.179.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/alarms_and_conditions/client_alarm_tools.js +7 -5
- package/dist/alarms_and_conditions/client_alarm_tools.js.map +1 -1
- package/dist/alarms_and_conditions/client_tools.js +38 -28
- package/dist/alarms_and_conditions/client_tools.js.map +1 -1
- package/dist/client_base.js.map +1 -1
- package/dist/client_monitored_item.d.ts +1 -1
- package/dist/client_monitored_item.js +4 -2
- package/dist/client_monitored_item.js.map +1 -1
- package/dist/client_monitored_item_group.d.ts +4 -3
- package/dist/client_monitored_item_group.js +8 -5
- package/dist/client_monitored_item_group.js.map +1 -1
- package/dist/client_monitored_item_toolbox.js +4 -2
- package/dist/client_monitored_item_toolbox.js.map +1 -1
- package/dist/client_session.d.ts +9 -2
- package/dist/client_session_keepalive_manager.d.ts +1 -1
- package/dist/client_session_keepalive_manager.js +50 -29
- package/dist/client_session_keepalive_manager.js.map +1 -1
- package/dist/client_subscription.d.ts +2 -2
- package/dist/client_subscription.js +3 -1
- package/dist/client_subscription.js.map +1 -1
- package/dist/common.d.ts +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/opcua_client.js +1 -0
- package/dist/opcua_client.js.map +1 -1
- package/dist/private/client_base_impl.js +125 -65
- package/dist/private/client_base_impl.js.map +1 -1
- package/dist/private/client_monitored_item_group_impl.d.ts +1 -0
- package/dist/private/client_monitored_item_group_impl.js +6 -8
- package/dist/private/client_monitored_item_group_impl.js.map +1 -1
- package/dist/private/client_monitored_item_impl.js +0 -4
- package/dist/private/client_monitored_item_impl.js.map +1 -1
- package/dist/private/client_publish_engine.js +62 -28
- package/dist/private/client_publish_engine.js.map +1 -1
- package/dist/private/client_session_impl.d.ts +49 -17
- package/dist/private/client_session_impl.js +240 -143
- package/dist/private/client_session_impl.js.map +1 -1
- package/dist/private/client_subscription_impl.js +15 -12
- package/dist/private/client_subscription_impl.js.map +1 -1
- package/dist/private/i_private_client.d.ts +1 -1
- package/dist/private/opcua_client_impl.js +12 -10
- package/dist/private/opcua_client_impl.js.map +1 -1
- package/dist/private/reconnection/client_publish_engine_reconnection.js +17 -7
- package/dist/private/reconnection/client_publish_engine_reconnection.js.map +1 -1
- package/dist/private/reconnection/client_subscription_reconnection.js +11 -7
- package/dist/private/reconnection/client_subscription_reconnection.js.map +1 -1
- package/dist/private/reconnection/reconnection.js +31 -14
- package/dist/private/reconnection/reconnection.js.map +1 -1
- package/dist/reverse/client_reverse_connect.js.map +1 -1
- package/dist/tools/findservers.js.map +1 -1
- package/dist/tools/read_history_server_capabilities.d.ts +2 -1
- package/dist/tools/read_history_server_capabilities.js +6 -3
- package/dist/tools/read_history_server_capabilities.js.map +1 -1
- package/package.json +50 -50
- package/source/alarms_and_conditions/client_alarm_tools.ts +10 -8
- package/source/alarms_and_conditions/client_tools.ts +71 -30
- package/source/client_base.ts +0 -1
- package/source/client_monitored_item.ts +10 -9
- package/source/client_monitored_item_base.ts +2 -8
- package/source/client_monitored_item_group.ts +13 -10
- package/source/client_monitored_item_toolbox.ts +4 -2
- package/source/client_session.ts +10 -3
- package/source/client_session_keepalive_manager.ts +72 -55
- package/source/client_subscription.ts +6 -3
- package/source/common.ts +4 -0
- package/source/index.ts +1 -1
- package/source/opcua_client.ts +1 -0
- package/source/private/client_base_impl.ts +179 -102
- package/source/private/client_monitored_item_group_impl.ts +17 -18
- package/source/private/client_monitored_item_impl.ts +0 -4
- package/source/private/client_publish_engine.ts +78 -40
- package/source/private/client_session_impl.ts +393 -236
- package/source/private/client_subscription_impl.ts +20 -25
- package/source/private/i_private_client.ts +1 -1
- package/source/private/opcua_client_impl.ts +13 -10
- package/source/private/reconnection/client_publish_engine_reconnection.ts +22 -21
- package/source/private/reconnection/client_subscription_reconnection.ts +12 -8
- package/source/private/reconnection/reconnection.ts +35 -18
- package/source/reverse/client_reverse_connect.ts +11 -3
- package/source/tools/findservers.ts +0 -1
- package/source/tools/read_history_server_capabilities.ts +9 -7
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* @module node-opcua-client-private
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import { EventEmitter } from "node:events";
|
|
5
6
|
import chalk from "chalk";
|
|
6
|
-
import { EventEmitter } from "events";
|
|
7
7
|
import { assert } from "node-opcua-assert";
|
|
8
8
|
import type { DateTime } from "node-opcua-basic-types";
|
|
9
9
|
import {
|
|
@@ -33,7 +33,12 @@ import {
|
|
|
33
33
|
readNamespaceArray
|
|
34
34
|
} from "node-opcua-pseudo-session";
|
|
35
35
|
import type { AnyConstructorFunc } from "node-opcua-schemas";
|
|
36
|
-
import {
|
|
36
|
+
import {
|
|
37
|
+
type ServiceFaultAnnotatedError as ChannelServiceFaultAnnotatedError,
|
|
38
|
+
ClientSecureChannelLayer,
|
|
39
|
+
requestHandleNotSetValue,
|
|
40
|
+
type SignatureData
|
|
41
|
+
} from "node-opcua-secure-channel";
|
|
37
42
|
import { BrowseDescription, BrowseRequest, BrowseResponse, BrowseResult } from "node-opcua-service-browse";
|
|
38
43
|
import { CallMethodRequest, type CallMethodResult, CallRequest, CallResponse } from "node-opcua-service-call";
|
|
39
44
|
import type { EndpointDescription } from "node-opcua-service-endpoints";
|
|
@@ -137,15 +142,15 @@ import { ClientSubscriptionImpl } from "./client_subscription_impl";
|
|
|
137
142
|
import type { IClientBase } from "./i_private_client";
|
|
138
143
|
import { repair_client_session } from "./reconnection/reconnection";
|
|
139
144
|
|
|
140
|
-
const helpAPIChange = process.env.DEBUG
|
|
145
|
+
const helpAPIChange = process.env.DEBUG?.match(/API/);
|
|
141
146
|
const debugLog = make_debugLog(__filename);
|
|
142
147
|
const doDebug = checkDebugFlag(__filename);
|
|
143
148
|
const warningLog = make_warningLog(__filename);
|
|
144
|
-
const
|
|
149
|
+
const _errorLog = make_errorLog(__filename);
|
|
145
150
|
|
|
146
151
|
let pendingTransactionMessageDisplayed = false;
|
|
147
152
|
|
|
148
|
-
function coerceBrowseDescription(data:
|
|
153
|
+
function coerceBrowseDescription(data: BrowseDescriptionLike | NodeId): BrowseDescription {
|
|
149
154
|
if (typeof data === "string" || data instanceof NodeId) {
|
|
150
155
|
return coerceBrowseDescription({
|
|
151
156
|
browseDirection: BrowseDirection.Forward,
|
|
@@ -156,13 +161,14 @@ function coerceBrowseDescription(data: any): BrowseDescription {
|
|
|
156
161
|
resultMask: 63
|
|
157
162
|
});
|
|
158
163
|
} else {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
164
|
+
const options = data as { nodeId: NodeIdLike; referenceTypeId?: NodeIdLike | null };
|
|
165
|
+
options.nodeId = resolveNodeId(options.nodeId);
|
|
166
|
+
options.referenceTypeId = options.referenceTypeId ? resolveNodeId(options.referenceTypeId) : null;
|
|
167
|
+
return new BrowseDescription(options);
|
|
162
168
|
}
|
|
163
169
|
}
|
|
164
170
|
|
|
165
|
-
function coerceReadValueId(node:
|
|
171
|
+
function coerceReadValueId(node: unknown): ReadValueId {
|
|
166
172
|
if (typeof node === "string" || node instanceof NodeId) {
|
|
167
173
|
return new ReadValueId({
|
|
168
174
|
attributeId: AttributeIds.Value,
|
|
@@ -172,7 +178,7 @@ function coerceReadValueId(node: any): ReadValueId {
|
|
|
172
178
|
});
|
|
173
179
|
} else {
|
|
174
180
|
assert(node instanceof Object);
|
|
175
|
-
return new ReadValueId(node);
|
|
181
|
+
return new ReadValueId(node as ReadValueIdOptions);
|
|
176
182
|
}
|
|
177
183
|
}
|
|
178
184
|
|
|
@@ -180,6 +186,31 @@ const emptyUint32Array = new Uint32Array(0);
|
|
|
180
186
|
|
|
181
187
|
type EmptyCallback = (err?: Error) => void;
|
|
182
188
|
|
|
189
|
+
// re-exported from node-opcua-secure-channel, where the annotation is produced
|
|
190
|
+
// (see process_request_callback): response / request / serviceDiagnostics / diagnosticsInfo.
|
|
191
|
+
type ServiceFaultAnnotatedError = ChannelServiceFaultAnnotatedError;
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* attach the server side diagnostics to an error, so that a caller can inspect them without
|
|
195
|
+
* having to know how the channel delivered the failure.
|
|
196
|
+
*
|
|
197
|
+
* For a ServiceFault there is no `response` argument at all - the channel moved the decoded
|
|
198
|
+
* fault onto `err.response` - so fall back to it, otherwise the diagnostics of the most
|
|
199
|
+
* interesting case would always be dropped.
|
|
200
|
+
*/
|
|
201
|
+
function annotateWithDiagnostics(err: Error, response?: Response): Error {
|
|
202
|
+
const annotatedError = err as ServiceFaultAnnotatedError;
|
|
203
|
+
const source = response ?? annotatedError.response;
|
|
204
|
+
if (source?.responseHeader.serviceDiagnostics) {
|
|
205
|
+
annotatedError.serviceDiagnostics = source.responseHeader.serviceDiagnostics;
|
|
206
|
+
}
|
|
207
|
+
const responseWithDiagnosticInfos = source as unknown as { diagnosticInfos?: unknown } | undefined;
|
|
208
|
+
if (responseWithDiagnosticInfos?.diagnosticInfos) {
|
|
209
|
+
annotatedError.diagnosticsInfo = responseWithDiagnosticInfos.diagnosticInfos;
|
|
210
|
+
}
|
|
211
|
+
return annotatedError;
|
|
212
|
+
}
|
|
213
|
+
|
|
183
214
|
export interface Reconnectable {
|
|
184
215
|
_reconnecting: {
|
|
185
216
|
reconnecting: boolean;
|
|
@@ -212,7 +243,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
212
243
|
public _reconnecting: {
|
|
213
244
|
reconnecting: boolean;
|
|
214
245
|
pendingCallbacks: EmptyCallback[];
|
|
215
|
-
pendingTransactions:
|
|
246
|
+
pendingTransactions: { request: Request; callback: (err: Error | null, response?: Response) => void }[];
|
|
216
247
|
};
|
|
217
248
|
|
|
218
249
|
/**
|
|
@@ -250,7 +281,10 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
250
281
|
}
|
|
251
282
|
|
|
252
283
|
getTransportSettings(): IBasicTransportSettings {
|
|
253
|
-
|
|
284
|
+
if (!this._client) {
|
|
285
|
+
throw new Error("session has been closed - no transport settings available");
|
|
286
|
+
}
|
|
287
|
+
return this._client.getTransportSettings();
|
|
254
288
|
}
|
|
255
289
|
/**
|
|
256
290
|
* the endpoint on which this session is operating
|
|
@@ -258,7 +292,10 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
258
292
|
* @type {EndpointDescription}
|
|
259
293
|
*/
|
|
260
294
|
get endpoint(): EndpointDescription {
|
|
261
|
-
|
|
295
|
+
if (!this._client?.endpoint) {
|
|
296
|
+
throw new Error("session has been closed - no endpoint available");
|
|
297
|
+
}
|
|
298
|
+
return this._client.endpoint;
|
|
262
299
|
}
|
|
263
300
|
|
|
264
301
|
get subscriptionCount(): number {
|
|
@@ -290,31 +327,32 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
290
327
|
if (!this._publishEngine) {
|
|
291
328
|
this._publishEngine = new ClientSidePublishEngine(this);
|
|
292
329
|
}
|
|
293
|
-
return this._publishEngine
|
|
330
|
+
return this._publishEngine;
|
|
294
331
|
}
|
|
295
332
|
|
|
296
333
|
public changeUser(userIdentityInfo: UserIdentityInfo): Promise<StatusCode>;
|
|
297
334
|
public changeUser(userIdentityInfo: UserIdentityInfo, callback: CallbackT<StatusCode>): void;
|
|
298
|
-
public changeUser(userIdentityInfo: UserIdentityInfo, callback?: CallbackT<StatusCode>):
|
|
335
|
+
public changeUser(userIdentityInfo: UserIdentityInfo, callback?: CallbackT<StatusCode>): unknown {
|
|
299
336
|
userIdentityInfo = userIdentityInfo || {
|
|
300
337
|
type: UserTokenType.Anonymous
|
|
301
338
|
};
|
|
302
339
|
if (!this._client || !this.userIdentityInfo) {
|
|
303
340
|
warningLog("changeUser: invalid session");
|
|
304
|
-
return callback
|
|
341
|
+
return callback?.(null, StatusCodes.BadInternalError);
|
|
305
342
|
}
|
|
306
343
|
|
|
307
344
|
const old_userIdentity: UserIdentityInfo = this.userIdentityInfo;
|
|
308
345
|
|
|
309
|
-
this._client._activateSession(this, userIdentityInfo, (err1: Error | null,
|
|
346
|
+
this._client._activateSession(this, userIdentityInfo, (err1: Error | null, _session2?: ClientSessionImpl) => {
|
|
310
347
|
if (err1) {
|
|
311
348
|
this.userIdentityInfo = old_userIdentity;
|
|
312
349
|
warningLog("activate session error = ", err1.message);
|
|
313
|
-
return callback
|
|
350
|
+
return callback?.(null, StatusCodes.BadUserAccessDenied);
|
|
314
351
|
}
|
|
315
352
|
this.userIdentityInfo = userIdentityInfo;
|
|
316
|
-
callback
|
|
353
|
+
callback?.(null, StatusCodes.Good);
|
|
317
354
|
});
|
|
355
|
+
return undefined;
|
|
318
356
|
}
|
|
319
357
|
/**
|
|
320
358
|
*
|
|
@@ -385,22 +423,24 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
385
423
|
* @internal
|
|
386
424
|
* @param args
|
|
387
425
|
*/
|
|
388
|
-
public browse(...args:
|
|
426
|
+
public browse(...args: unknown[]): unknown {
|
|
389
427
|
const arg0 = args[0];
|
|
390
428
|
const isArray = Array.isArray(arg0);
|
|
391
|
-
const callback
|
|
429
|
+
const callback = args[1] as ResponseCallback<BrowseResult[] | BrowseResult>;
|
|
392
430
|
assert(typeof callback === "function");
|
|
393
431
|
|
|
394
|
-
assert(isFinite(this.requestedMaxReferencesPerNode));
|
|
432
|
+
assert(Number.isFinite(this.requestedMaxReferencesPerNode));
|
|
395
433
|
|
|
396
|
-
const nodesToBrowse: BrowseDescription[] = (
|
|
434
|
+
const nodesToBrowse: BrowseDescription[] = (
|
|
435
|
+
isArray ? (arg0 as BrowseDescriptionLike[]) : [arg0 as BrowseDescriptionLike]
|
|
436
|
+
).map(coerceBrowseDescription);
|
|
397
437
|
|
|
398
438
|
const request = new BrowseRequest({
|
|
399
439
|
nodesToBrowse,
|
|
400
440
|
requestedMaxReferencesPerNode: this.requestedMaxReferencesPerNode
|
|
401
441
|
});
|
|
402
442
|
|
|
403
|
-
this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
443
|
+
return this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
404
444
|
if (err) {
|
|
405
445
|
return callback(err);
|
|
406
446
|
}
|
|
@@ -423,8 +463,8 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
423
463
|
" BrowseResponse : the server didn't take into" +
|
|
424
464
|
" account our requestedMaxReferencesPerNode "
|
|
425
465
|
);
|
|
426
|
-
warningLog(
|
|
427
|
-
warningLog(
|
|
466
|
+
warningLog(` this.requestedMaxReferencesPerNode= ${this.requestedMaxReferencesPerNode}`);
|
|
467
|
+
warningLog(` got ${r.references.length}for ${nodesToBrowse[i].nodeId.toString()}`);
|
|
428
468
|
warningLog(" continuationPoint ", r.continuationPoint);
|
|
429
469
|
}
|
|
430
470
|
}
|
|
@@ -451,21 +491,21 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
451
491
|
|
|
452
492
|
public async browseNext(continuationPoint: Buffer, releaseContinuationPoints: boolean): Promise<BrowseResult>;
|
|
453
493
|
public async browseNext(continuationPoints: Buffer[], releaseContinuationPoints: boolean): Promise<BrowseResult[]>;
|
|
454
|
-
public browseNext(...args:
|
|
494
|
+
public browseNext(...args: unknown[]): unknown {
|
|
455
495
|
const arg0 = args[0];
|
|
456
496
|
const isArray = Array.isArray(arg0);
|
|
457
497
|
const releaseContinuationPoints = args[1] as boolean;
|
|
458
|
-
const callback
|
|
498
|
+
const callback = args[2] as ResponseCallback<BrowseResult[] | BrowseResult>;
|
|
459
499
|
assert(typeof callback === "function", "expecting a callback function here");
|
|
460
500
|
|
|
461
|
-
const continuationPoints: Buffer[] = isArray ? arg0 : [arg0 as Buffer];
|
|
501
|
+
const continuationPoints: Buffer[] = isArray ? (arg0 as Buffer[]) : [arg0 as Buffer];
|
|
462
502
|
|
|
463
503
|
const request = new BrowseNextRequest({
|
|
464
504
|
continuationPoints,
|
|
465
505
|
releaseContinuationPoints
|
|
466
506
|
});
|
|
467
507
|
|
|
468
|
-
this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
508
|
+
return this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
469
509
|
/* c8 ignore next */
|
|
470
510
|
if (err) {
|
|
471
511
|
return callback(err);
|
|
@@ -525,13 +565,13 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
525
565
|
* @internal
|
|
526
566
|
* @param args
|
|
527
567
|
*/
|
|
528
|
-
public readVariableValue(...args:
|
|
529
|
-
const callback = args[1]
|
|
568
|
+
public readVariableValue(...args: unknown[]): unknown {
|
|
569
|
+
const callback = args[1] as ResponseCallback<DataValue[] | DataValue>;
|
|
530
570
|
assert(typeof callback === "function");
|
|
531
571
|
|
|
532
572
|
const isArray = Array.isArray(args[0]);
|
|
533
573
|
|
|
534
|
-
const nodes = isArray ? args[0] : [args[0]];
|
|
574
|
+
const nodes: unknown[] = isArray ? (args[0] as unknown[]) : [args[0]];
|
|
535
575
|
|
|
536
576
|
const nodesToRead = nodes.map(coerceReadValueId);
|
|
537
577
|
|
|
@@ -540,7 +580,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
540
580
|
timestampsToReturn: TimestampsToReturn.Neither
|
|
541
581
|
});
|
|
542
582
|
|
|
543
|
-
this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
583
|
+
return this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
544
584
|
/* c8 ignore next */
|
|
545
585
|
if (err) {
|
|
546
586
|
return callback(err);
|
|
@@ -631,33 +671,34 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
631
671
|
end: DateTime,
|
|
632
672
|
parameters: ExtraReadHistoryValueParameters
|
|
633
673
|
): Promise<HistoryReadResult>;
|
|
634
|
-
public readHistoryValue(...args:
|
|
635
|
-
const startTime = args[1];
|
|
636
|
-
const endTime = args[2];
|
|
674
|
+
public readHistoryValue(...args: unknown[]): unknown {
|
|
675
|
+
const startTime = args[1] as DateTime;
|
|
676
|
+
const endTime = args[2] as DateTime;
|
|
637
677
|
|
|
638
678
|
let options: ExtraReadHistoryValueParameters = {};
|
|
639
679
|
let callback = args[3];
|
|
640
680
|
if (typeof callback !== "function") {
|
|
641
|
-
options = args[3];
|
|
681
|
+
options = args[3] as ExtraReadHistoryValueParameters;
|
|
642
682
|
callback = args[4];
|
|
643
683
|
}
|
|
644
684
|
assert(typeof callback === "function");
|
|
685
|
+
const cb = callback as (err: Error | null, results?: HistoryReadResult[] | HistoryReadResult) => void;
|
|
645
686
|
|
|
646
687
|
// adjust parameters
|
|
647
688
|
options.numValuesPerNode = options.numValuesPerNode || 0;
|
|
648
|
-
options.returnBounds = options.returnBounds || options.returnBounds === undefined
|
|
689
|
+
options.returnBounds = !!(options.returnBounds || options.returnBounds === undefined);
|
|
649
690
|
options.isReadModified = options.isReadModified || false;
|
|
650
691
|
options.timestampsToReturn = options.timestampsToReturn ?? TimestampsToReturn.Both;
|
|
651
692
|
|
|
652
693
|
const arg0 = args[0];
|
|
653
694
|
const isArray = Array.isArray(arg0);
|
|
654
695
|
|
|
655
|
-
const nodes = isArray ? arg0 : [arg0];
|
|
696
|
+
const nodes: unknown[] = isArray ? (arg0 as unknown[]) : [arg0];
|
|
656
697
|
|
|
657
698
|
const nodesToRead: HistoryReadValueIdOptions[] = [];
|
|
658
699
|
|
|
659
|
-
for (const node of nodes) {
|
|
660
|
-
if (!node.nodeId) {
|
|
700
|
+
for (const node of nodes as (NodeIdLike | HistoryReadValueIdOptions2)[]) {
|
|
701
|
+
if (!(node as HistoryReadValueIdOptions2).nodeId) {
|
|
661
702
|
nodesToRead.push({
|
|
662
703
|
continuationPoint: undefined,
|
|
663
704
|
dataEncoding: undefined, // {namespaceIndex: 0, name: undefined},
|
|
@@ -687,30 +728,30 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
687
728
|
request.nodesToRead = request.nodesToRead || [];
|
|
688
729
|
|
|
689
730
|
assert(nodes.length === request.nodesToRead.length);
|
|
690
|
-
this.historyRead(request, (err: Error | null, response?: HistoryReadResponse) => {
|
|
731
|
+
return this.historyRead(request, (err: Error | null, response?: HistoryReadResponse) => {
|
|
691
732
|
/* c8 ignore next */
|
|
692
733
|
if (err) {
|
|
693
|
-
return
|
|
734
|
+
return cb(err);
|
|
694
735
|
}
|
|
695
736
|
/* c8 ignore next */
|
|
696
737
|
if (!response || !(response instanceof HistoryReadResponse)) {
|
|
697
|
-
return
|
|
738
|
+
return cb(new Error("Internal Error"));
|
|
698
739
|
}
|
|
699
740
|
response.results = response.results || [];
|
|
700
741
|
assert(nodes.length === response.results.length);
|
|
701
|
-
|
|
742
|
+
cb(null, isArray ? response.results : response.results[0]);
|
|
702
743
|
});
|
|
703
744
|
}
|
|
704
745
|
|
|
705
746
|
public historyRead(request: HistoryReadRequest, callback: Callback<HistoryReadResponse>): void;
|
|
706
747
|
public historyRead(request: HistoryReadRequest): Promise<HistoryReadResponse>;
|
|
707
|
-
public historyRead(request: HistoryReadRequest, callback?: CallbackT<HistoryReadResponse>):
|
|
748
|
+
public historyRead(request: HistoryReadRequest, callback?: CallbackT<HistoryReadResponse>): unknown {
|
|
708
749
|
/* c8 ignore next */
|
|
709
750
|
if (!callback) {
|
|
710
751
|
throw new Error("expecting a callback");
|
|
711
752
|
}
|
|
712
753
|
|
|
713
|
-
this.performMessageTransaction(request, (err: Error | null, response) => {
|
|
754
|
+
return this.performMessageTransaction(request, (err: Error | null, response) => {
|
|
714
755
|
/* c8 ignore next */
|
|
715
756
|
if (err) {
|
|
716
757
|
return callback(err);
|
|
@@ -814,9 +855,9 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
814
855
|
endTime: DateTime,
|
|
815
856
|
aggregateFn: AggregateFunction[] | AggregateFunction,
|
|
816
857
|
processingInterval: number,
|
|
817
|
-
...args:
|
|
818
|
-
):
|
|
819
|
-
const callback = typeof args[0] === "function" ? args[0] : args[1]
|
|
858
|
+
...args: unknown[]
|
|
859
|
+
): unknown {
|
|
860
|
+
const callback = (typeof args[0] === "function" ? args[0] : args[1]) as Callback<HistoryReadResult[] | HistoryReadResult>;
|
|
820
861
|
assert(typeof callback === "function");
|
|
821
862
|
const defaultAggregateFunction = {
|
|
822
863
|
percentDataBad: 100,
|
|
@@ -825,7 +866,9 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
825
866
|
useServerCapabilitiesDefaults: true,
|
|
826
867
|
useSlopedExtrapolation: false
|
|
827
868
|
};
|
|
828
|
-
const aggregateConfiguration =
|
|
869
|
+
const aggregateConfiguration = (
|
|
870
|
+
typeof args[0] === "function" ? defaultAggregateFunction : args[0]
|
|
871
|
+
) as AggregateConfigurationOptions;
|
|
829
872
|
|
|
830
873
|
const isArray = Array.isArray(arg0);
|
|
831
874
|
|
|
@@ -854,8 +897,8 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
854
897
|
timestampsToReturn: TimestampsToReturn.Both
|
|
855
898
|
});
|
|
856
899
|
|
|
857
|
-
assert(nodesToRead.length === request.nodesToRead
|
|
858
|
-
this.performMessageTransaction(request, (err: Error | null, response) => {
|
|
900
|
+
assert(nodesToRead.length === request.nodesToRead?.length);
|
|
901
|
+
return this.performMessageTransaction(request, (err: Error | null, response) => {
|
|
859
902
|
/* c8 ignore next */
|
|
860
903
|
if (err) {
|
|
861
904
|
return callback(err);
|
|
@@ -984,17 +1027,17 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
984
1027
|
* @internal
|
|
985
1028
|
* @param args
|
|
986
1029
|
*/
|
|
987
|
-
public write(...args:
|
|
1030
|
+
public write(...args: unknown[]): unknown {
|
|
988
1031
|
const arg0 = args[0];
|
|
989
1032
|
const isArray = Array.isArray(arg0);
|
|
990
|
-
const nodesToWrite = isArray ? arg0 : [arg0];
|
|
1033
|
+
const nodesToWrite: WriteValueOptions[] = isArray ? (arg0 as WriteValueOptions[]) : [arg0 as WriteValueOptions];
|
|
991
1034
|
|
|
992
|
-
const callback = args[1];
|
|
1035
|
+
const callback = args[1] as (err: Error | null, results?: StatusCode[] | StatusCode | Response) => void;
|
|
993
1036
|
assert(typeof callback === "function");
|
|
994
1037
|
|
|
995
1038
|
const request = new WriteRequest({ nodesToWrite });
|
|
996
1039
|
|
|
997
|
-
this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
1040
|
+
return this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
998
1041
|
/* c8 ignore next */
|
|
999
1042
|
if (err) {
|
|
1000
1043
|
return callback(err, response);
|
|
@@ -1051,10 +1094,10 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1051
1094
|
|
|
1052
1095
|
public writeSingleNode(nodeId: NodeIdLike, value: VariantLike): Promise<StatusCode>;
|
|
1053
1096
|
|
|
1054
|
-
public writeSingleNode(...args:
|
|
1097
|
+
public writeSingleNode(...args: unknown[]): unknown {
|
|
1055
1098
|
const nodeId = args[0] as NodeIdLike;
|
|
1056
1099
|
const value = args[1] as VariantLike;
|
|
1057
|
-
const callback = args[2]
|
|
1100
|
+
const callback = args[2] as ResponseCallback<StatusCode>;
|
|
1058
1101
|
|
|
1059
1102
|
assert(typeof callback === "function");
|
|
1060
1103
|
|
|
@@ -1065,7 +1108,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1065
1108
|
value: new DataValue({ value })
|
|
1066
1109
|
});
|
|
1067
1110
|
|
|
1068
|
-
this.write(nodeToWrite, (err, statusCode) => {
|
|
1111
|
+
return this.write(nodeToWrite, (err, statusCode) => {
|
|
1069
1112
|
/* c8 ignore next */
|
|
1070
1113
|
if (err) {
|
|
1071
1114
|
return callback(err);
|
|
@@ -1100,11 +1143,11 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1100
1143
|
|
|
1101
1144
|
public readAllAttributes(nodes: NodeIdLike[], callback: (err: Error | null, data?: NodeAttributes[]) => void): void;
|
|
1102
1145
|
|
|
1103
|
-
public readAllAttributes(...args:
|
|
1146
|
+
public readAllAttributes(...args: unknown[]): void {
|
|
1104
1147
|
const nodes = args[0] as NodeIdLike[];
|
|
1105
1148
|
const callback = args[1] as (err: Error | null, data?: NodeAttributes[]) => void;
|
|
1106
1149
|
readAllAttributes(this, nodes)
|
|
1107
|
-
.then((data:
|
|
1150
|
+
.then((data: NodeAttributes[]) => callback(null, data))
|
|
1108
1151
|
.catch((err: Error) => callback(err));
|
|
1109
1152
|
}
|
|
1110
1153
|
|
|
@@ -1172,28 +1215,31 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1172
1215
|
* @internal
|
|
1173
1216
|
* @param args
|
|
1174
1217
|
*/
|
|
1175
|
-
public read(...args:
|
|
1218
|
+
public read(...args: unknown[]): unknown {
|
|
1176
1219
|
if (args.length === 2) {
|
|
1177
|
-
return this.read(args[0], 0, args[1]);
|
|
1220
|
+
return this.read(args[0] as ReadValueIdOptions, 0, args[1] as ResponseCallback<DataValue>);
|
|
1178
1221
|
}
|
|
1179
1222
|
assert(args.length === 3);
|
|
1180
1223
|
|
|
1181
1224
|
const isArray = Array.isArray(args[0]);
|
|
1182
1225
|
|
|
1183
|
-
const nodesToRead = isArray ? args[0] : [args[0]];
|
|
1226
|
+
const nodesToRead: ReadValueIdOptions[] = isArray ? (args[0] as ReadValueIdOptions[]) : [args[0] as ReadValueIdOptions];
|
|
1184
1227
|
|
|
1185
1228
|
assert(Array.isArray(nodesToRead));
|
|
1186
1229
|
|
|
1187
|
-
const maxAge = args[1];
|
|
1230
|
+
const maxAge = args[1] as number;
|
|
1188
1231
|
|
|
1189
|
-
const callback = args[2];
|
|
1232
|
+
const callback = args[2] as (err: Error | null, results?: DataValue[] | DataValue | Response) => void;
|
|
1190
1233
|
assert(typeof callback === "function");
|
|
1191
1234
|
|
|
1192
1235
|
/* c8 ignore next */
|
|
1193
1236
|
if (helpAPIChange) {
|
|
1194
1237
|
// the read method deprecation detection and warning
|
|
1195
1238
|
if (
|
|
1196
|
-
!(
|
|
1239
|
+
!(
|
|
1240
|
+
getFunctionParameterNames(callback as unknown as (...args: unknown[]) => void)[1] === "dataValues" ||
|
|
1241
|
+
getFunctionParameterNames(callback as unknown as (...args: unknown[]) => void)[1] === "dataValue"
|
|
1242
|
+
)
|
|
1197
1243
|
) {
|
|
1198
1244
|
warningLog(chalk.red("[NODE-OPCUA-E04] the ClientSession#read API has changed !!, please fix the client code"));
|
|
1199
1245
|
warningLog(chalk.red(" replace ..:"));
|
|
@@ -1206,7 +1252,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1206
1252
|
"please make sure to refactor your code and check that " +
|
|
1207
1253
|
"the second argument of your callback function is named"
|
|
1208
1254
|
),
|
|
1209
|
-
chalk.cyan(
|
|
1255
|
+
chalk.cyan(`dataValue${isArray ? "s" : ""}`)
|
|
1210
1256
|
);
|
|
1211
1257
|
warningLog(chalk.cyan("to make this exception disappear"));
|
|
1212
1258
|
throw new Error("ERROR ClientSession#read API has changed !!, please fix the client code");
|
|
@@ -1215,7 +1261,9 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1215
1261
|
|
|
1216
1262
|
// coerce nodeIds
|
|
1217
1263
|
for (const node of nodesToRead) {
|
|
1218
|
-
|
|
1264
|
+
if (node.nodeId) {
|
|
1265
|
+
node.nodeId = this.resolveNodeId(node.nodeId);
|
|
1266
|
+
}
|
|
1219
1267
|
}
|
|
1220
1268
|
|
|
1221
1269
|
const request = new ReadRequest({
|
|
@@ -1224,7 +1272,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1224
1272
|
timestampsToReturn: TimestampsToReturn.Both
|
|
1225
1273
|
});
|
|
1226
1274
|
|
|
1227
|
-
this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
1275
|
+
return this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
1228
1276
|
/* c8 ignore next */
|
|
1229
1277
|
if (err) {
|
|
1230
1278
|
return callback(err, response);
|
|
@@ -1236,7 +1284,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1236
1284
|
}
|
|
1237
1285
|
|
|
1238
1286
|
// perform ExtensionObject resolution
|
|
1239
|
-
promoteOpaqueStructure(this, response.results
|
|
1287
|
+
promoteOpaqueStructure(this, response.results || [])
|
|
1240
1288
|
.then(() => {
|
|
1241
1289
|
response.results = response.results || /* c8 ignore next */ [];
|
|
1242
1290
|
callback(null, isArray ? response.results : response.results[0]);
|
|
@@ -1249,17 +1297,20 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1249
1297
|
|
|
1250
1298
|
public emitCloseEvent(statusCode: StatusCode): void {
|
|
1251
1299
|
if (!this._closeEventHasBeenEmitted) {
|
|
1252
|
-
|
|
1300
|
+
// c8 ignore next
|
|
1301
|
+
doDebug && debugLog("ClientSession#emitCloseEvent");
|
|
1253
1302
|
this._closeEventHasBeenEmitted = true;
|
|
1254
1303
|
this.emit("session_closed", statusCode);
|
|
1255
1304
|
}
|
|
1256
1305
|
}
|
|
1257
1306
|
|
|
1307
|
+
public createSubscription(options: CreateSubscriptionRequestLike, callback: ResponseCallback<CreateSubscriptionResponse>): void;
|
|
1308
|
+
public createSubscription(options: CreateSubscriptionRequestLike): Promise<CreateSubscriptionResponse>;
|
|
1258
1309
|
public createSubscription(
|
|
1259
1310
|
options: CreateSubscriptionRequestLike,
|
|
1260
1311
|
callback?: ResponseCallback<CreateSubscriptionResponse>
|
|
1261
|
-
):
|
|
1262
|
-
this._defaultRequest(CreateSubscriptionRequest, CreateSubscriptionResponse, options, callback);
|
|
1312
|
+
): unknown {
|
|
1313
|
+
return this._defaultRequest(CreateSubscriptionRequest, CreateSubscriptionResponse, options, callback);
|
|
1263
1314
|
}
|
|
1264
1315
|
|
|
1265
1316
|
/**
|
|
@@ -1279,12 +1330,11 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1279
1330
|
createSubscriptionRequest: CreateSubscriptionRequestLike,
|
|
1280
1331
|
callback: (err: Error | null, subscription?: ClientSubscription) => void
|
|
1281
1332
|
): void;
|
|
1282
|
-
public createSubscription2(...args:
|
|
1333
|
+
public createSubscription2(...args: unknown[]): unknown {
|
|
1283
1334
|
const createSubscriptionRequest = args[0] as CreateSubscriptionRequestLike;
|
|
1284
|
-
let callback = args[1];
|
|
1335
|
+
let callback = args[1] as ((err: Error | null, subscription?: ClientSubscription) => void) | null;
|
|
1285
1336
|
const subscription = new ClientSubscriptionImpl(this, createSubscriptionRequest);
|
|
1286
1337
|
|
|
1287
|
-
// tslint:disable-next-line:no-empty
|
|
1288
1338
|
subscription.on("error", (err) => {
|
|
1289
1339
|
if (callback) {
|
|
1290
1340
|
callback(err);
|
|
@@ -1298,17 +1348,18 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1298
1348
|
callback = null;
|
|
1299
1349
|
}
|
|
1300
1350
|
});
|
|
1351
|
+
return undefined;
|
|
1301
1352
|
}
|
|
1302
1353
|
|
|
1303
1354
|
public deleteSubscriptions(
|
|
1304
1355
|
options: DeleteSubscriptionsRequestLike,
|
|
1305
1356
|
callback?: ResponseCallback<DeleteSubscriptionsResponse>
|
|
1306
|
-
):
|
|
1307
|
-
this._defaultRequest(DeleteSubscriptionsRequest, DeleteSubscriptionsResponse, options, callback);
|
|
1357
|
+
): unknown {
|
|
1358
|
+
return this._defaultRequest(DeleteSubscriptionsRequest, DeleteSubscriptionsResponse, options, callback);
|
|
1308
1359
|
}
|
|
1309
1360
|
|
|
1310
|
-
public setTriggering(request: SetTriggeringRequestOptions, callback?: ResponseCallback<SetTriggeringResponse>):
|
|
1311
|
-
this._defaultRequest(SetTriggeringRequest, SetTriggeringResponse, request, callback);
|
|
1361
|
+
public setTriggering(request: SetTriggeringRequestOptions, callback?: ResponseCallback<SetTriggeringResponse>): unknown {
|
|
1362
|
+
return this._defaultRequest(SetTriggeringRequest, SetTriggeringResponse, request, callback);
|
|
1312
1363
|
}
|
|
1313
1364
|
|
|
1314
1365
|
/**
|
|
@@ -1316,22 +1367,27 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1316
1367
|
public transferSubscriptions(
|
|
1317
1368
|
options: TransferSubscriptionsRequestLike,
|
|
1318
1369
|
callback?: ResponseCallback<TransferSubscriptionsResponse>
|
|
1319
|
-
):
|
|
1320
|
-
this._defaultRequest(TransferSubscriptionsRequest, TransferSubscriptionsResponse, options, callback);
|
|
1370
|
+
): unknown {
|
|
1371
|
+
return this._defaultRequest(TransferSubscriptionsRequest, TransferSubscriptionsResponse, options, callback);
|
|
1321
1372
|
}
|
|
1322
1373
|
|
|
1374
|
+
public createMonitoredItems(
|
|
1375
|
+
options: CreateMonitoredItemsRequestLike,
|
|
1376
|
+
callback: ResponseCallback<CreateMonitoredItemsResponse>
|
|
1377
|
+
): void;
|
|
1378
|
+
public createMonitoredItems(options: CreateMonitoredItemsRequestLike): Promise<CreateMonitoredItemsResponse>;
|
|
1323
1379
|
public createMonitoredItems(
|
|
1324
1380
|
options: CreateMonitoredItemsRequestLike,
|
|
1325
1381
|
callback?: ResponseCallback<CreateMonitoredItemsResponse>
|
|
1326
|
-
):
|
|
1327
|
-
this._defaultRequest(CreateMonitoredItemsRequest, CreateMonitoredItemsResponse, options, callback);
|
|
1382
|
+
): unknown {
|
|
1383
|
+
return this._defaultRequest(CreateMonitoredItemsRequest, CreateMonitoredItemsResponse, options, callback);
|
|
1328
1384
|
}
|
|
1329
1385
|
|
|
1330
1386
|
public modifyMonitoredItems(
|
|
1331
1387
|
options: ModifyMonitoredItemsRequestLike,
|
|
1332
1388
|
callback?: ResponseCallback<ModifyMonitoredItemsResponse>
|
|
1333
|
-
):
|
|
1334
|
-
this._defaultRequest(ModifyMonitoredItemsRequest, ModifyMonitoredItemsResponse, options, callback);
|
|
1389
|
+
): unknown {
|
|
1390
|
+
return this._defaultRequest(ModifyMonitoredItemsRequest, ModifyMonitoredItemsResponse, options, callback);
|
|
1335
1391
|
}
|
|
1336
1392
|
|
|
1337
1393
|
/**
|
|
@@ -1340,12 +1396,15 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1340
1396
|
public modifySubscription(
|
|
1341
1397
|
options: ModifySubscriptionRequestLike,
|
|
1342
1398
|
callback?: ResponseCallback<ModifySubscriptionResponse>
|
|
1343
|
-
):
|
|
1344
|
-
this._defaultRequest(ModifySubscriptionRequest, ModifySubscriptionResponse, options, callback);
|
|
1399
|
+
): unknown {
|
|
1400
|
+
return this._defaultRequest(ModifySubscriptionRequest, ModifySubscriptionResponse, options, callback);
|
|
1345
1401
|
}
|
|
1346
1402
|
|
|
1347
|
-
public setMonitoringMode(
|
|
1348
|
-
|
|
1403
|
+
public setMonitoringMode(
|
|
1404
|
+
options: SetMonitoringModeRequestLike,
|
|
1405
|
+
callback?: ResponseCallback<SetMonitoringModeResponse>
|
|
1406
|
+
): unknown {
|
|
1407
|
+
return this._defaultRequest(SetMonitoringModeRequest, SetMonitoringModeResponse, options, callback);
|
|
1349
1408
|
}
|
|
1350
1409
|
|
|
1351
1410
|
/**
|
|
@@ -1389,11 +1448,11 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1389
1448
|
/**
|
|
1390
1449
|
* @internal
|
|
1391
1450
|
*/
|
|
1392
|
-
public setPublishingMode(...args:
|
|
1393
|
-
const publishingEnabled = args[0];
|
|
1451
|
+
public setPublishingMode(...args: unknown[]): unknown {
|
|
1452
|
+
const publishingEnabled = args[0] as boolean;
|
|
1394
1453
|
const isArray = Array.isArray(args[1]);
|
|
1395
|
-
const subscriptionIds = isArray ? args[1] : [args[1]];
|
|
1396
|
-
const callback = args[2];
|
|
1454
|
+
const subscriptionIds: SubscriptionId[] = isArray ? (args[1] as SubscriptionId[]) : [args[1] as SubscriptionId];
|
|
1455
|
+
const callback = args[2] as (err: Error | null, statusCode?: StatusCode[] | StatusCode) => void;
|
|
1397
1456
|
|
|
1398
1457
|
assert(typeof callback === "function");
|
|
1399
1458
|
assert(publishingEnabled === true || publishingEnabled === false);
|
|
@@ -1403,7 +1462,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1403
1462
|
subscriptionIds
|
|
1404
1463
|
});
|
|
1405
1464
|
|
|
1406
|
-
this._defaultRequest(
|
|
1465
|
+
return this._defaultRequest(
|
|
1407
1466
|
SetPublishingModeRequest,
|
|
1408
1467
|
SetPublishingModeResponse,
|
|
1409
1468
|
options,
|
|
@@ -1434,16 +1493,16 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1434
1493
|
* @internal
|
|
1435
1494
|
* @param args
|
|
1436
1495
|
*/
|
|
1437
|
-
public translateBrowsePath(...args:
|
|
1496
|
+
public translateBrowsePath(...args: unknown[]): unknown {
|
|
1438
1497
|
const isArray = Array.isArray(args[0]);
|
|
1439
|
-
const browsePaths = isArray ? args[0] : [args[0]];
|
|
1498
|
+
const browsePaths: BrowsePath[] = isArray ? (args[0] as BrowsePath[]) : [args[0] as BrowsePath];
|
|
1440
1499
|
|
|
1441
|
-
const callback = args[1];
|
|
1500
|
+
const callback = args[1] as (err: Error | null, results?: BrowsePathResult[] | BrowsePathResult | Response) => void;
|
|
1442
1501
|
assert(typeof callback === "function");
|
|
1443
1502
|
|
|
1444
1503
|
const request = new TranslateBrowsePathsToNodeIdsRequest({ browsePaths });
|
|
1445
1504
|
|
|
1446
|
-
this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
1505
|
+
return this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
1447
1506
|
/* c8 ignore next */
|
|
1448
1507
|
if (err) {
|
|
1449
1508
|
return callback(err, response);
|
|
@@ -1459,33 +1518,41 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1459
1518
|
}
|
|
1460
1519
|
|
|
1461
1520
|
public channelId(): number {
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
: -1;
|
|
1521
|
+
const secureChannel = this._client?._secureChannel;
|
|
1522
|
+
return secureChannel?.isOpened() ? secureChannel.channelId : -1;
|
|
1465
1523
|
}
|
|
1466
1524
|
public isChannelValid(): boolean {
|
|
1467
1525
|
/* c8 ignore next */
|
|
1468
1526
|
if (!this._client) {
|
|
1469
|
-
|
|
1527
|
+
// c8 ignore next
|
|
1528
|
+
doDebug && debugLog(chalk.red("Warning SessionClient is null ?"));
|
|
1470
1529
|
}
|
|
1471
1530
|
|
|
1472
|
-
return this._client
|
|
1531
|
+
return !!this._client?._secureChannel?.isOpened();
|
|
1473
1532
|
}
|
|
1474
1533
|
|
|
1475
1534
|
public performMessageTransaction(request: Request, callback: (err: Error | null, response?: Response) => void): void {
|
|
1476
1535
|
if (!this._client) {
|
|
1477
1536
|
// session may have been closed by user ... but is still in used !!
|
|
1478
|
-
|
|
1537
|
+
callback(new Error("Session has been closed and should not be used to perform a transaction anymore"));
|
|
1538
|
+
return;
|
|
1479
1539
|
}
|
|
1480
1540
|
if (
|
|
1481
1541
|
request instanceof PublishRequest ||
|
|
1482
1542
|
request instanceof ActivateSessionRequest ||
|
|
1483
1543
|
request instanceof CloseSessionRequest
|
|
1484
1544
|
) {
|
|
1485
|
-
|
|
1545
|
+
this._performMessageTransaction(request, callback);
|
|
1546
|
+
return;
|
|
1486
1547
|
}
|
|
1487
1548
|
|
|
1488
|
-
|
|
1549
|
+
// Hold the transaction only while the channel is genuinely down and a repair is under
|
|
1550
|
+
// way. The repair restores the session *after* the secure channel is back up
|
|
1551
|
+
// (_repairConnection: _recreate_secure_channel, then _finalReconnectionStep), so its own
|
|
1552
|
+
// traffic - including the plain Read that readOperationLimits issues - always sees a
|
|
1553
|
+
// valid channel and passes straight through. Queueing on "reconnecting" alone would
|
|
1554
|
+
// park the repair's requests behind the repair that is waiting for them.
|
|
1555
|
+
if (!this.isChannelValid() && (this._reconnecting.reconnecting || this._client.isReconnecting)) {
|
|
1489
1556
|
/* c8 ignore next */
|
|
1490
1557
|
if (this._reconnecting.pendingTransactions.length > 10) {
|
|
1491
1558
|
if (!pendingTransactionMessageDisplayed) {
|
|
@@ -1493,7 +1560,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1493
1560
|
warningLog(
|
|
1494
1561
|
"[NODE-OPCUA-W21]",
|
|
1495
1562
|
"Pending transactions: ",
|
|
1496
|
-
this._reconnecting.pendingTransactions.map((a
|
|
1563
|
+
this._reconnecting.pendingTransactions.map((a) => a.request.constructor.name).join(" ")
|
|
1497
1564
|
);
|
|
1498
1565
|
warningLog(
|
|
1499
1566
|
"[NODE-OPCUA-W22]",
|
|
@@ -1506,12 +1573,14 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1506
1573
|
);
|
|
1507
1574
|
}
|
|
1508
1575
|
} else if (this._reconnecting.pendingTransactions.length > 3) {
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1576
|
+
// c8 ignore next
|
|
1577
|
+
doDebug &&
|
|
1578
|
+
debugLog(
|
|
1579
|
+
chalk.yellow(
|
|
1580
|
+
"Warning : your client is sending multiple requests simultaneously to the server",
|
|
1581
|
+
request.constructor.name
|
|
1582
|
+
)
|
|
1583
|
+
);
|
|
1515
1584
|
}
|
|
1516
1585
|
this._reconnecting.pendingTransactions.push({ request, callback });
|
|
1517
1586
|
return;
|
|
@@ -1522,7 +1591,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1522
1591
|
attemptCount > 0 &&
|
|
1523
1592
|
warningLog("reprocessRequest => ", request.constructor.name, this._reconnecting.pendingTransactions.length);
|
|
1524
1593
|
this._performMessageTransaction(request, (err: null | Error, response?: Response) => {
|
|
1525
|
-
if (err
|
|
1594
|
+
if (err?.message.match(/BadSessionIdInvalid/) && request.constructor.name !== "ActivateSessionRequest") {
|
|
1526
1595
|
warningLog(
|
|
1527
1596
|
"Transaction on Invalid Session ",
|
|
1528
1597
|
request.constructor.name,
|
|
@@ -1534,62 +1603,105 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1534
1603
|
);
|
|
1535
1604
|
request.requestHeader.requestHandle = requestHandleNotSetValue;
|
|
1536
1605
|
if (this.isReconnecting) {
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1606
|
+
// Hand it back to the queue rather than parking it on a one-shot
|
|
1607
|
+
// session_restored listener: that event is emitted only when a repair
|
|
1608
|
+
// succeeds, so a repair that gave up - or a dispose, which drops every
|
|
1609
|
+
// listener - left the caller waiting for an answer that could never come.
|
|
1610
|
+
// flushPendingTransactions is called on every exit from a repair, so the
|
|
1611
|
+
// transaction is always resolved one way or the other.
|
|
1612
|
+
// c8 ignore next
|
|
1613
|
+
doDebug && debugLog("holding for replay after repair:", request.constructor.name, "attempt", attemptCount);
|
|
1614
|
+
this._reconnecting.pendingTransactions.push({ request, callback });
|
|
1541
1615
|
} else {
|
|
1542
1616
|
this.#_recreate_session_and_reperform_transaction(request, callback);
|
|
1543
1617
|
}
|
|
1544
1618
|
return;
|
|
1545
1619
|
}
|
|
1620
|
+
// the queue is owned by flushPendingTransactions, which the repair calls on every
|
|
1621
|
+
// exit: draining one entry from here would send it before the session is restored,
|
|
1622
|
+
// and would race with that flush.
|
|
1546
1623
|
callback(err, response);
|
|
1547
|
-
const length = this._reconnecting.pendingTransactions.length; // record length before callback is called !
|
|
1548
|
-
if (length > 0) {
|
|
1549
|
-
debugLog("reprocessRequest => ", this._reconnecting.pendingTransactions.length, " transaction(s) left in queue");
|
|
1550
|
-
// tslint:disable-next-line: no-shadowed-variable
|
|
1551
|
-
const { request, callback } = this._reconnecting.pendingTransactions.shift();
|
|
1552
|
-
this.#reprocessRequest(0, request, callback);
|
|
1553
|
-
}
|
|
1554
1624
|
});
|
|
1555
1625
|
}
|
|
1556
1626
|
|
|
1627
|
+
/**
|
|
1628
|
+
* record that the server has answered.
|
|
1629
|
+
*
|
|
1630
|
+
* A transaction that failed on a timeout or on a broken channel comes back with no response
|
|
1631
|
+
* at all and must not refresh lastResponseReceivedTime, or the keep-alive manager would never
|
|
1632
|
+
* notice that the server is gone (see #1569). A ServiceFault does count - the round trip
|
|
1633
|
+
* completed - but the channel reports it as an Error carrying the decoded fault on
|
|
1634
|
+
* err.response, so the response argument alone does not tell the two cases apart.
|
|
1635
|
+
*
|
|
1636
|
+
* @internal
|
|
1637
|
+
*/
|
|
1638
|
+
/**
|
|
1639
|
+
* resolve every transaction that was held while the connection was down: replay them when the
|
|
1640
|
+
* session is usable again, fail them when the repair gave up.
|
|
1641
|
+
*
|
|
1642
|
+
* Every exit from a repair must call this, otherwise a held caller waits for an answer that
|
|
1643
|
+
* can never come - and the session is disposed with a queue that nobody drained.
|
|
1644
|
+
*
|
|
1645
|
+
* @internal
|
|
1646
|
+
*/
|
|
1647
|
+
public flushPendingTransactions(err: Error | null): void {
|
|
1648
|
+
const heldTransactions = this._reconnecting.pendingTransactions.splice(0);
|
|
1649
|
+
if (heldTransactions.length === 0) {
|
|
1650
|
+
return;
|
|
1651
|
+
}
|
|
1652
|
+
// c8 ignore next
|
|
1653
|
+
doDebug && debugLog("flushPendingTransactions", heldTransactions.length, err ? `failing: ${err.message}` : "replaying");
|
|
1654
|
+
pendingTransactionMessageDisplayed = false;
|
|
1655
|
+
for (const pending of heldTransactions) {
|
|
1656
|
+
if (err) {
|
|
1657
|
+
pending.callback(err);
|
|
1658
|
+
} else {
|
|
1659
|
+
this.#reprocessRequest(0, pending.request, pending.callback);
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1664
|
+
public noteServerAnswer(err: Error | null, response?: Response): void {
|
|
1665
|
+
if (response || (err as ServiceFaultAnnotatedError)?.response) {
|
|
1666
|
+
this.lastResponseReceivedTime = new Date();
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1557
1670
|
public _performMessageTransaction(request: Request, callback: (err: Error | null, response?: Response) => void): void {
|
|
1558
1671
|
assert(typeof callback === "function");
|
|
1559
1672
|
|
|
1560
1673
|
/* c8 ignore next */
|
|
1561
1674
|
if (!this._client) {
|
|
1562
1675
|
// session may have been closed by user ... but is still in used !!
|
|
1563
|
-
|
|
1676
|
+
callback(new Error("Session has been closed and should not be used to perform a transaction anymore"));
|
|
1677
|
+
return;
|
|
1564
1678
|
}
|
|
1565
1679
|
|
|
1566
1680
|
if (!this.isChannelValid()) {
|
|
1567
1681
|
// the secure channel is broken, may be the server has crashed or the network cable has been disconnected
|
|
1568
1682
|
// for a long time
|
|
1569
1683
|
// we may need to queue this transaction, as a secure token may be being reprocessed
|
|
1570
|
-
|
|
1571
|
-
|
|
1684
|
+
// c8 ignore next
|
|
1685
|
+
doDebug && debugLog(chalk.bgWhite.red("!!! Performing transaction on invalid channel !!! ", request.constructor.name));
|
|
1686
|
+
callback(new Error("Invalid Channel BadConnectionClosed"));
|
|
1687
|
+
return;
|
|
1572
1688
|
}
|
|
1573
1689
|
|
|
1574
1690
|
// is this stuff useful?
|
|
1575
1691
|
if (request.requestHeader) {
|
|
1576
|
-
|
|
1692
|
+
if (!this.authenticationToken) {
|
|
1693
|
+
throw new Error("internal error: authenticationToken should be set on an active session");
|
|
1694
|
+
}
|
|
1695
|
+
request.requestHeader.authenticationToken = this.authenticationToken;
|
|
1577
1696
|
}
|
|
1578
1697
|
|
|
1579
1698
|
this.lastRequestSentTime = new Date();
|
|
1580
1699
|
|
|
1581
1700
|
this._client.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
1582
|
-
this.
|
|
1701
|
+
this.noteServerAnswer(err, response);
|
|
1583
1702
|
|
|
1584
|
-
/* c8 ignore next */
|
|
1585
1703
|
if (err) {
|
|
1586
|
-
|
|
1587
|
-
(err as any).serviceDiagnostics = response.responseHeader.serviceDiagnostics;
|
|
1588
|
-
}
|
|
1589
|
-
if (response && (response as any).diagnosticInfos) {
|
|
1590
|
-
(err as any).diagnosticsInfo = (response as any).diagnosticInfos;
|
|
1591
|
-
}
|
|
1592
|
-
return callback(err);
|
|
1704
|
+
return callback(annotateWithDiagnostics(err, response));
|
|
1593
1705
|
}
|
|
1594
1706
|
|
|
1595
1707
|
/* c8 ignore next */
|
|
@@ -1597,22 +1709,14 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1597
1709
|
return callback(new Error("internal Error"));
|
|
1598
1710
|
}
|
|
1599
1711
|
|
|
1600
|
-
/* c8 ignore next */
|
|
1601
1712
|
if (response.responseHeader.serviceResult.isNot(StatusCodes.Good)) {
|
|
1602
|
-
|
|
1713
|
+
const serviceResultError = new Error(
|
|
1603
1714
|
" ServiceResult is " +
|
|
1604
1715
|
response.responseHeader.serviceResult.toString() +
|
|
1605
1716
|
" request was " +
|
|
1606
1717
|
request.constructor.name
|
|
1607
1718
|
);
|
|
1608
|
-
|
|
1609
|
-
if (response && response.responseHeader.serviceDiagnostics) {
|
|
1610
|
-
(err as any).serviceDiagnostics = response.responseHeader.serviceDiagnostics;
|
|
1611
|
-
}
|
|
1612
|
-
if (response && (response as any).diagnosticInfos) {
|
|
1613
|
-
(err as any).diagnosticsInfo = (response as any).diagnosticInfos;
|
|
1614
|
-
}
|
|
1615
|
-
return callback(err, response);
|
|
1719
|
+
return callback(annotateWithDiagnostics(serviceResultError, response), response);
|
|
1616
1720
|
}
|
|
1617
1721
|
return callback(null, response);
|
|
1618
1722
|
});
|
|
@@ -1644,7 +1748,12 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1644
1748
|
*/
|
|
1645
1749
|
public evaluateRemainingLifetime(): number {
|
|
1646
1750
|
const now = Date.now();
|
|
1647
|
-
|
|
1751
|
+
// anchored on the last answer, not the last send: the server restarts its session
|
|
1752
|
+
// watchdog when it *receives* a request, and the only proof the client has that a
|
|
1753
|
+
// request arrived is an answer coming back. Anchoring on the send made this return a
|
|
1754
|
+
// full lifetime throughout an outage - a client that keeps trying keeps refreshing the
|
|
1755
|
+
// send timestamp - which is precisely when the caller needs the truth (see #1569).
|
|
1756
|
+
const expiryTime = this.lastResponseReceivedTime.getTime() + this.timeout;
|
|
1648
1757
|
return Math.max(0, expiryTime - now);
|
|
1649
1758
|
}
|
|
1650
1759
|
|
|
@@ -1668,29 +1777,32 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1668
1777
|
* @internal
|
|
1669
1778
|
* @param args
|
|
1670
1779
|
*/
|
|
1671
|
-
public close(...args:
|
|
1672
|
-
if (
|
|
1673
|
-
return this.close(true, args[0]);
|
|
1780
|
+
public close(...args: unknown[]): unknown {
|
|
1781
|
+
if (args.length === 1) {
|
|
1782
|
+
return this.close(true, args[0] as ErrorCallback);
|
|
1674
1783
|
}
|
|
1675
1784
|
|
|
1676
1785
|
const deleteSubscription = args[0];
|
|
1677
|
-
const callback = args[1];
|
|
1786
|
+
const callback = args[1] as ErrorCallback;
|
|
1678
1787
|
|
|
1679
1788
|
assert(typeof callback === "function");
|
|
1680
1789
|
assert(typeof deleteSubscription === "boolean");
|
|
1681
1790
|
|
|
1682
1791
|
/* c8 ignore next */
|
|
1683
1792
|
if (!this._client) {
|
|
1684
|
-
|
|
1793
|
+
// c8 ignore next
|
|
1794
|
+
doDebug && debugLog("ClientSession#close : warning, client is already closed");
|
|
1685
1795
|
return callback(); // already close ?
|
|
1686
1796
|
}
|
|
1687
1797
|
assert(this._client);
|
|
1688
1798
|
|
|
1689
1799
|
this._terminatePublishEngine();
|
|
1690
|
-
this._client.closeSession(this, deleteSubscription, (err?: Error) => {
|
|
1691
|
-
|
|
1800
|
+
this._client.closeSession(this, deleteSubscription as boolean, (err?: Error) => {
|
|
1801
|
+
// c8 ignore next
|
|
1802
|
+
doDebug && debugLog("session Close err ", err ? err.message : "null");
|
|
1692
1803
|
callback();
|
|
1693
1804
|
});
|
|
1805
|
+
return undefined;
|
|
1694
1806
|
}
|
|
1695
1807
|
|
|
1696
1808
|
/**
|
|
@@ -1709,12 +1821,14 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1709
1821
|
* @internal
|
|
1710
1822
|
* @param args
|
|
1711
1823
|
*/
|
|
1712
|
-
public call(...args:
|
|
1824
|
+
public call(...args: unknown[]): unknown {
|
|
1713
1825
|
const isArray = Array.isArray(args[0]);
|
|
1714
|
-
const methodsToCall
|
|
1826
|
+
const methodsToCall: CallMethodRequestLike[] = isArray
|
|
1827
|
+
? (args[0] as CallMethodRequestLike[])
|
|
1828
|
+
: [args[0] as CallMethodRequestLike];
|
|
1715
1829
|
assert(Array.isArray(methodsToCall));
|
|
1716
1830
|
|
|
1717
|
-
const callback = args[1]
|
|
1831
|
+
const callback = args[1] as ResponseCallback<CallMethodResult[] | CallMethodResult>;
|
|
1718
1832
|
|
|
1719
1833
|
// Note : The client has no explicit address space and therefore will struggle to
|
|
1720
1834
|
// access the method arguments signature.
|
|
@@ -1724,7 +1838,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1724
1838
|
// const request = this._client.factory.constructObjectId("CallRequest",{ methodsToCall: methodsToCall});
|
|
1725
1839
|
const request = new CallRequest({ methodsToCall });
|
|
1726
1840
|
|
|
1727
|
-
this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
1841
|
+
return this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
1728
1842
|
/* c8 ignore next */
|
|
1729
1843
|
if (err) {
|
|
1730
1844
|
return callback(err);
|
|
@@ -1734,11 +1848,12 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1734
1848
|
if (!response || !(response instanceof CallResponse)) {
|
|
1735
1849
|
return callback(new Error("internal error"));
|
|
1736
1850
|
}
|
|
1737
|
-
|
|
1851
|
+
const results: CallMethodResult[] = response.results || [];
|
|
1852
|
+
response.results = results;
|
|
1738
1853
|
|
|
1739
|
-
promoteOpaqueStructureForCall(this,
|
|
1854
|
+
promoteOpaqueStructureForCall(this, results)
|
|
1740
1855
|
.then(() => {
|
|
1741
|
-
callback(null, isArray ?
|
|
1856
|
+
callback(null, isArray ? results : results[0]);
|
|
1742
1857
|
})
|
|
1743
1858
|
.catch((err) => {
|
|
1744
1859
|
callback(err);
|
|
@@ -1757,9 +1872,9 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1757
1872
|
|
|
1758
1873
|
public async getMonitoredItems(subscriptionId: SubscriptionId): Promise<MonitoredItemData>;
|
|
1759
1874
|
public getMonitoredItems(subscriptionId: SubscriptionId, callback: ResponseCallback<MonitoredItemData>): void;
|
|
1760
|
-
public getMonitoredItems(...args:
|
|
1875
|
+
public getMonitoredItems(...args: unknown[]): unknown {
|
|
1761
1876
|
const subscriptionId = args[0] as SubscriptionId;
|
|
1762
|
-
const callback = args[1]
|
|
1877
|
+
const callback = args[1] as ResponseCallback<MonitoredItemData>;
|
|
1763
1878
|
// <UAObject NodeId="i=2253" BrowseName="Server">
|
|
1764
1879
|
// <UAMethod NodeId="i=11492" BrowseName="GetMonitoredItems"
|
|
1765
1880
|
// ParentNodeId="i=2253" MethodDeclarationId="i=11489">
|
|
@@ -1773,7 +1888,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1773
1888
|
objectId: coerceNodeId("ns=0;i=2253") // ObjectId.Server
|
|
1774
1889
|
});
|
|
1775
1890
|
|
|
1776
|
-
this.call(methodsToCall, (err?: Error | null, result?: CallMethodResult) => {
|
|
1891
|
+
return this.call(methodsToCall, (err?: Error | null, result?: CallMethodResult) => {
|
|
1777
1892
|
/* c8 ignore next */
|
|
1778
1893
|
if (err) {
|
|
1779
1894
|
return callback(err);
|
|
@@ -1816,13 +1931,13 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1816
1931
|
/**
|
|
1817
1932
|
* @internal
|
|
1818
1933
|
*/
|
|
1819
|
-
public getArgumentDefinition(...args:
|
|
1934
|
+
public getArgumentDefinition(...args: unknown[]): unknown {
|
|
1820
1935
|
const methodId = args[0] as MethodId;
|
|
1821
1936
|
const callback = args[1] as ResponseCallback<ArgumentDefinition>;
|
|
1822
1937
|
assert(typeof callback === "function");
|
|
1823
1938
|
return getArgumentDefinitionHelper(this, methodId)
|
|
1824
1939
|
.then((result) => {
|
|
1825
|
-
callback
|
|
1940
|
+
callback?.(null, result);
|
|
1826
1941
|
})
|
|
1827
1942
|
.catch((err) => {
|
|
1828
1943
|
callback(err);
|
|
@@ -1831,7 +1946,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1831
1946
|
|
|
1832
1947
|
public async registerNodes(nodesToRegister: NodeIdLike[]): Promise<NodeId[]>;
|
|
1833
1948
|
public registerNodes(nodesToRegister: NodeIdLike[], callback: (err: Error | null, registeredNodeIds?: NodeId[]) => void): void;
|
|
1834
|
-
public registerNodes(...args:
|
|
1949
|
+
public registerNodes(...args: unknown[]): unknown {
|
|
1835
1950
|
const nodesToRegister = args[0] as NodeIdLike[];
|
|
1836
1951
|
const callback = args[1] as (err: Error | null, registeredNodeIds?: NodeId[]) => void;
|
|
1837
1952
|
|
|
@@ -1842,7 +1957,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1842
1957
|
nodesToRegister: nodesToRegister.map((n) => this.resolveNodeId(n))
|
|
1843
1958
|
});
|
|
1844
1959
|
|
|
1845
|
-
this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
1960
|
+
return this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
1846
1961
|
/* c8 ignore next */
|
|
1847
1962
|
if (err) {
|
|
1848
1963
|
return callback(err);
|
|
@@ -1860,7 +1975,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1860
1975
|
|
|
1861
1976
|
public async unregisterNodes(nodesToUnregister: NodeIdLike[]): Promise<void>;
|
|
1862
1977
|
public unregisterNodes(nodesToUnregister: NodeIdLike[], callback: (err?: Error) => void): void;
|
|
1863
|
-
public unregisterNodes(...args:
|
|
1978
|
+
public unregisterNodes(...args: unknown[]): unknown {
|
|
1864
1979
|
const nodesToUnregister = args[0] as NodeIdLike[];
|
|
1865
1980
|
const callback = args[1] as (err?: Error) => void;
|
|
1866
1981
|
|
|
@@ -1871,7 +1986,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1871
1986
|
nodesToUnregister: nodesToUnregister.map((n) => this.resolveNodeId(n))
|
|
1872
1987
|
});
|
|
1873
1988
|
|
|
1874
|
-
this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
1989
|
+
return this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
1875
1990
|
/* c8 ignore next */
|
|
1876
1991
|
if (err) {
|
|
1877
1992
|
return callback(err);
|
|
@@ -1887,14 +2002,14 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1887
2002
|
public async queryFirst(queryFirstRequest: QueryFirstRequestLike): Promise<QueryFirstResponse>;
|
|
1888
2003
|
|
|
1889
2004
|
public queryFirst(queryFirstRequest: QueryFirstRequestLike, callback: ResponseCallback<QueryFirstResponse>): void;
|
|
1890
|
-
public queryFirst(...args:
|
|
2005
|
+
public queryFirst(...args: unknown[]): unknown {
|
|
1891
2006
|
const queryFirstRequest = args[0] as QueryFirstRequestLike;
|
|
1892
2007
|
const callback = args[1] as ResponseCallback<QueryFirstResponse>;
|
|
1893
2008
|
|
|
1894
2009
|
assert(typeof callback === "function");
|
|
1895
2010
|
const request = new QueryFirstRequest(queryFirstRequest);
|
|
1896
2011
|
|
|
1897
|
-
this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
2012
|
+
return this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
1898
2013
|
/* c8 ignore next */
|
|
1899
2014
|
if (err) {
|
|
1900
2015
|
return callback(err);
|
|
@@ -1944,11 +2059,8 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1944
2059
|
this.stopKeepAliveManager();
|
|
1945
2060
|
this.removeAllListeners();
|
|
1946
2061
|
//
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
// tslint:disable-next-line: no-console
|
|
1950
|
-
warningLog("dispose when pendingTransactions is not empty ");
|
|
1951
|
-
}
|
|
2062
|
+
// never strand a held caller: the session is going away, so nothing will ever replay them
|
|
2063
|
+
this.flushPendingTransactions(new Error("Session has been disposed while the transaction was waiting for reconnection"));
|
|
1952
2064
|
}
|
|
1953
2065
|
|
|
1954
2066
|
public toString(): string {
|
|
@@ -1959,41 +2071,43 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1959
2071
|
|
|
1960
2072
|
const timeoutInfo =
|
|
1961
2073
|
timeoutDelay < 0
|
|
1962
|
-
? chalk.red(
|
|
1963
|
-
: chalk.green(
|
|
2074
|
+
? chalk.red(` expired since ${-timeoutDelay / 1000} seconds`)
|
|
2075
|
+
: chalk.green(` timeout in ${timeoutDelay / 1000} seconds`);
|
|
1964
2076
|
|
|
1965
2077
|
let str = "";
|
|
1966
|
-
str +=
|
|
1967
|
-
str +=
|
|
1968
|
-
str +=
|
|
1969
|
-
str +=
|
|
1970
|
-
str +=
|
|
1971
|
-
str +=
|
|
1972
|
-
str +=
|
|
1973
|
-
str +=
|
|
1974
|
-
str +=
|
|
1975
|
-
str +=
|
|
1976
|
-
str +=
|
|
1977
|
-
str +=
|
|
1978
|
-
str +=
|
|
1979
|
-
str +=
|
|
1980
|
-
if (this._client
|
|
2078
|
+
str += ` name..................... ${this.name}`;
|
|
2079
|
+
str += `\n sessionId................ ${this.sessionId.toString()}`;
|
|
2080
|
+
str += `\n authenticationToken...... ${this.authenticationToken ? this.authenticationToken?.toString() : ""}`;
|
|
2081
|
+
str += `\n timeout.................. ${this.timeout}ms${timeoutInfo}`;
|
|
2082
|
+
str += `\n serverNonce.............. ${this.serverNonce ? this.serverNonce?.toString("hex") : ""}`;
|
|
2083
|
+
str += `\n serverCertificate........ ${buffer_ellipsis(this.serverCertificate)}`;
|
|
2084
|
+
str += `\n serverSignature.......... ${this.serverSignature}`;
|
|
2085
|
+
str += `\n lastRequestSentTime...... ${new Date(this.lastRequestSentTime).toISOString()} (${lap1})`;
|
|
2086
|
+
str += `\n lastResponseReceivedTime. ${new Date(this.lastResponseReceivedTime).toISOString()} (${lap2})`;
|
|
2087
|
+
str += `\n isReconnecting........... ${this.isReconnecting}`;
|
|
2088
|
+
str += `\n isValidChannel........... ${this.isChannelValid()} has been closed ${this.hasBeenClosed()}`;
|
|
2089
|
+
str += `\n channelId................ ${this.channelId()}`;
|
|
2090
|
+
str += `\n remaining life time...... ${this.evaluateRemainingLifetime()}`;
|
|
2091
|
+
str += `\n subscription count....... ${this.subscriptionCount}`;
|
|
2092
|
+
if (this._client?._secureChannel) {
|
|
1981
2093
|
if (this._client._secureChannel.activeSecurityToken) {
|
|
1982
|
-
str +=
|
|
2094
|
+
str += `\n reviseTokenLifetime...... ${this._client._secureChannel.activeSecurityToken.revisedLifetime}`;
|
|
1983
2095
|
}
|
|
1984
2096
|
}
|
|
1985
|
-
str += "\n keepAlive ................ " + this._keepAliveManager ? true : false;
|
|
1986
2097
|
if (this._keepAliveManager) {
|
|
1987
|
-
str +=
|
|
1988
|
-
str +=
|
|
1989
|
-
str +=
|
|
2098
|
+
str += `\n keepAlive ................ ${this._keepAliveManager}`;
|
|
2099
|
+
str += `\n keepAlive checkInterval.. ${this._keepAliveManager.checkInterval} ms`;
|
|
2100
|
+
str += `\n (defaultTransportTimeout).${ClientSecureChannelLayer.defaultTransportTimeout} ms`;
|
|
2101
|
+
str += `\n session timeout ${this.timeout} ms`;
|
|
1990
2102
|
}
|
|
1991
2103
|
return str;
|
|
1992
2104
|
}
|
|
1993
2105
|
|
|
1994
|
-
public getBuiltInDataType(
|
|
1995
|
-
|
|
1996
|
-
|
|
2106
|
+
public getBuiltInDataType(nodeId: NodeId): Promise<DataType>;
|
|
2107
|
+
public getBuiltInDataType(nodeId: NodeId, callback: (err: Error | null, dataType?: DataType) => void): void;
|
|
2108
|
+
public getBuiltInDataType(...args: unknown[]): unknown {
|
|
2109
|
+
const nodeId = args[0] as NodeId;
|
|
2110
|
+
const callback = args[1] as (err: Error | null, dataType?: DataType) => void;
|
|
1997
2111
|
return getBuiltInDataType(this, nodeId)
|
|
1998
2112
|
.then((dataType: DataType) => callback(null, dataType))
|
|
1999
2113
|
.catch(callback);
|
|
@@ -2001,21 +2115,24 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
2001
2115
|
|
|
2002
2116
|
public async readNamespaceArray(): Promise<string[]>;
|
|
2003
2117
|
public readNamespaceArray(callback: (err: Error | null, namespaceArray?: string[]) => void): void;
|
|
2004
|
-
public readNamespaceArray(...args:
|
|
2005
|
-
const callback = args[0];
|
|
2118
|
+
public readNamespaceArray(...args: unknown[]): unknown {
|
|
2119
|
+
const callback = args[0] as (err: Error | null, namespaceArray?: string[]) => void;
|
|
2006
2120
|
readNamespaceArray(this)
|
|
2007
2121
|
.then((namespaceArray) => callback(null, namespaceArray))
|
|
2008
2122
|
.catch((err) => {
|
|
2009
2123
|
callback(err);
|
|
2010
2124
|
});
|
|
2125
|
+
return undefined;
|
|
2011
2126
|
}
|
|
2012
2127
|
|
|
2013
2128
|
public getNamespaceIndex(namespaceUri: string): number {
|
|
2014
2129
|
assert(this.$$namespaceArray, "please make sure that readNamespaceArray has been called");
|
|
2015
|
-
|
|
2130
|
+
if (!this.$$namespaceArray) {
|
|
2131
|
+
throw new Error("please make sure that readNamespaceArray has been called");
|
|
2132
|
+
}
|
|
2133
|
+
return this.$$namespaceArray.indexOf(namespaceUri);
|
|
2016
2134
|
}
|
|
2017
2135
|
|
|
2018
|
-
// tslint:disable:no-empty
|
|
2019
2136
|
// ---------------------------------------- Alarm & condition stub
|
|
2020
2137
|
public disableCondition(): void {
|
|
2021
2138
|
/** empty */
|
|
@@ -2025,39 +2142,66 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
2025
2142
|
/** empty */
|
|
2026
2143
|
}
|
|
2027
2144
|
|
|
2145
|
+
public addCommentCondition(
|
|
2146
|
+
conditionId: NodeIdLike,
|
|
2147
|
+
eventId: Buffer,
|
|
2148
|
+
comment: LocalizedTextLike,
|
|
2149
|
+
callback: Callback<StatusCode>
|
|
2150
|
+
): void;
|
|
2151
|
+
public addCommentCondition(conditionId: NodeIdLike, eventId: Buffer, comment: LocalizedTextLike): Promise<StatusCode>;
|
|
2028
2152
|
public addCommentCondition(
|
|
2029
2153
|
_conditionId: NodeIdLike,
|
|
2030
2154
|
_eventId: Buffer,
|
|
2031
2155
|
_comment: LocalizedTextLike,
|
|
2032
2156
|
_callback?: Callback<StatusCode>
|
|
2033
|
-
):
|
|
2157
|
+
): unknown {
|
|
2034
2158
|
/** empty */
|
|
2159
|
+
return undefined;
|
|
2035
2160
|
}
|
|
2036
2161
|
|
|
2162
|
+
public confirmCondition(
|
|
2163
|
+
conditionId: NodeIdLike,
|
|
2164
|
+
eventId: Buffer,
|
|
2165
|
+
comment: LocalizedTextLike,
|
|
2166
|
+
callback: Callback<StatusCode>
|
|
2167
|
+
): void;
|
|
2168
|
+
public confirmCondition(conditionId: NodeIdLike, eventId: Buffer, comment: LocalizedTextLike): Promise<StatusCode>;
|
|
2037
2169
|
public confirmCondition(
|
|
2038
2170
|
_conditionId: NodeIdLike,
|
|
2039
2171
|
_eventId: Buffer,
|
|
2040
2172
|
_comment: LocalizedTextLike,
|
|
2041
2173
|
_callback?: Callback<StatusCode>
|
|
2042
|
-
):
|
|
2174
|
+
): unknown {
|
|
2043
2175
|
/** empty */
|
|
2176
|
+
return undefined;
|
|
2044
2177
|
}
|
|
2045
2178
|
|
|
2179
|
+
public acknowledgeCondition(
|
|
2180
|
+
conditionId: NodeId,
|
|
2181
|
+
eventId: Buffer,
|
|
2182
|
+
comment: LocalizedTextLike,
|
|
2183
|
+
callback: Callback<StatusCode>
|
|
2184
|
+
): void;
|
|
2185
|
+
public acknowledgeCondition(conditionId: NodeId, eventId: Buffer, comment: LocalizedTextLike): Promise<StatusCode>;
|
|
2046
2186
|
public acknowledgeCondition(
|
|
2047
2187
|
_conditionId: NodeId,
|
|
2048
2188
|
_eventId: Buffer,
|
|
2049
2189
|
_comment: LocalizedTextLike,
|
|
2050
2190
|
_callback?: Callback<StatusCode>
|
|
2051
|
-
):
|
|
2191
|
+
): unknown {
|
|
2052
2192
|
/** empty */
|
|
2193
|
+
return undefined;
|
|
2053
2194
|
}
|
|
2054
2195
|
|
|
2055
2196
|
/**
|
|
2056
2197
|
* @deprecated
|
|
2057
2198
|
* @private
|
|
2058
2199
|
*/
|
|
2059
|
-
public findMethodId(
|
|
2200
|
+
public findMethodId(nodeId: NodeIdLike, methodName: string, callback: ResponseCallback<NodeId>): void;
|
|
2201
|
+
public findMethodId(nodeId: NodeIdLike, methodName: string): Promise<NodeId>;
|
|
2202
|
+
public findMethodId(_nodeId: NodeIdLike, _methodName: string, _callback?: ResponseCallback<NodeId>): unknown {
|
|
2060
2203
|
/** empty */
|
|
2204
|
+
return undefined;
|
|
2061
2205
|
}
|
|
2062
2206
|
|
|
2063
2207
|
public _callMethodCondition(
|
|
@@ -2081,41 +2225,53 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
2081
2225
|
* @param dataType
|
|
2082
2226
|
* @param pojo
|
|
2083
2227
|
*/
|
|
2084
|
-
public async constructExtensionObject(dataType: NodeId, pojo: Record<string,
|
|
2228
|
+
public async constructExtensionObject(dataType: NodeId, pojo: Record<string, unknown>): Promise<ExtensionObject> {
|
|
2085
2229
|
const Constructor = await this.getExtensionObjectConstructor(dataType);
|
|
2086
2230
|
return new Constructor(pojo);
|
|
2087
2231
|
}
|
|
2088
2232
|
|
|
2089
|
-
private _defaultRequest
|
|
2233
|
+
private _defaultRequest<TRequestOptions, TResponse extends Response>(
|
|
2234
|
+
requestClass: new (options: TRequestOptions) => Request,
|
|
2235
|
+
_responseClass: unknown,
|
|
2236
|
+
options: TRequestOptions,
|
|
2237
|
+
callback?: (err: Error | null, response?: TResponse) => void
|
|
2238
|
+
): unknown {
|
|
2090
2239
|
assert(typeof callback === "function");
|
|
2240
|
+
if (!callback) {
|
|
2241
|
+
throw new Error("_defaultRequest: expecting a callback function here");
|
|
2242
|
+
}
|
|
2091
2243
|
|
|
2092
|
-
const request = options instanceof requestClass ? options : new requestClass(options);
|
|
2244
|
+
const request: Request = options instanceof requestClass ? options : new requestClass(options);
|
|
2093
2245
|
|
|
2094
2246
|
/* c8 ignore next */
|
|
2095
2247
|
if (doDebug) {
|
|
2096
|
-
request.trace = new Error("").stack;
|
|
2248
|
+
(request as unknown as { trace?: string }).trace = new Error("").stack;
|
|
2097
2249
|
}
|
|
2098
2250
|
|
|
2099
2251
|
/* c8 ignore next */
|
|
2100
2252
|
if (this._closeEventHasBeenEmitted) {
|
|
2101
|
-
|
|
2253
|
+
// c8 ignore next
|
|
2254
|
+
doDebug && debugLog("ClientSession#_defaultRequest => session has been closed !!", request.toString());
|
|
2102
2255
|
setImmediate(() => {
|
|
2103
2256
|
callback(new Error("ClientSession is closed !"));
|
|
2104
2257
|
});
|
|
2105
|
-
return;
|
|
2258
|
+
return undefined;
|
|
2106
2259
|
}
|
|
2107
2260
|
|
|
2108
|
-
this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
2261
|
+
return this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
2109
2262
|
if (this._closeEventHasBeenEmitted) {
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2263
|
+
// c8 ignore next
|
|
2264
|
+
doDebug &&
|
|
2265
|
+
debugLog(
|
|
2266
|
+
"ClientSession#_defaultRequest ... err =",
|
|
2267
|
+
err ? err.message : "null",
|
|
2268
|
+
response ? response.toString() : " null"
|
|
2269
|
+
);
|
|
2115
2270
|
}
|
|
2116
2271
|
/* c8 ignore next */
|
|
2117
2272
|
if (err) {
|
|
2118
|
-
|
|
2273
|
+
// c8 ignore next
|
|
2274
|
+
doDebug && debugLog("Client session : performMessageTransaction error = ", err.message);
|
|
2119
2275
|
// let intercept interesting error message
|
|
2120
2276
|
if (err.message.match(/BadSessionClosed/)) {
|
|
2121
2277
|
// the session has been closed by Server
|
|
@@ -2143,6 +2299,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
2143
2299
|
// DO NOT TERMINATE SESSION, as we will need a publishEngine when we
|
|
2144
2300
|
// reconnect this._terminatePublishEngine();
|
|
2145
2301
|
|
|
2302
|
+
// biome-ignore lint/correctness/noConstantCondition: deliberate debug on/off toggle, not dead code
|
|
2146
2303
|
if (false) {
|
|
2147
2304
|
// ER 10.2019
|
|
2148
2305
|
/**
|
|
@@ -2152,21 +2309,23 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
2152
2309
|
this.emitCloseEvent(StatusCodes.BadSessionClosed);
|
|
2153
2310
|
}
|
|
2154
2311
|
}
|
|
2155
|
-
return callback(err, response);
|
|
2312
|
+
return callback(err, response as TResponse | undefined);
|
|
2156
2313
|
}
|
|
2157
|
-
callback(null, response);
|
|
2314
|
+
callback(null, response as TResponse | undefined);
|
|
2158
2315
|
});
|
|
2159
2316
|
}
|
|
2160
2317
|
#_recreate_session_and_reperform_transaction(request: Request, callback: (err: Error | null, response?: Response) => void) {
|
|
2161
2318
|
warningLog("attempt to recreate session to reperform a transaction ", request.constructor.name);
|
|
2162
2319
|
if (this.recursive_repair_detector >= 1) {
|
|
2163
|
-
// tslint:disable-next-line: no-console
|
|
2164
2320
|
warningLog("recreate_session_and_reperform_transaction => Already in Progress");
|
|
2165
2321
|
return callback(new Error("Cannot recreate session"));
|
|
2166
2322
|
}
|
|
2323
|
+
if (!this._client) {
|
|
2324
|
+
return callback(new Error("Cannot recreate session: session has no client"));
|
|
2325
|
+
}
|
|
2167
2326
|
this.recursive_repair_detector += 1;
|
|
2168
2327
|
warningLog(chalk.red("----------------> Repairing Client Session as Server believes it is invalid now "));
|
|
2169
|
-
repair_client_session(this._client
|
|
2328
|
+
repair_client_session(this._client, this, (err?: Error) => {
|
|
2170
2329
|
this.recursive_repair_detector -= 1;
|
|
2171
2330
|
if (err) {
|
|
2172
2331
|
warningLog(chalk.red("----------------> session Repaired has failed with error", err.message));
|
|
@@ -2182,7 +2341,7 @@ async function promoteOpaqueStructureForCallMethodResult(
|
|
|
2182
2341
|
session: IBasicSessionAsync2,
|
|
2183
2342
|
callMethodResult: CallMethodResult
|
|
2184
2343
|
): Promise<void> {
|
|
2185
|
-
if (!callMethodResult
|
|
2344
|
+
if (!callMethodResult?.outputArguments || callMethodResult.outputArguments.length === 0) {
|
|
2186
2345
|
return;
|
|
2187
2346
|
}
|
|
2188
2347
|
await promoteOpaqueStructure(
|
|
@@ -2217,8 +2376,6 @@ async function promoteOpaqueStructureForCall(session: IBasicSessionAsync2, callM
|
|
|
2217
2376
|
await Promise.all(promises);
|
|
2218
2377
|
}
|
|
2219
2378
|
|
|
2220
|
-
// tslint:disable:no-var-requires
|
|
2221
|
-
// tslint:disable:max-line-length
|
|
2222
2379
|
import { withCallback } from "thenify-ex";
|
|
2223
2380
|
|
|
2224
2381
|
const opts = { multiArgs: false };
|