node-opcua-server 2.53.0 → 2.56.1
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/LICENSE +20 -20
- package/dist/base_server.js +12 -14
- package/dist/base_server.js.map +1 -1
- package/dist/factory.d.ts +4 -2
- package/dist/factory.js.map +1 -1
- package/dist/history_server_capabilities.js.map +1 -1
- package/dist/i_server_side_publish_engine.d.ts +1 -1
- package/dist/i_server_side_publish_engine.js +1 -1
- package/dist/i_server_side_publish_engine.js.map +1 -1
- package/dist/monitored_item.d.ts +3 -0
- package/dist/monitored_item.js +7 -14
- package/dist/monitored_item.js.map +1 -1
- package/dist/node_sampler.js +1 -1
- package/dist/node_sampler.js.map +1 -1
- package/dist/opcua_server.d.ts +29 -44
- package/dist/opcua_server.js +218 -262
- package/dist/opcua_server.js.map +1 -1
- package/dist/queue.js +1 -0
- package/dist/queue.js.map +1 -1
- package/dist/register_server_manager.d.ts +4 -1
- package/dist/register_server_manager.js +5 -5
- package/dist/register_server_manager.js.map +1 -1
- package/dist/register_server_manager_hidden.d.ts +1 -1
- package/dist/register_server_manager_hidden.js.map +1 -1
- package/dist/register_server_manager_mdns_only.d.ts +4 -1
- package/dist/register_server_manager_mdns_only.js +1 -1
- package/dist/register_server_manager_mdns_only.js.map +1 -1
- package/dist/server_capabilities.js.map +1 -1
- package/dist/server_end_point.d.ts +4 -1
- package/dist/server_end_point.js +10 -11
- package/dist/server_end_point.js.map +1 -1
- package/dist/server_engine.d.ts +11 -7
- package/dist/server_engine.js +72 -74
- package/dist/server_engine.js.map +1 -1
- package/dist/server_publish_engine.d.ts +4 -1
- package/dist/server_publish_engine.js +5 -5
- package/dist/server_publish_engine.js.map +1 -1
- package/dist/server_publish_engine_for_orphan_subscriptions.d.ts +2 -2
- package/dist/server_publish_engine_for_orphan_subscriptions.js.map +1 -1
- package/dist/server_session.d.ts +1 -1
- package/dist/server_session.js +24 -29
- package/dist/server_session.js.map +1 -1
- package/dist/server_subscription.d.ts +3 -1
- package/dist/server_subscription.js +6 -6
- package/dist/server_subscription.js.map +1 -1
- package/dist/sessions_compatible_for_transfer.js +2 -1
- package/dist/sessions_compatible_for_transfer.js.map +1 -1
- package/dist/validate_filter.js +4 -7
- package/dist/validate_filter.js.map +1 -1
- package/package.json +45 -44
- package/source/base_server.ts +19 -22
- package/source/factory.ts +5 -2
- package/source/history_server_capabilities.ts +3 -4
- package/source/i_channel_data.ts +4 -8
- package/source/i_register_server_manager.ts +0 -3
- package/source/i_server_side_publish_engine.ts +5 -6
- package/source/i_socket_data.ts +1 -1
- package/source/index.ts +14 -14
- package/source/monitored_item.ts +32 -44
- package/source/node_sampler.ts +82 -82
- package/source/opcua_server.ts +326 -357
- package/source/queue.ts +6 -7
- package/source/register_server_manager.ts +35 -23
- package/source/register_server_manager_hidden.ts +8 -10
- package/source/register_server_manager_mdns_only.ts +8 -13
- package/source/server_capabilities.ts +0 -5
- package/source/server_end_point.ts +28 -30
- package/source/server_engine.ts +122 -122
- package/source/server_publish_engine.ts +24 -21
- package/source/server_publish_engine_for_orphan_subscriptions.ts +26 -26
- package/source/server_session.ts +44 -49
- package/source/server_subscription.ts +23 -23
- package/source/sessions_compatible_for_transfer.ts +26 -25
- package/source/validate_filter.ts +8 -22
- package/test_helpers/create_certificates.js +1 -1
package/source/server_engine.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module node-opcua-server
|
|
3
3
|
*/
|
|
4
|
-
|
|
4
|
+
import { EventEmitter } from "events";
|
|
5
5
|
import * as async from "async";
|
|
6
6
|
import * as chalk from "chalk";
|
|
7
|
-
import { EventEmitter } from "events";
|
|
8
7
|
import { assert } from "node-opcua-assert";
|
|
9
8
|
|
|
10
9
|
import {
|
|
@@ -29,13 +28,12 @@ import {
|
|
|
29
28
|
BindVariableOptions,
|
|
30
29
|
MethodFunctorCallback,
|
|
31
30
|
ISessionContext,
|
|
32
|
-
DTServerStatus,
|
|
31
|
+
DTServerStatus,
|
|
32
|
+
resolveOpaqueOnAddressSpace,
|
|
33
|
+
ContinuationData
|
|
33
34
|
} from "node-opcua-address-space";
|
|
34
|
-
|
|
35
35
|
import { generateAddressSpace } from "node-opcua-address-space/nodeJS";
|
|
36
|
-
|
|
37
36
|
import { DataValue, coerceTimestampsToReturn, apply_timestamps_no_copy } from "node-opcua-data-value";
|
|
38
|
-
|
|
39
37
|
import {
|
|
40
38
|
ServerDiagnosticsSummaryDataType,
|
|
41
39
|
ServerState,
|
|
@@ -54,17 +52,17 @@ import {
|
|
|
54
52
|
import { coerceNodeId, makeNodeId, NodeId, NodeIdLike, NodeIdType, resolveNodeId } from "node-opcua-nodeid";
|
|
55
53
|
import { BrowseResult } from "node-opcua-service-browse";
|
|
56
54
|
import { ReadRequest, TimestampsToReturn } from "node-opcua-service-read";
|
|
57
|
-
|
|
58
|
-
import { TransferResult } from "node-opcua-service-subscription";
|
|
59
|
-
|
|
55
|
+
import { UInt32 } from "node-opcua-basic-types";
|
|
60
56
|
import { CreateSubscriptionRequestLike } from "node-opcua-client";
|
|
61
57
|
import { ExtraDataTypeManager } from "node-opcua-client-dynamic-extension-object";
|
|
62
58
|
import { DataTypeIds, MethodIds, ObjectIds, VariableIds } from "node-opcua-constants";
|
|
63
59
|
import { getCurrentClock, minOPCUADate } from "node-opcua-date-time";
|
|
64
60
|
import { checkDebugFlag, make_debugLog, make_errorLog, make_warningLog, traceFromThisProjectOnly } from "node-opcua-debug";
|
|
65
61
|
import { nodesets } from "node-opcua-nodesets";
|
|
62
|
+
import { NumericRange } from "node-opcua-numeric-range";
|
|
66
63
|
import { ObjectRegistry } from "node-opcua-object-registry";
|
|
67
64
|
import { CallMethodResult } from "node-opcua-service-call";
|
|
65
|
+
import { TransferResult } from "node-opcua-service-subscription";
|
|
68
66
|
import { ApplicationDescription } from "node-opcua-service-endpoints";
|
|
69
67
|
import { HistoryReadDetails, HistoryReadRequest, HistoryReadResult, HistoryReadValueId } from "node-opcua-service-history";
|
|
70
68
|
import { StatusCode, StatusCodes, CallbackT, StatusCodeCallback } from "node-opcua-status-code";
|
|
@@ -74,7 +72,6 @@ import {
|
|
|
74
72
|
BrowsePathResult,
|
|
75
73
|
BuildInfo,
|
|
76
74
|
BuildInfoOptions,
|
|
77
|
-
ProgramDiagnostic2DataType,
|
|
78
75
|
ReadAtTimeDetails,
|
|
79
76
|
ReadEventDetails,
|
|
80
77
|
ReadProcessedDetails,
|
|
@@ -84,10 +81,9 @@ import {
|
|
|
84
81
|
WriteValue,
|
|
85
82
|
ReadValueId,
|
|
86
83
|
TimeZoneDataType,
|
|
87
|
-
ProgramDiagnosticDataType
|
|
88
|
-
CallMethodResultOptions
|
|
84
|
+
ProgramDiagnosticDataType
|
|
89
85
|
} from "node-opcua-types";
|
|
90
|
-
import { DataType, isValidVariant, Variant, VariantArrayType
|
|
86
|
+
import { DataType, isValidVariant, Variant, VariantArrayType } from "node-opcua-variant";
|
|
91
87
|
|
|
92
88
|
import { HistoryServerCapabilities, HistoryServerCapabilitiesOptions } from "./history_server_capabilities";
|
|
93
89
|
import { MonitoredItem } from "./monitored_item";
|
|
@@ -97,9 +93,7 @@ import { ServerSidePublishEngineForOrphanSubscription } from "./server_publish_e
|
|
|
97
93
|
import { ServerSession } from "./server_session";
|
|
98
94
|
import { Subscription } from "./server_subscription";
|
|
99
95
|
import { sessionsCompatibleForTransfer } from "./sessions_compatible_for_transfer";
|
|
100
|
-
import {
|
|
101
|
-
import { UInt32 } from "node-opcua-basic-types";
|
|
102
|
-
import { resolveOpaqueOnAddressSpace } from "node-opcua-address-space";
|
|
96
|
+
import { OPCUAServerOptions } from "./opcua_server";
|
|
103
97
|
|
|
104
98
|
const debugLog = make_debugLog(__filename);
|
|
105
99
|
const errorLog = make_errorLog(__filename);
|
|
@@ -128,7 +122,7 @@ function setSubscriptionDurable(
|
|
|
128
122
|
// https://reference.opcfoundation.org/v104/Core/docs/Part4/6.8/
|
|
129
123
|
assert(Array.isArray(inputArguments));
|
|
130
124
|
assert(typeof callback === "function");
|
|
131
|
-
assert(
|
|
125
|
+
assert(Object.prototype.hasOwnProperty.call(context, "session"), " expecting a session id in the context object");
|
|
132
126
|
const session = context.session as ServerSession;
|
|
133
127
|
if (!session) {
|
|
134
128
|
return callback(null, { statusCode: StatusCodes.BadInternalError });
|
|
@@ -211,7 +205,7 @@ function getMonitoredItemsId(
|
|
|
211
205
|
) {
|
|
212
206
|
assert(Array.isArray(inputArguments));
|
|
213
207
|
assert(typeof callback === "function");
|
|
214
|
-
assert(
|
|
208
|
+
assert(Object.prototype.hasOwnProperty.call(context, "session"), " expecting a session id in the context object");
|
|
215
209
|
|
|
216
210
|
const session = context.session as ServerSession;
|
|
217
211
|
if (!session) {
|
|
@@ -315,7 +309,7 @@ export class ServerEngine extends EventEmitter {
|
|
|
315
309
|
private _sessions: { [key: string]: ServerSession };
|
|
316
310
|
private _closedSessions: { [key: string]: ServerSession };
|
|
317
311
|
private _orphanPublishEngine?: ServerSidePublishEngineForOrphanSubscription;
|
|
318
|
-
private
|
|
312
|
+
private _shutdownTasks: ((this: ServerEngine) => void)[];
|
|
319
313
|
private _applicationUri: string;
|
|
320
314
|
private _expectedShutdownTime!: Date;
|
|
321
315
|
private _serverStatus: ServerStatusDataType;
|
|
@@ -373,11 +367,11 @@ export class ServerEngine extends EventEmitter {
|
|
|
373
367
|
|
|
374
368
|
// --------------------------------------------------- serverDiagnosticsSummary extension Object
|
|
375
369
|
this.serverDiagnosticsSummary = new ServerDiagnosticsSummaryDataType();
|
|
376
|
-
assert(
|
|
370
|
+
assert(Object.prototype.hasOwnProperty.call(this.serverDiagnosticsSummary, "currentSessionCount"));
|
|
377
371
|
|
|
378
372
|
// note spelling is different for serverDiagnosticsSummary.currentSubscriptionCount
|
|
379
373
|
// and sessionDiagnostics.currentSubscriptionsCount ( with an s)
|
|
380
|
-
assert(
|
|
374
|
+
assert(Object.prototype.hasOwnProperty.call(this.serverDiagnosticsSummary, "currentSubscriptionCount"));
|
|
381
375
|
|
|
382
376
|
(this.serverDiagnosticsSummary as any).__defineGetter__("currentSubscriptionCount", () => {
|
|
383
377
|
// currentSubscriptionCount returns the total number of subscriptions
|
|
@@ -395,7 +389,7 @@ export class ServerEngine extends EventEmitter {
|
|
|
395
389
|
|
|
396
390
|
this.addressSpace = null;
|
|
397
391
|
|
|
398
|
-
this.
|
|
392
|
+
this._shutdownTasks = [];
|
|
399
393
|
|
|
400
394
|
this._applicationUri = "";
|
|
401
395
|
if (typeof options.applicationUri === "function") {
|
|
@@ -404,7 +398,7 @@ export class ServerEngine extends EventEmitter {
|
|
|
404
398
|
this._applicationUri = options.applicationUri || "<unset _applicationUri>";
|
|
405
399
|
}
|
|
406
400
|
|
|
407
|
-
options.serverDiagnosticsEnabled = Object.prototype.hasOwnProperty.call(options,"serverDiagnosticsEnable")
|
|
401
|
+
options.serverDiagnosticsEnabled = Object.prototype.hasOwnProperty.call(options, "serverDiagnosticsEnable")
|
|
408
402
|
? options.serverDiagnosticsEnabled
|
|
409
403
|
: true;
|
|
410
404
|
|
|
@@ -414,7 +408,7 @@ export class ServerEngine extends EventEmitter {
|
|
|
414
408
|
return !!this._serverStatus!;
|
|
415
409
|
}
|
|
416
410
|
|
|
417
|
-
public dispose() {
|
|
411
|
+
public dispose(): void {
|
|
418
412
|
this.addressSpace = null;
|
|
419
413
|
|
|
420
414
|
assert(Object.keys(this._sessions).length === 0, "ServerEngine#_sessions not empty");
|
|
@@ -430,7 +424,7 @@ export class ServerEngine extends EventEmitter {
|
|
|
430
424
|
this._orphanPublishEngine = undefined;
|
|
431
425
|
}
|
|
432
426
|
|
|
433
|
-
this.
|
|
427
|
+
this._shutdownTasks = [];
|
|
434
428
|
this._serverStatus = null as any as ServerStatusDataType;
|
|
435
429
|
this._internalState = "disposed";
|
|
436
430
|
this.removeAllListeners();
|
|
@@ -454,9 +448,9 @@ export class ServerEngine extends EventEmitter {
|
|
|
454
448
|
* register a function that will be called when the server will perform its shut down.
|
|
455
449
|
* @method registerShutdownTask
|
|
456
450
|
*/
|
|
457
|
-
public registerShutdownTask(task:
|
|
451
|
+
public registerShutdownTask(task: (this: ServerEngine) => void): void {
|
|
458
452
|
assert(typeof task === "function");
|
|
459
|
-
this.
|
|
453
|
+
this._shutdownTasks.push(task);
|
|
460
454
|
}
|
|
461
455
|
|
|
462
456
|
/**
|
|
@@ -491,10 +485,10 @@ export class ServerEngine extends EventEmitter {
|
|
|
491
485
|
// all subscriptions must have been terminated
|
|
492
486
|
assert(this.currentSubscriptionCount === 0, "all subscriptions must have been terminated");
|
|
493
487
|
|
|
494
|
-
this.
|
|
488
|
+
this._shutdownTasks.push(shutdownAndDisposeAddressSpace);
|
|
495
489
|
|
|
496
490
|
// perform registerShutdownTask
|
|
497
|
-
for (const task of this.
|
|
491
|
+
for (const task of this._shutdownTasks) {
|
|
498
492
|
task.call(this);
|
|
499
493
|
}
|
|
500
494
|
|
|
@@ -504,21 +498,21 @@ export class ServerEngine extends EventEmitter {
|
|
|
504
498
|
/**
|
|
505
499
|
* the number of active sessions
|
|
506
500
|
*/
|
|
507
|
-
public get currentSessionCount() {
|
|
501
|
+
public get currentSessionCount(): number {
|
|
508
502
|
return this.serverDiagnosticsSummary.currentSessionCount;
|
|
509
503
|
}
|
|
510
504
|
|
|
511
505
|
/**
|
|
512
506
|
* the cumulated number of sessions that have been opened since this object exists
|
|
513
507
|
*/
|
|
514
|
-
public get cumulatedSessionCount() {
|
|
508
|
+
public get cumulatedSessionCount(): number {
|
|
515
509
|
return this.serverDiagnosticsSummary.cumulatedSessionCount;
|
|
516
510
|
}
|
|
517
511
|
|
|
518
512
|
/**
|
|
519
513
|
* the number of active subscriptions.
|
|
520
514
|
*/
|
|
521
|
-
public get currentSubscriptionCount() {
|
|
515
|
+
public get currentSubscriptionCount(): number {
|
|
522
516
|
return this.serverDiagnosticsSummary.currentSubscriptionCount;
|
|
523
517
|
}
|
|
524
518
|
|
|
@@ -598,7 +592,7 @@ export class ServerEngine extends EventEmitter {
|
|
|
598
592
|
this.incrementSecurityRejectedRequestsCount();
|
|
599
593
|
}
|
|
600
594
|
|
|
601
|
-
public setShutdownTime(date: Date) {
|
|
595
|
+
public setShutdownTime(date: Date): void {
|
|
602
596
|
this._expectedShutdownTime = date;
|
|
603
597
|
}
|
|
604
598
|
public setShutdownReason(reason: LocalizedTextLike): void {
|
|
@@ -631,21 +625,21 @@ export class ServerEngine extends EventEmitter {
|
|
|
631
625
|
/**
|
|
632
626
|
* the server urn
|
|
633
627
|
*/
|
|
634
|
-
public get serverNameUrn() {
|
|
628
|
+
public get serverNameUrn(): string {
|
|
635
629
|
return this._applicationUri;
|
|
636
630
|
}
|
|
637
631
|
|
|
638
632
|
/**
|
|
639
633
|
* the urn of the server namespace
|
|
640
634
|
*/
|
|
641
|
-
public get serverNamespaceUrn() {
|
|
635
|
+
public get serverNamespaceUrn(): string {
|
|
642
636
|
return this._applicationUri; // "urn:" + engine.serverName;
|
|
643
637
|
}
|
|
644
|
-
public get serverStatus() {
|
|
638
|
+
public get serverStatus(): ServerStatusDataType {
|
|
645
639
|
return this._serverStatus;
|
|
646
640
|
}
|
|
647
641
|
|
|
648
|
-
public setServerState(serverState: ServerState) {
|
|
642
|
+
public setServerState(serverState: ServerState): void {
|
|
649
643
|
assert(serverState !== null && serverState !== undefined);
|
|
650
644
|
this.addressSpace?.rootFolder?.objects?.server?.serverStatus?.state?.setValueFromSource({
|
|
651
645
|
dataType: DataType.UInt32,
|
|
@@ -670,7 +664,7 @@ export class ServerEngine extends EventEmitter {
|
|
|
670
664
|
* @param options.nodeset_filename {String} - [option](default : 'mini.Node.Set2.xml' )
|
|
671
665
|
* @param callback
|
|
672
666
|
*/
|
|
673
|
-
public initialize(options:
|
|
667
|
+
public initialize(options: OPCUAServerOptions, callback: () => void): void {
|
|
674
668
|
assert(!this.addressSpace); // check that 'initialize' has not been already called
|
|
675
669
|
|
|
676
670
|
this._internalState = "initializing";
|
|
@@ -690,6 +684,7 @@ export class ServerEngine extends EventEmitter {
|
|
|
690
684
|
const serverNamespace = this.addressSpace.registerNamespace(this.serverNamespaceUrn);
|
|
691
685
|
assert(serverNamespace.index === 1);
|
|
692
686
|
|
|
687
|
+
// eslint-disable-next-line max-statements
|
|
693
688
|
generateAddressSpace(this.addressSpace, options.nodeset_filename, () => {
|
|
694
689
|
/* istanbul ignore next */
|
|
695
690
|
if (!this.addressSpace) {
|
|
@@ -840,6 +835,7 @@ export class ServerEngine extends EventEmitter {
|
|
|
840
835
|
return this.isAuditing;
|
|
841
836
|
});
|
|
842
837
|
|
|
838
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
843
839
|
const engine = this;
|
|
844
840
|
const makeNotReadableIfEnabledFlagIsFalse = (variable: UAVariable) => {
|
|
845
841
|
const originalIsReadable = variable.isReadable;
|
|
@@ -867,7 +863,9 @@ export class ServerEngine extends EventEmitter {
|
|
|
867
863
|
}
|
|
868
864
|
);
|
|
869
865
|
const nodeId = makeNodeId(VariableIds.Server_ServerDiagnostics_ServerDiagnosticsSummary);
|
|
870
|
-
const serverDiagnosticsSummaryNode = addressSpace.findNode(
|
|
866
|
+
const serverDiagnosticsSummaryNode = addressSpace.findNode(
|
|
867
|
+
nodeId
|
|
868
|
+
) as UAServerDiagnosticsSummary<ServerDiagnosticsSummaryDataType>;
|
|
871
869
|
|
|
872
870
|
if (serverDiagnosticsSummaryNode) {
|
|
873
871
|
serverDiagnosticsSummaryNode.bindExtensionObject(this.serverDiagnosticsSummary);
|
|
@@ -877,7 +875,9 @@ export class ServerEngine extends EventEmitter {
|
|
|
877
875
|
};
|
|
878
876
|
|
|
879
877
|
const bindServerStatus = () => {
|
|
880
|
-
const serverStatusNode = addressSpace.findNode(
|
|
878
|
+
const serverStatusNode = addressSpace.findNode(
|
|
879
|
+
makeNodeId(VariableIds.Server_ServerStatus)
|
|
880
|
+
) as UAServerStatus<DTServerStatus>;
|
|
881
881
|
|
|
882
882
|
if (!serverStatusNode) {
|
|
883
883
|
return;
|
|
@@ -1199,7 +1199,7 @@ export class ServerEngine extends EventEmitter {
|
|
|
1199
1199
|
|
|
1200
1200
|
this._internalState = "initialized";
|
|
1201
1201
|
this.setServerState(ServerState.Running);
|
|
1202
|
-
setImmediate(callback);
|
|
1202
|
+
setImmediate(() => callback());
|
|
1203
1203
|
});
|
|
1204
1204
|
}
|
|
1205
1205
|
|
|
@@ -1218,7 +1218,10 @@ export class ServerEngine extends EventEmitter {
|
|
|
1218
1218
|
return addressSpace.browseSingleNode(nodeId, browseDescription, context);
|
|
1219
1219
|
}
|
|
1220
1220
|
|
|
1221
|
-
public async browseWithAutomaticExpansion(
|
|
1221
|
+
public async browseWithAutomaticExpansion(
|
|
1222
|
+
nodesToBrowse: BrowseDescription[],
|
|
1223
|
+
context?: ISessionContext
|
|
1224
|
+
): Promise<BrowseResult[]> {
|
|
1222
1225
|
// do expansion first
|
|
1223
1226
|
for (const browseDescription of nodesToBrowse) {
|
|
1224
1227
|
const nodeId = resolveNodeId(browseDescription.nodeId);
|
|
@@ -1347,7 +1350,7 @@ export class ServerEngine extends EventEmitter {
|
|
|
1347
1350
|
context: ISessionContext,
|
|
1348
1351
|
writeValue: WriteValue,
|
|
1349
1352
|
callback: (err: Error | null, statusCode?: StatusCode) => void
|
|
1350
|
-
) {
|
|
1353
|
+
): void {
|
|
1351
1354
|
assert(context instanceof SessionContext);
|
|
1352
1355
|
assert(typeof callback === "function");
|
|
1353
1356
|
assert(writeValue.schema.name === "WriteValue");
|
|
@@ -1383,7 +1386,7 @@ export class ServerEngine extends EventEmitter {
|
|
|
1383
1386
|
context: ISessionContext,
|
|
1384
1387
|
nodesToWrite: WriteValue[],
|
|
1385
1388
|
callback: (err: Error | null, statusCodes?: StatusCode[]) => void
|
|
1386
|
-
) {
|
|
1389
|
+
): void {
|
|
1387
1390
|
assert(context instanceof SessionContext);
|
|
1388
1391
|
assert(typeof callback === "function");
|
|
1389
1392
|
|
|
@@ -1420,6 +1423,7 @@ export class ServerEngine extends EventEmitter {
|
|
|
1420
1423
|
attributeId: AttributeIds,
|
|
1421
1424
|
historyReadDetails: ReadRawModifiedDetails | ReadEventDetails | ReadProcessedDetails | ReadAtTimeDetails,
|
|
1422
1425
|
timestampsToReturn: TimestampsToReturn,
|
|
1426
|
+
continuationData: ContinuationData,
|
|
1423
1427
|
callback: (err: Error | null, results?: HistoryReadResult) => void
|
|
1424
1428
|
): void {
|
|
1425
1429
|
if (timestampsToReturn === TimestampsToReturn.Invalid) {
|
|
@@ -1439,6 +1443,7 @@ export class ServerEngine extends EventEmitter {
|
|
|
1439
1443
|
}),
|
|
1440
1444
|
historyReadDetails,
|
|
1441
1445
|
timestampsToReturn,
|
|
1446
|
+
continuationData,
|
|
1442
1447
|
callback
|
|
1443
1448
|
);
|
|
1444
1449
|
}
|
|
@@ -1461,104 +1466,94 @@ export class ServerEngine extends EventEmitter {
|
|
|
1461
1466
|
context: ISessionContext,
|
|
1462
1467
|
historyReadRequest: HistoryReadRequest,
|
|
1463
1468
|
callback: (err: Error | null, results: HistoryReadResult[]) => void
|
|
1464
|
-
) {
|
|
1469
|
+
): void {
|
|
1465
1470
|
assert(context instanceof SessionContext);
|
|
1466
1471
|
assert(historyReadRequest instanceof HistoryReadRequest);
|
|
1467
1472
|
assert(typeof callback === "function");
|
|
1468
1473
|
|
|
1469
1474
|
const timestampsToReturn = historyReadRequest.timestampsToReturn;
|
|
1470
1475
|
const historyReadDetails = historyReadRequest.historyReadDetails! as HistoryReadDetails;
|
|
1476
|
+
const releaseContinuationPoints = historyReadRequest.releaseContinuationPoints;
|
|
1477
|
+
assert(historyReadDetails instanceof HistoryReadDetails);
|
|
1478
|
+
// ReadAnnotationDataDetails | ReadAtTimeDetails | ReadEventDetails | ReadProcessedDetails | ReadRawModifiedDetails;
|
|
1471
1479
|
|
|
1472
1480
|
const nodesToRead = historyReadRequest.nodesToRead || ([] as HistoryReadValueId[]);
|
|
1473
|
-
|
|
1474
|
-
assert(historyReadDetails instanceof HistoryReadDetails);
|
|
1475
1481
|
assert(Array.isArray(nodesToRead));
|
|
1476
1482
|
|
|
1477
1483
|
// special cases with ReadProcessedDetails
|
|
1478
|
-
|
|
1484
|
+
interface M {
|
|
1485
|
+
nodeToRead: HistoryReadValueId;
|
|
1486
|
+
processDetail: ReadProcessedDetails;
|
|
1487
|
+
index: number;
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
const _q = async (m: M): Promise<HistoryReadResult> => {
|
|
1491
|
+
return new Promise((resolve) => {
|
|
1492
|
+
const continuationPoint = m.nodeToRead.continuationPoint;
|
|
1493
|
+
this._historyReadSingleNode(
|
|
1494
|
+
context,
|
|
1495
|
+
m.nodeToRead,
|
|
1496
|
+
m.processDetail,
|
|
1497
|
+
timestampsToReturn,
|
|
1498
|
+
{ continuationPoint, releaseContinuationPoints /**, index = ??? */ },
|
|
1499
|
+
(err: Error | null, result?: any) => {
|
|
1500
|
+
if (err && !result) {
|
|
1501
|
+
errorLog("Internal error", err.message);
|
|
1502
|
+
result = new HistoryReadResult({ statusCode: StatusCodes.BadInternalError });
|
|
1503
|
+
}
|
|
1504
|
+
resolve(result);
|
|
1505
|
+
}
|
|
1506
|
+
);
|
|
1507
|
+
});
|
|
1508
|
+
};
|
|
1509
|
+
|
|
1479
1510
|
if (historyReadDetails instanceof ReadProcessedDetails) {
|
|
1480
1511
|
//
|
|
1481
1512
|
if (!historyReadDetails.aggregateType || historyReadDetails.aggregateType.length !== nodesToRead.length) {
|
|
1482
1513
|
return callback(null, [new HistoryReadResult({ statusCode: StatusCodes.BadInvalidArgument })]);
|
|
1483
1514
|
}
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1515
|
+
const promises: Promise<HistoryReadResult>[] = [];
|
|
1516
|
+
let index = 0;
|
|
1517
|
+
for (const nodeToRead of nodesToRead) {
|
|
1518
|
+
const aggregateType = historyReadDetails.aggregateType[index];
|
|
1519
|
+
const processDetail = new ReadProcessedDetails({ ...historyReadDetails, aggregateType: [aggregateType] });
|
|
1520
|
+
promises.push(_q({ nodeToRead, processDetail, index }));
|
|
1521
|
+
index++;
|
|
1488
1522
|
}
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
// const aggregateType = historyReadDetails.aggregateType[i];
|
|
1493
|
-
// const key = nodesToRead.toString();
|
|
1494
|
-
// if (!map.has(key)) {
|
|
1495
|
-
// map.set(key, {
|
|
1496
|
-
// nodeToRead,
|
|
1497
|
-
// indexes: [],
|
|
1498
|
-
// processDetail: new ReadProcessedDetails({ ...historyReadDetails, aggregateType: [] })
|
|
1499
|
-
// });
|
|
1500
|
-
// }
|
|
1501
|
-
// map.get(key)!.processDetail.aggregateType?.push(aggregateType);
|
|
1502
|
-
// map.get(key)!.indexes.push(i);
|
|
1503
|
-
// }
|
|
1504
|
-
// const m = [...map.values()];
|
|
1505
|
-
const elements: M[] = [];
|
|
1506
|
-
for (let i = 0; i < nodesToRead.length; i++) {
|
|
1507
|
-
const nodeToRead = nodesToRead[i];
|
|
1508
|
-
const aggregateType = historyReadDetails.aggregateType[i];
|
|
1509
|
-
elements.push({
|
|
1510
|
-
indexes: [i],
|
|
1511
|
-
nodeToRead,
|
|
1512
|
-
processDetail: new ReadProcessedDetails({ ...historyReadDetails, aggregateType: [aggregateType] })
|
|
1513
|
-
});
|
|
1514
|
-
}
|
|
1515
|
-
|
|
1516
|
-
async.forEach(
|
|
1517
|
-
elements,
|
|
1518
|
-
(m: M, _local_callback: (err: Error | null) => void) => {
|
|
1519
|
-
this._historyReadSingleNode(
|
|
1520
|
-
context,
|
|
1521
|
-
m.nodeToRead,
|
|
1522
|
-
m.processDetail,
|
|
1523
|
-
timestampsToReturn,
|
|
1524
|
-
(err: Error | null, result?: any) => {
|
|
1525
|
-
if (err && !result) {
|
|
1526
|
-
result = new HistoryReadResult({ statusCode: StatusCodes.BadInternalError });
|
|
1527
|
-
}
|
|
1528
|
-
historyData.push(result);
|
|
1529
|
-
_local_callback(null);
|
|
1530
|
-
}
|
|
1531
|
-
);
|
|
1532
|
-
},
|
|
1533
|
-
(err?: Error | null) => {
|
|
1534
|
-
callback(err!, historyData);
|
|
1535
|
-
}
|
|
1536
|
-
);
|
|
1523
|
+
Promise.all(promises).then((results: HistoryReadResult[]) => {
|
|
1524
|
+
callback(null, results);
|
|
1525
|
+
});
|
|
1537
1526
|
return;
|
|
1538
1527
|
}
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1528
|
+
|
|
1529
|
+
const _r = async (nodeToRead: HistoryReadValueId, index: number) => {
|
|
1530
|
+
const continuationPoint = nodeToRead.continuationPoint;
|
|
1531
|
+
return new Promise<HistoryReadResult>((resolve, reject) => {
|
|
1542
1532
|
this._historyReadSingleNode(
|
|
1543
1533
|
context,
|
|
1544
1534
|
nodeToRead,
|
|
1545
1535
|
historyReadDetails,
|
|
1546
1536
|
timestampsToReturn,
|
|
1537
|
+
{ continuationPoint, releaseContinuationPoints, index },
|
|
1547
1538
|
(err: Error | null, result?: any) => {
|
|
1548
1539
|
if (err && !result) {
|
|
1549
1540
|
result = new HistoryReadResult({ statusCode: StatusCodes.BadInternalError });
|
|
1550
1541
|
}
|
|
1551
|
-
|
|
1552
|
-
cbNode();
|
|
1542
|
+
resolve(result);
|
|
1553
1543
|
// it's not guaranteed that the historical read process is really asynchronous
|
|
1554
1544
|
}
|
|
1555
1545
|
);
|
|
1556
|
-
}
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1546
|
+
});
|
|
1547
|
+
};
|
|
1548
|
+
const promises: Promise<HistoryReadResult>[] = [];
|
|
1549
|
+
let index = 0;
|
|
1550
|
+
for (const nodeToRead of nodesToRead) {
|
|
1551
|
+
promises.push(_r(nodeToRead, index));
|
|
1552
|
+
index++;
|
|
1553
|
+
}
|
|
1554
|
+
Promise.all(promises).then((results: HistoryReadResult[]) => {
|
|
1555
|
+
callback(null, results);
|
|
1556
|
+
});
|
|
1562
1557
|
}
|
|
1563
1558
|
|
|
1564
1559
|
public getOldestUnactivatedSession(): ServerSession | null {
|
|
@@ -1677,7 +1672,7 @@ export class ServerEngine extends EventEmitter {
|
|
|
1677
1672
|
* against data loss in the case of a Session termination. In these cases, the Subscription can be reassigned to
|
|
1678
1673
|
* another Client before its lifetime expires.
|
|
1679
1674
|
*/
|
|
1680
|
-
public closeSession(authenticationToken: NodeId, deleteSubscriptions: boolean, reason: ClosingReason) {
|
|
1675
|
+
public closeSession(authenticationToken: NodeId, deleteSubscriptions: boolean, reason: ClosingReason): void {
|
|
1681
1676
|
reason = reason || "CloseSession";
|
|
1682
1677
|
assert(typeof reason === "string");
|
|
1683
1678
|
assert(reason === "Timeout" || reason === "Terminated" || reason === "CloseSession" || reason === "Forcing");
|
|
@@ -1945,7 +1940,7 @@ export class ServerEngine extends EventEmitter {
|
|
|
1945
1940
|
}
|
|
1946
1941
|
}
|
|
1947
1942
|
|
|
1948
|
-
|
|
1943
|
+
protected _unexposeSubscriptionDiagnostics(subscription: Subscription): void {
|
|
1949
1944
|
const subscriptionDiagnosticsArray = this._getServerSubscriptionDiagnosticsArrayNode();
|
|
1950
1945
|
const subscriptionDiagnostics = subscription.subscriptionDiagnostics;
|
|
1951
1946
|
assert(subscriptionDiagnostics instanceof SubscriptionDiagnosticsDataType);
|
|
@@ -1965,13 +1960,13 @@ export class ServerEngine extends EventEmitter {
|
|
|
1965
1960
|
* create a new subscription
|
|
1966
1961
|
* @return {Subscription}
|
|
1967
1962
|
*/
|
|
1968
|
-
public _createSubscriptionOnSession(session: ServerSession, request: CreateSubscriptionRequestLike) {
|
|
1969
|
-
assert(
|
|
1970
|
-
assert(
|
|
1971
|
-
assert(
|
|
1972
|
-
assert(
|
|
1973
|
-
assert(
|
|
1974
|
-
assert(
|
|
1963
|
+
public _createSubscriptionOnSession(session: ServerSession, request: CreateSubscriptionRequestLike): Subscription {
|
|
1964
|
+
assert(Object.prototype.hasOwnProperty.call(request, "requestedPublishingInterval")); // Duration
|
|
1965
|
+
assert(Object.prototype.hasOwnProperty.call(request, "requestedLifetimeCount")); // Counter
|
|
1966
|
+
assert(Object.prototype.hasOwnProperty.call(request, "requestedMaxKeepAliveCount")); // Counter
|
|
1967
|
+
assert(Object.prototype.hasOwnProperty.call(request, "maxNotificationsPerPublish")); // Counter
|
|
1968
|
+
assert(Object.prototype.hasOwnProperty.call(request, "publishingEnabled")); // Boolean
|
|
1969
|
+
assert(Object.prototype.hasOwnProperty.call(request, "priority")); // Byte
|
|
1975
1970
|
|
|
1976
1971
|
// adjust publishing parameters
|
|
1977
1972
|
const publishingInterval = request.requestedPublishingInterval || 0;
|
|
@@ -1997,6 +1992,7 @@ export class ServerEngine extends EventEmitter {
|
|
|
1997
1992
|
assert((subscription.publishEngine as any) === session.publishEngine);
|
|
1998
1993
|
session.publishEngine.add_subscription(subscription);
|
|
1999
1994
|
|
|
1995
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
2000
1996
|
const engine = this;
|
|
2001
1997
|
subscription.once("terminated", function (this: Subscription) {
|
|
2002
1998
|
engine._unexposeSubscriptionDiagnostics(this);
|
|
@@ -2009,7 +2005,7 @@ export class ServerEngine extends EventEmitter {
|
|
|
2009
2005
|
if (nodeId.namespace >= (this.addressSpace?.getNamespaceArray().length || 0)) {
|
|
2010
2006
|
return null;
|
|
2011
2007
|
}
|
|
2012
|
-
const namespace = this.addressSpace
|
|
2008
|
+
const namespace = this.addressSpace!.getNamespace(nodeId.namespace)!;
|
|
2013
2009
|
return namespace.findNode2(nodeId)!;
|
|
2014
2010
|
}
|
|
2015
2011
|
|
|
@@ -2051,6 +2047,7 @@ export class ServerEngine extends EventEmitter {
|
|
|
2051
2047
|
nodeToRead: HistoryReadValueId,
|
|
2052
2048
|
historyReadDetails: HistoryReadDetails,
|
|
2053
2049
|
timestampsToReturn: TimestampsToReturn,
|
|
2050
|
+
continuationData: ContinuationData,
|
|
2054
2051
|
callback: CallbackT<HistoryReadResult>
|
|
2055
2052
|
): void {
|
|
2056
2053
|
assert(context instanceof SessionContext);
|
|
@@ -2062,6 +2059,9 @@ export class ServerEngine extends EventEmitter {
|
|
|
2062
2059
|
const continuationPoint = nodeToRead.continuationPoint;
|
|
2063
2060
|
|
|
2064
2061
|
timestampsToReturn = coerceTimestampsToReturn(timestampsToReturn);
|
|
2062
|
+
if (timestampsToReturn === TimestampsToReturn.Invalid) {
|
|
2063
|
+
return callback(null, new HistoryReadResult({ statusCode: StatusCodes.BadTimestampsToReturnInvalid }));
|
|
2064
|
+
}
|
|
2065
2065
|
|
|
2066
2066
|
const obj = this.__findNode(nodeId) as UAVariable;
|
|
2067
2067
|
|
|
@@ -2104,7 +2104,7 @@ export class ServerEngine extends EventEmitter {
|
|
|
2104
2104
|
historyReadDetails,
|
|
2105
2105
|
indexRange,
|
|
2106
2106
|
dataEncoding,
|
|
2107
|
-
|
|
2107
|
+
continuationData,
|
|
2108
2108
|
(err: Error | null, result?: HistoryReadResult) => {
|
|
2109
2109
|
if (err || !result) {
|
|
2110
2110
|
return callback(err);
|