node-opcua-server 2.70.3 → 2.72.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.
@@ -2,8 +2,10 @@
2
2
  * @module node-opcua-server
3
3
  */
4
4
  // tslint:disable:max-classes-per-file
5
- import { Certificate } from "node-opcua-crypto";
5
+ import { UInt32 } from "node-opcua-basic-types";
6
+ import { QualifiedName } from "node-opcua-data-model";
6
7
  import { SignedSoftwareCertificate } from "node-opcua-types";
8
+ import { OPCUAServer } from "./opcua_server";
7
9
 
8
10
  /**
9
11
  */
@@ -37,86 +39,162 @@ export class OperationLimits {
37
39
  public maxNodesPerTranslateBrowsePathsToNodeIds: number;
38
40
 
39
41
  constructor(options: OperationLimitsOptions) {
40
- /**
41
- * @property maxNodesPerRead
42
- * @default 0
43
- */
44
42
  this.maxNodesPerRead = options.maxNodesPerRead || 0;
45
- /**
46
- * @property maxNodesPerWrite
47
- * @default 0
48
- */
49
43
  this.maxNodesPerWrite = options.maxNodesPerWrite || 0;
50
- /**
51
- * @property maxNodesPerMethodCall
52
- * @default 0
53
- */
54
44
  this.maxNodesPerMethodCall = options.maxNodesPerMethodCall || 0;
55
- /**
56
- * @property maxNodesPerBrowse
57
- * @default 0
58
- */
59
45
  this.maxNodesPerBrowse = options.maxNodesPerBrowse || 0;
60
- /**
61
- * @property maxNodesPerRegisterNodes
62
- * @default 0
63
- */
64
46
  this.maxNodesPerRegisterNodes = options.maxNodesPerRegisterNodes || 0;
65
- /**
66
- * @property maxNodesPerNodeManagement
67
- * @default 0
68
- */
69
47
  this.maxNodesPerNodeManagement = options.maxNodesPerNodeManagement || 0;
70
- /**
71
- * @property maxMonitoredItemsPerCall
72
- * @default 0
73
- */
74
48
  this.maxMonitoredItemsPerCall = options.maxMonitoredItemsPerCall || 0;
75
- /**
76
- * @property maxNodesPerHistoryReadData
77
- */
78
49
  this.maxNodesPerHistoryReadData = options.maxNodesPerHistoryReadData || 0;
79
- /**
80
- * @property maxNodesPerHistoryReadEvents
81
- * @default 0
82
- */
83
50
  this.maxNodesPerHistoryReadEvents = options.maxNodesPerHistoryReadEvents || 0;
84
- /**
85
- * @property maxNodesPerHistoryUpdateData
86
- * @default 0
87
- */
88
51
  this.maxNodesPerHistoryUpdateData = options.maxNodesPerHistoryUpdateData || 0;
89
- /**
90
- * @property maxNodesPerHistoryUpdateEvents
91
- * @default 0
92
- */
93
52
  this.maxNodesPerHistoryUpdateEvents = options.maxNodesPerHistoryUpdateEvents || 0;
94
- /**
95
- * @property maxNodesPerTranslateBrowsePathsToNodeIds
96
- * @default 0
97
- */
98
53
  this.maxNodesPerTranslateBrowsePathsToNodeIds = options.maxNodesPerTranslateBrowsePathsToNodeIds || 0;
99
54
  }
100
55
  }
101
56
 
102
- export interface ServerCapabilitiesOptions {
103
- maxBrowseContinuationPoints?: number;
104
- maxHistoryContinuationPoints?: number;
105
- maxStringLength?: number;
106
- maxArrayLength?: number;
107
- maxByteStringLength?: number;
108
- maxQueryContinuationPoints?: number;
109
- minSupportedSampleRate?: number;
110
- operationLimits?: OperationLimitsOptions;
111
-
112
- serverProfileArray?: string[];
113
- localeIdArray?: string[];
114
- softwareCertificates?: SignedSoftwareCertificate[];
57
+ export interface IServerCapabilities {
58
+ maxBrowseContinuationPoints: number;
59
+ maxHistoryContinuationPoints: number;
60
+ maxStringLength: number;
61
+ maxArrayLength: number;
62
+ maxByteStringLength: number;
63
+ maxQueryContinuationPoints: number;
64
+ minSupportedSampleRate: number;
65
+ operationLimits: OperationLimitsOptions;
66
+
67
+ serverProfileArray: string[];
68
+ localeIdArray: string[];
69
+ softwareCertificates: SignedSoftwareCertificate[];
70
+
71
+ // new in 1.05
72
+ /**
73
+ * MaxSessions is an integer specifying the maximum number of concurrent
74
+ * Sessions the Server can support. The value specifies the
75
+ * maximum the Server can support under normal circumstances,
76
+ * therefore there is no guarantee the Server can always support
77
+ * the maximum.
78
+ */
79
+ maxSessions: UInt32;
80
+
81
+ /**
82
+ * MaxSubscriptions is an integer specifying the maximum number of
83
+ * Subscriptions the Server can support. The value specifies the
84
+ * maximum the Server can support under normal circumstances,
85
+ * therefore there is no guarantee the Server can always support
86
+ * the maximum.
87
+ */
88
+ maxSubscriptions: UInt32;
89
+
90
+ /**
91
+ * MaxMonitoredItems is an integer specifying the maximum number of
92
+ * MonitoredItems the Server can support. The value specifies the
93
+ * maximum the Server can support under normal circumstances,
94
+ * therefore there is no guarantee the Server can always support
95
+ * the maximum.
96
+ */
97
+ maxMonitoredItems: UInt32;
98
+
99
+ /**
100
+ * MaxSubscriptionsPerSession is an integer specifying the maximum number of
101
+ * Subscriptions per Session the Server can support. The value specifies the
102
+ * maximum the Server can support under normal circumstances,
103
+ * therefore there is no guarantee the Server can always support
104
+ * the maximum.
105
+ */
106
+ maxSubscriptionsPerSession: UInt32;
107
+
108
+ /**
109
+ * MaxMonitoredItemsPerSubscription is an integer specifying the maximum number of
110
+ * MonitoredItems per Subscription the Server can support. The value specifies the
111
+ * maximum the Server can support under normal circumstances,
112
+ * therefore there is no guarantee the Server can always support
113
+ * the maximum
114
+ */
115
+ maxMonitoredItemsPerSubscription: UInt32;
116
+
117
+ /**
118
+ * MaxSelectClauseParameters is an integer specifying the maximum number of
119
+ * EventField SelectClause Parameters the Server can support for an EventFilter.
120
+ * The value specifies the maximum the Server can support under normal circumstances,
121
+ * therefore there is no guarantee the Server can always support
122
+ * the maximum.
123
+ */
124
+ maxSelectClauseParameters: UInt32;
125
+
126
+ /**
127
+ * MaxWhereClauseParameters is an integer specifying the maximum number of
128
+ * EventField WhereClause Parameters the Server can support for an EventFilter.
129
+ * The value specifies the maximum the Server can support under normal circumstances,
130
+ * therefore there is no guarantee the Server can always support the maximum
131
+ */
132
+ maxWhereClauseParameters: UInt32;
133
+
134
+ /**
135
+ * (draft)
136
+ * MaxMonitoredItemsQueueSize is an integer specifying the maximum size of MonitoredItem
137
+ * queues. The value specifies the maximum the Server can support under normal circumstances,
138
+ * therefore there is no guarantee the Server can always support the maximum.
139
+ *
140
+ */
141
+ maxMonitoredItemsQueueSize: UInt32;
142
+
143
+ /**
144
+ *
145
+ * ConformanceUnits is a QualifiedName array specifying the set of conformance units
146
+ * the Server supports. This list should be limited to the ConformanceUnits the Server
147
+ * supports in its current configuration.
148
+ *
149
+ */
150
+ conformanceUnits: QualifiedName[];
115
151
  }
152
+ export type ServerCapabilitiesOptions = Partial<IServerCapabilities>;
153
+
154
+ export const defaultServerCapabilities: IServerCapabilities = {
155
+ maxBrowseContinuationPoints: 0,
156
+ maxHistoryContinuationPoints: 0,
157
+ maxStringLength: 65535,
158
+ maxArrayLength: 65535,
159
+ maxByteStringLength: 65535,
160
+ maxQueryContinuationPoints: 0,
161
+
162
+ minSupportedSampleRate: 100,
163
+
164
+ operationLimits: {
165
+ maxNodesPerBrowse: 0,
166
+ maxNodesPerHistoryReadData: 0,
167
+ maxNodesPerHistoryReadEvents: 0,
168
+ maxNodesPerHistoryUpdateData: 0,
169
+ maxNodesPerHistoryUpdateEvents: 0,
170
+ maxNodesPerMethodCall: 0,
171
+ maxNodesPerNodeManagement: 0,
172
+ maxNodesPerRead: 0,
173
+ maxNodesPerRegisterNodes: 0,
174
+ maxNodesPerWrite: 0,
175
+ maxNodesPerTranslateBrowsePathsToNodeIds: 0,
176
+ maxMonitoredItemsPerCall: 0
177
+ },
178
+
179
+ serverProfileArray: [],
180
+ localeIdArray: [],
181
+ softwareCertificates: [],
182
+
183
+ maxSessions: 10,
184
+ maxSubscriptions: 100,
185
+ maxMonitoredItems: 1000000, // 1 million
186
+ maxSubscriptionsPerSession: 10,
187
+ maxMonitoredItemsPerSubscription: 100000, // one hundred thousand
188
+ maxSelectClauseParameters: 100,
189
+ maxWhereClauseParameters: 100,
190
+ maxMonitoredItemsQueueSize: 60000,
191
+
192
+ conformanceUnits: []
193
+ };
116
194
 
117
195
  /**
118
196
  */
119
- export class ServerCapabilities {
197
+ export class ServerCapabilities implements IServerCapabilities {
120
198
  public maxBrowseContinuationPoints: number;
121
199
  public maxHistoryContinuationPoints: number;
122
200
  public maxStringLength: number;
@@ -130,6 +208,18 @@ export class ServerCapabilities {
130
208
  public localeIdArray: string[];
131
209
  public softwareCertificates: SignedSoftwareCertificate[];
132
210
 
211
+ // new in 1.05
212
+ public maxSessions: UInt32;
213
+ public maxSubscriptions: UInt32;
214
+ public maxMonitoredItems: UInt32;
215
+ public maxSubscriptionsPerSession: UInt32;
216
+ public maxMonitoredItemsPerSubscription: UInt32;
217
+ public maxSelectClauseParameters: UInt32;
218
+ public maxWhereClauseParameters: UInt32;
219
+ public maxMonitoredItemsQueueSize: UInt32;
220
+ public conformanceUnits: QualifiedName[];
221
+
222
+ // eslint-disable-next-line complexity
133
223
  constructor(options: ServerCapabilitiesOptions) {
134
224
  options = options || {};
135
225
  options.operationLimits = options.operationLimits || {};
@@ -137,36 +227,33 @@ export class ServerCapabilities {
137
227
  this.serverProfileArray = options.serverProfileArray || [];
138
228
  this.localeIdArray = options.localeIdArray || [];
139
229
  this.softwareCertificates = options.softwareCertificates || [];
140
- /**
141
- * @property maxArrayLength
142
- */
143
- this.maxArrayLength = options.maxArrayLength || 0;
144
- /**
145
- * @property maxStringLength
146
- */
147
- this.maxStringLength = options.maxStringLength || 0;
148
- /**
149
- * @property maxByteStringLength
150
- */
151
- this.maxByteStringLength = options.maxByteStringLength || 0;
152
- /**
153
- * @property maxBrowseContinuationPoints
154
- */
155
- this.maxBrowseContinuationPoints = options.maxBrowseContinuationPoints || 0;
156
- /**
157
- * @property maxQueryContinuationPoints
158
- */
159
- this.maxQueryContinuationPoints = options.maxQueryContinuationPoints || 0;
160
- /**
161
- * @property maxHistoryContinuationPoints
162
- */
163
- this.maxHistoryContinuationPoints = options.maxHistoryContinuationPoints || 0;
164
-
165
- /**
166
- * @property operationLimits
167
- */
230
+
231
+ this.maxArrayLength = options.maxArrayLength || defaultServerCapabilities.maxArrayLength;
232
+ this.maxStringLength = options.maxStringLength || defaultServerCapabilities.maxStringLength;
233
+ this.maxByteStringLength = options.maxByteStringLength || defaultServerCapabilities.maxByteStringLength;
234
+ this.maxBrowseContinuationPoints =
235
+ options.maxBrowseContinuationPoints || defaultServerCapabilities.maxBrowseContinuationPoints;
236
+ this.maxQueryContinuationPoints =
237
+ options.maxQueryContinuationPoints || defaultServerCapabilities.maxQueryContinuationPoints;
238
+ this.maxHistoryContinuationPoints =
239
+ options.maxHistoryContinuationPoints || defaultServerCapabilities.maxHistoryContinuationPoints;
240
+
168
241
  this.operationLimits = new OperationLimits(options.operationLimits);
169
242
 
170
- this.minSupportedSampleRate = 100; // to do adjust me
243
+ this.minSupportedSampleRate = options.minSupportedSampleRate || defaultServerCapabilities.minSupportedSampleRate; // to do adjust me
244
+
245
+ // new in 1.05
246
+ this.maxSessions = options.maxSessions || defaultServerCapabilities.maxSessions;
247
+
248
+ this.maxSubscriptionsPerSession = options.maxSubscriptionsPerSession || defaultServerCapabilities.maxSubscriptionsPerSession;
249
+ this.maxSubscriptions = options.maxSubscriptions || defaultServerCapabilities.maxSubscriptions;
250
+ this.maxMonitoredItems = options.maxMonitoredItems || defaultServerCapabilities.maxMonitoredItems;
251
+ this.maxMonitoredItemsPerSubscription =
252
+ options.maxMonitoredItemsPerSubscription || defaultServerCapabilities.maxMonitoredItemsPerSubscription;
253
+ this.maxSelectClauseParameters = options.maxSelectClauseParameters || defaultServerCapabilities.maxSelectClauseParameters;
254
+ this.maxWhereClauseParameters = options.maxWhereClauseParameters || defaultServerCapabilities.maxWhereClauseParameters;
255
+ this.maxMonitoredItemsQueueSize =
256
+ options.maxMonitoredItemsQueueSize || defaultServerCapabilities.maxMonitoredItemsQueueSize;
257
+ this.conformanceUnits = options.conformanceUnits || defaultServerCapabilities.conformanceUnits;
171
258
  }
172
259
  }
@@ -11,7 +11,7 @@ import * as async from "async";
11
11
  import { assert } from "node-opcua-assert";
12
12
  import { ICertificateManager, OPCUACertificateManager } from "node-opcua-certificate-manager";
13
13
  import { Certificate, convertPEMtoDER, makeSHA1Thumbprint, PrivateKeyPEM, split_der } from "node-opcua-crypto";
14
- import { checkDebugFlag, make_debugLog, make_errorLog } from "node-opcua-debug";
14
+ import { checkDebugFlag, make_debugLog, make_errorLog, make_warningLog } from "node-opcua-debug";
15
15
  import { getFullyQualifiedDomainName, resolveFullyQualifiedDomainName } from "node-opcua-hostname";
16
16
  import {
17
17
  fromURI,
@@ -32,6 +32,7 @@ import { ISocketData } from "./i_socket_data";
32
32
 
33
33
  const debugLog = make_debugLog(__filename);
34
34
  const errorLog = make_errorLog(__filename);
35
+ const warningLog = make_warningLog(__filename);
35
36
  const doDebug = checkDebugFlag(__filename);
36
37
 
37
38
  const default_transportProfileUri = "http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary";
@@ -704,14 +705,14 @@ export class OPCUAServerEndPoint extends EventEmitter implements ServerSecureCha
704
705
 
705
706
  const establish_connection = () => {
706
707
  const nbConnections = Object.keys(this._channels).length;
707
- debugLog(
708
- " nbConnections ",
709
- nbConnections,
710
- " self._server.maxConnections",
711
- this._server!.maxConnections,
712
- this.maxConnections
713
- );
714
708
  if (nbConnections >= this.maxConnections) {
709
+ warningLog(
710
+ " nbConnections ",
711
+ nbConnections,
712
+ " self._server.maxConnections",
713
+ this._server!.maxConnections,
714
+ this.maxConnections
715
+ );
715
716
  deny_connection();
716
717
  return;
717
718
  }
@@ -314,6 +314,7 @@ export class ServerEngine extends EventEmitter {
314
314
  private _applicationUri: string;
315
315
  private _expectedShutdownTime!: Date;
316
316
  private _serverStatus: ServerStatusDataType;
317
+ private _globalCounter: { totalMonitoredItemCount: number } = { totalMonitoredItemCount: 0 };
317
318
 
318
319
  constructor(options: ServerEngineOptions) {
319
320
  super();
@@ -964,6 +965,32 @@ export class ServerEngine extends EventEmitter {
964
965
  return this.serverCapabilities.maxHistoryContinuationPoints;
965
966
  });
966
967
 
968
+ // new in 1.05
969
+ bindStandardScalar(VariableIds.Server_ServerCapabilities_MaxSessions, DataType.UInt32, () => {
970
+ return this.serverCapabilities.maxSessions;
971
+ });
972
+ bindStandardScalar(VariableIds.Server_ServerCapabilities_MaxSubscriptions, DataType.UInt32, () => {
973
+ return this.serverCapabilities.maxSubscriptions;
974
+ });
975
+ bindStandardScalar(VariableIds.Server_ServerCapabilities_MaxMonitoredItems, DataType.UInt32, () => {
976
+ return this.serverCapabilities.maxMonitoredItems;
977
+ });
978
+ bindStandardScalar(VariableIds.Server_ServerCapabilities_MaxSubscriptionsPerSession, DataType.UInt32, () => {
979
+ return this.serverCapabilities.maxSubscriptionsPerSession;
980
+ });
981
+ bindStandardScalar(VariableIds.Server_ServerCapabilities_MaxSelectClauseParameters, DataType.UInt32, () => {
982
+ return this.serverCapabilities.maxSelectClauseParameters;
983
+ });
984
+ bindStandardScalar(VariableIds.Server_ServerCapabilities_MaxWhereClauseParameters, DataType.UInt32, () => {
985
+ return this.serverCapabilities.maxWhereClauseParameters;
986
+ });
987
+ //bindStandardArray(VariableIds.Server_ServerCapabilities_ConformanceUnits, DataType.QualifiedName, () => {
988
+ // return this.serverCapabilities.conformanceUnits;
989
+ //});
990
+ bindStandardScalar(VariableIds.Server_ServerCapabilities_MaxMonitoredItemsPerSubscription, DataType.UInt32, () => {
991
+ return this.serverCapabilities.maxMonitoredItemsPerSubscription;
992
+ });
993
+
967
994
  // added by DI : Server-specific period of time in milliseconds until the Server will revoke a lock.
968
995
  // TODO bindStandardScalar(VariableIds.Server_ServerCapabilities_MaxInactiveLockTime,
969
996
  // TODO DataType.UInt16, function () {
@@ -2010,7 +2037,9 @@ export class ServerEngine extends EventEmitter {
2010
2037
  publishingEnabled: request.publishingEnabled,
2011
2038
  publishingInterval,
2012
2039
  // -------------------
2013
- sessionId: NodeId.nullNodeId
2040
+ sessionId: NodeId.nullNodeId,
2041
+ globalCounter: this._globalCounter,
2042
+ serverCapabilities: this.serverCapabilities // shared
2014
2043
  });
2015
2044
 
2016
2045
  // add subscriptionDiagnostics
@@ -105,6 +105,7 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
105
105
  public nodeId: NodeId;
106
106
  public sessionName = "";
107
107
 
108
+
108
109
  public publishEngine: ServerSidePublishEngine;
109
110
  public sessionObject: any;
110
111
  public readonly creationDate: Date;
@@ -10,7 +10,7 @@ import { AddressSpace, BaseNode, Duration, UAObjectType } from "node-opcua-addre
10
10
  import { checkSelectClauses } from "node-opcua-address-space";
11
11
  import { SessionContext } from "node-opcua-address-space";
12
12
  import { assert } from "node-opcua-assert";
13
- import { Byte } from "node-opcua-basic-types";
13
+ import { Byte, UInt32 } from "node-opcua-basic-types";
14
14
  import { SubscriptionDiagnosticsDataType } from "node-opcua-common";
15
15
  import { NodeClass, AttributeIds, isValidDataEncoding } from "node-opcua-data-model";
16
16
  import { TimestampsToReturn } from "node-opcua-data-value";
@@ -312,6 +312,10 @@ function createSubscriptionDiagnostics(subscription: Subscription): Subscription
312
312
  return subscriptionDiagnostics as SubscriptionDiagnosticsDataTypePriv;
313
313
  }
314
314
 
315
+ interface IGlobalMonitoredItemCounter {
316
+ totalMonitoredItemCount: number;
317
+ }
318
+
315
319
  export interface SubscriptionOptions {
316
320
  sessionId?: NodeId;
317
321
  /**
@@ -342,6 +346,9 @@ export interface SubscriptionOptions {
342
346
  * a unique identifier
343
347
  */
344
348
  id?: number;
349
+
350
+ serverCapabilities: ServerCapabilitiesPartial;
351
+ globalCounter: IGlobalMonitoredItemCounter;
345
352
  }
346
353
 
347
354
  let g_monitoredItemId = Math.ceil(Math.random() * 100000);
@@ -435,6 +442,11 @@ export interface MonitoredItemBase {
435
442
  export type CreateMonitoredItemHook = (subscription: Subscription, monitoredItem: MonitoredItemBase) => Promise<StatusCode>;
436
443
  export type DeleteMonitoredItemHook = (subscription: Subscription, monitoredItem: MonitoredItemBase) => Promise<StatusCode>;
437
444
 
445
+ export interface ServerCapabilitiesPartial {
446
+ maxMonitoredItems: UInt32;
447
+ maxMonitoredItemsPerSubscription: UInt32;
448
+ }
449
+
438
450
  /**
439
451
  * The Subscription class used in the OPCUA server side.
440
452
  */
@@ -443,7 +455,19 @@ export class Subscription extends EventEmitter {
443
455
  public static defaultPublishingInterval = 1000; // one second
444
456
  public static maximumPublishingInterval: number = 1000 * 60 * 60 * 24 * 15; // 15 days
445
457
  public static maxNotificationPerPublishHighLimit = 1000;
446
- public static maxMonitoredItemCount = 20000;
458
+
459
+ /**
460
+ * maximum number of monitored item in a subscription to be used
461
+ * when serverCapacity.maxMonitoredItems and serverCapacity.maxMonitoredItemsPerSubscription are not set.
462
+ */
463
+ public static defaultMaxMonitoredItemCount = 20000;
464
+
465
+ /**
466
+ * @deprecated use serverCapacity.maxMonitoredItems and serverCapacity.maxMonitoredItemsPerSubscription instead
467
+ */
468
+ protected static get maxMonitoredItemCount() {
469
+ return Subscription.defaultMaxMonitoredItemCount;
470
+ }
447
471
 
448
472
  public static registry = new ObjectRegistry();
449
473
 
@@ -507,6 +531,9 @@ export class Subscription extends EventEmitter {
507
531
  private timerId: any;
508
532
  private _hasUncollectedMonitoredItemNotifications = false;
509
533
 
534
+ private globalCounter: IGlobalMonitoredItemCounter;
535
+ private serverCapabilities: ServerCapabilitiesPartial;
536
+
510
537
  constructor(options: SubscriptionOptions) {
511
538
  super();
512
539
 
@@ -566,6 +593,12 @@ export class Subscription extends EventEmitter {
566
593
  this._start_timer();
567
594
 
568
595
  debugLog(chalk.green(`creating subscription ${this.id}`));
596
+
597
+ this.serverCapabilities = options.serverCapabilities;
598
+ this.serverCapabilities.maxMonitoredItems = this.serverCapabilities.maxMonitoredItems || Subscription.defaultMaxMonitoredItemCount;
599
+ this.serverCapabilities.maxMonitoredItemsPerSubscription =
600
+ this.serverCapabilities.maxMonitoredItemsPerSubscription || Subscription.defaultMaxMonitoredItemCount;
601
+ this.globalCounter = options.globalCounter;
569
602
  }
570
603
 
571
604
  public getSessionId(): NodeId {
@@ -968,12 +1001,16 @@ export class Subscription extends EventEmitter {
968
1001
  if (statusCodeFilter !== StatusCodes.Good) {
969
1002
  return handle_error(statusCodeFilter);
970
1003
  }
971
- // xx var monitoringMode = monitoredItemCreateRequest.monitoringMode; // Disabled, Sampling, Reporting
972
- // xx var requestedParameters = monitoredItemCreateRequest.requestedParameters;
1004
+
973
1005
  // do we have enough room for new monitored items ?
974
- if (this.monitoredItemCount >= Subscription.maxMonitoredItemCount) {
1006
+ if (this.monitoredItemCount >= this.serverCapabilities.maxMonitoredItemsPerSubscription) {
1007
+ return handle_error(StatusCodes.BadTooManyMonitoredItems);
1008
+ }
1009
+
1010
+ if (this.globalCounter.totalMonitoredItemCount >= this.serverCapabilities.maxMonitoredItems) {
975
1011
  return handle_error(StatusCodes.BadTooManyMonitoredItems);
976
1012
  }
1013
+
977
1014
  const createResult = this._createMonitoredItemStep2(timestampsToReturn, monitoredItemCreateRequest, node);
978
1015
 
979
1016
  assert(createResult.statusCode === StatusCodes.Good);
@@ -1052,6 +1089,7 @@ export class Subscription extends EventEmitter {
1052
1089
  this.emit("removeMonitoredItem", monitoredItem);
1053
1090
 
1054
1091
  delete this.monitoredItems[monitoredItemId];
1092
+ this.globalCounter.totalMonitoredItemCount -= 1;
1055
1093
 
1056
1094
  this._removePendingNotificationsFor(monitoredItemId);
1057
1095
  // flush pending notifications
@@ -1724,7 +1762,10 @@ export class Subscription extends EventEmitter {
1724
1762
  monitoredItem.$subscription = this;
1725
1763
 
1726
1764
  assert(monitoredItem.monitoredItemId === monitoredItemId);
1765
+
1727
1766
  this.monitoredItems[monitoredItemId] = monitoredItem;
1767
+ this.globalCounter.totalMonitoredItemCount += 1;
1768
+
1728
1769
  assert(monitoredItem.clientHandle !== 4294967295);
1729
1770
 
1730
1771
  const filterResult = _process_filter(node, requestedParameters.filter);