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.
Files changed (75) hide show
  1. package/LICENSE +20 -20
  2. package/dist/base_server.js +12 -14
  3. package/dist/base_server.js.map +1 -1
  4. package/dist/factory.d.ts +4 -2
  5. package/dist/factory.js.map +1 -1
  6. package/dist/history_server_capabilities.js.map +1 -1
  7. package/dist/i_server_side_publish_engine.d.ts +1 -1
  8. package/dist/i_server_side_publish_engine.js +1 -1
  9. package/dist/i_server_side_publish_engine.js.map +1 -1
  10. package/dist/monitored_item.d.ts +3 -0
  11. package/dist/monitored_item.js +7 -14
  12. package/dist/monitored_item.js.map +1 -1
  13. package/dist/node_sampler.js +1 -1
  14. package/dist/node_sampler.js.map +1 -1
  15. package/dist/opcua_server.d.ts +29 -44
  16. package/dist/opcua_server.js +218 -262
  17. package/dist/opcua_server.js.map +1 -1
  18. package/dist/queue.js +1 -0
  19. package/dist/queue.js.map +1 -1
  20. package/dist/register_server_manager.d.ts +4 -1
  21. package/dist/register_server_manager.js +5 -5
  22. package/dist/register_server_manager.js.map +1 -1
  23. package/dist/register_server_manager_hidden.d.ts +1 -1
  24. package/dist/register_server_manager_hidden.js.map +1 -1
  25. package/dist/register_server_manager_mdns_only.d.ts +4 -1
  26. package/dist/register_server_manager_mdns_only.js +1 -1
  27. package/dist/register_server_manager_mdns_only.js.map +1 -1
  28. package/dist/server_capabilities.js.map +1 -1
  29. package/dist/server_end_point.d.ts +4 -1
  30. package/dist/server_end_point.js +10 -11
  31. package/dist/server_end_point.js.map +1 -1
  32. package/dist/server_engine.d.ts +11 -7
  33. package/dist/server_engine.js +72 -74
  34. package/dist/server_engine.js.map +1 -1
  35. package/dist/server_publish_engine.d.ts +4 -1
  36. package/dist/server_publish_engine.js +5 -5
  37. package/dist/server_publish_engine.js.map +1 -1
  38. package/dist/server_publish_engine_for_orphan_subscriptions.d.ts +2 -2
  39. package/dist/server_publish_engine_for_orphan_subscriptions.js.map +1 -1
  40. package/dist/server_session.d.ts +1 -1
  41. package/dist/server_session.js +24 -29
  42. package/dist/server_session.js.map +1 -1
  43. package/dist/server_subscription.d.ts +3 -1
  44. package/dist/server_subscription.js +6 -6
  45. package/dist/server_subscription.js.map +1 -1
  46. package/dist/sessions_compatible_for_transfer.js +2 -1
  47. package/dist/sessions_compatible_for_transfer.js.map +1 -1
  48. package/dist/validate_filter.js +4 -7
  49. package/dist/validate_filter.js.map +1 -1
  50. package/package.json +45 -44
  51. package/source/base_server.ts +19 -22
  52. package/source/factory.ts +5 -2
  53. package/source/history_server_capabilities.ts +3 -4
  54. package/source/i_channel_data.ts +4 -8
  55. package/source/i_register_server_manager.ts +0 -3
  56. package/source/i_server_side_publish_engine.ts +5 -6
  57. package/source/i_socket_data.ts +1 -1
  58. package/source/index.ts +14 -14
  59. package/source/monitored_item.ts +32 -44
  60. package/source/node_sampler.ts +82 -82
  61. package/source/opcua_server.ts +326 -357
  62. package/source/queue.ts +6 -7
  63. package/source/register_server_manager.ts +35 -23
  64. package/source/register_server_manager_hidden.ts +8 -10
  65. package/source/register_server_manager_mdns_only.ts +8 -13
  66. package/source/server_capabilities.ts +0 -5
  67. package/source/server_end_point.ts +28 -30
  68. package/source/server_engine.ts +122 -122
  69. package/source/server_publish_engine.ts +24 -21
  70. package/source/server_publish_engine_for_orphan_subscriptions.ts +26 -26
  71. package/source/server_session.ts +44 -49
  72. package/source/server_subscription.ts +23 -23
  73. package/source/sessions_compatible_for_transfer.ts +26 -25
  74. package/source/validate_filter.ts +8 -22
  75. package/test_helpers/create_certificates.js +1 -1
@@ -1,10 +1,9 @@
1
1
  /**
2
2
  * @module node-opcua-server
3
3
  */
4
- // tslint:disable:no-console
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, VariantLike } from "node-opcua-variant";
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 { NumericRange } from "node-opcua-numeric-range";
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(context.hasOwnProperty("session"), " expecting a session id in the context object");
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(context.hasOwnProperty("session"), " expecting a session id in the context object");
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 _shutdownTask: any[];
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(this.serverDiagnosticsSummary.hasOwnProperty("currentSessionCount"));
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(this.serverDiagnosticsSummary.hasOwnProperty("currentSubscriptionCount"));
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._shutdownTask = [];
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._shutdownTask = [];
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: any) {
451
+ public registerShutdownTask(task: (this: ServerEngine) => void): void {
458
452
  assert(typeof task === "function");
459
- this._shutdownTask.push(task);
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._shutdownTask.push(shutdownAndDisposeAddressSpace);
488
+ this._shutdownTasks.push(shutdownAndDisposeAddressSpace);
495
489
 
496
490
  // perform registerShutdownTask
497
- for (const task of this._shutdownTask) {
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: any, callback: any) {
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(nodeId) as UAServerDiagnosticsSummary<ServerDiagnosticsSummaryDataType>;
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(makeNodeId(VariableIds.Server_ServerStatus)) as UAServerStatus<DTServerStatus>;
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(nodesToBrowse: BrowseDescription[], context?: ISessionContext) {
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
- const historyData: HistoryReadResult[] = [];
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
- interface M {
1485
- nodeToRead: HistoryReadValueId;
1486
- processDetail: ReadProcessedDetails;
1487
- indexes: number[];
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
- // const map: Map<string, M> = new Map();
1490
- // for (let i = 0; i < nodesToRead.length; i++) {
1491
- // const nodeToRead = nodesToRead[i];
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
- async.eachSeries(
1540
- nodesToRead,
1541
- (nodeToRead: HistoryReadValueId, cbNode: () => void) => {
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
- historyData.push(result);
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
- (err?: Error | null) => {
1558
- assert(historyData.length === nodesToRead.length);
1559
- callback(err || null, historyData);
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
- private _unexposeSubscriptionDiagnostics(subscription: Subscription) {
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(request.hasOwnProperty("requestedPublishingInterval")); // Duration
1970
- assert(request.hasOwnProperty("requestedLifetimeCount")); // Counter
1971
- assert(request.hasOwnProperty("requestedMaxKeepAliveCount")); // Counter
1972
- assert(request.hasOwnProperty("maxNotificationsPerPublish")); // Counter
1973
- assert(request.hasOwnProperty("publishingEnabled")); // Boolean
1974
- assert(request.hasOwnProperty("priority")); // Byte
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?.getNamespace(nodeId.namespace)!;
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
- continuationPoint,
2107
+ continuationData,
2108
2108
  (err: Error | null, result?: HistoryReadResult) => {
2109
2109
  if (err || !result) {
2110
2110
  return callback(err);