node-opcua-server 2.97.0 → 2.98.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.
Files changed (91) hide show
  1. package/package.json +43 -43
  2. package/dist/base_server.d.ts +0 -110
  3. package/dist/base_server.js +0 -491
  4. package/dist/base_server.js.map +0 -1
  5. package/dist/factory.d.ts +0 -12
  6. package/dist/factory.js +0 -24
  7. package/dist/factory.js.map +0 -1
  8. package/dist/filter/check_where_clause_on_address_space.d.ts +0 -3
  9. package/dist/filter/check_where_clause_on_address_space.js +0 -23
  10. package/dist/filter/check_where_clause_on_address_space.js.map +0 -1
  11. package/dist/filter/extract_event_fields.d.ts +0 -10
  12. package/dist/filter/extract_event_fields.js +0 -18
  13. package/dist/filter/extract_event_fields.js.map +0 -1
  14. package/dist/helper.d.ts +0 -10
  15. package/dist/helper.js +0 -76
  16. package/dist/helper.js.map +0 -1
  17. package/dist/history_server_capabilities.d.ts +0 -35
  18. package/dist/history_server_capabilities.js +0 -44
  19. package/dist/history_server_capabilities.js.map +0 -1
  20. package/dist/i_channel_data.d.ts +0 -13
  21. package/dist/i_channel_data.js +0 -3
  22. package/dist/i_channel_data.js.map +0 -1
  23. package/dist/i_register_server_manager.d.ts +0 -16
  24. package/dist/i_register_server_manager.js +0 -3
  25. package/dist/i_register_server_manager.js.map +0 -1
  26. package/dist/i_server_side_publish_engine.d.ts +0 -36
  27. package/dist/i_server_side_publish_engine.js +0 -50
  28. package/dist/i_server_side_publish_engine.js.map +0 -1
  29. package/dist/i_socket_data.d.ts +0 -11
  30. package/dist/i_socket_data.js +0 -3
  31. package/dist/i_socket_data.js.map +0 -1
  32. package/dist/index.d.ts +0 -16
  33. package/dist/index.js +0 -33
  34. package/dist/index.js.map +0 -1
  35. package/dist/monitored_item.d.ts +0 -188
  36. package/dist/monitored_item.js +0 -1113
  37. package/dist/monitored_item.js.map +0 -1
  38. package/dist/node_sampler.d.ts +0 -3
  39. package/dist/node_sampler.js +0 -80
  40. package/dist/node_sampler.js.map +0 -1
  41. package/dist/opcua_server.d.ts +0 -747
  42. package/dist/opcua_server.js +0 -2429
  43. package/dist/opcua_server.js.map +0 -1
  44. package/dist/queue.d.ts +0 -11
  45. package/dist/queue.js +0 -72
  46. package/dist/queue.js.map +0 -1
  47. package/dist/register_server_manager.d.ts +0 -96
  48. package/dist/register_server_manager.js +0 -585
  49. package/dist/register_server_manager.js.map +0 -1
  50. package/dist/register_server_manager_hidden.d.ts +0 -17
  51. package/dist/register_server_manager_hidden.js +0 -28
  52. package/dist/register_server_manager_hidden.js.map +0 -1
  53. package/dist/register_server_manager_mdns_only.d.ts +0 -22
  54. package/dist/register_server_manager_mdns_only.js +0 -56
  55. package/dist/register_server_manager_mdns_only.js.map +0 -1
  56. package/dist/sampling_func.d.ts +0 -3
  57. package/dist/sampling_func.js +0 -3
  58. package/dist/sampling_func.js.map +0 -1
  59. package/dist/server_capabilities.d.ts +0 -148
  60. package/dist/server_capabilities.js +0 -102
  61. package/dist/server_capabilities.js.map +0 -1
  62. package/dist/server_end_point.d.ts +0 -185
  63. package/dist/server_end_point.js +0 -841
  64. package/dist/server_end_point.js.map +0 -1
  65. package/dist/server_engine.d.ts +0 -318
  66. package/dist/server_engine.js +0 -1775
  67. package/dist/server_engine.js.map +0 -1
  68. package/dist/server_publish_engine.d.ts +0 -113
  69. package/dist/server_publish_engine.js +0 -542
  70. package/dist/server_publish_engine.js.map +0 -1
  71. package/dist/server_publish_engine_for_orphan_subscriptions.d.ts +0 -16
  72. package/dist/server_publish_engine_for_orphan_subscriptions.js +0 -52
  73. package/dist/server_publish_engine_for_orphan_subscriptions.js.map +0 -1
  74. package/dist/server_session.d.ts +0 -185
  75. package/dist/server_session.js +0 -758
  76. package/dist/server_session.js.map +0 -1
  77. package/dist/server_subscription.d.ts +0 -421
  78. package/dist/server_subscription.js +0 -1348
  79. package/dist/server_subscription.js.map +0 -1
  80. package/dist/sessions_compatible_for_transfer.d.ts +0 -2
  81. package/dist/sessions_compatible_for_transfer.js +0 -40
  82. package/dist/sessions_compatible_for_transfer.js.map +0 -1
  83. package/dist/user_manager.d.ts +0 -32
  84. package/dist/user_manager.js +0 -99
  85. package/dist/user_manager.js.map +0 -1
  86. package/dist/user_manager_ua.d.ts +0 -3
  87. package/dist/user_manager_ua.js +0 -40
  88. package/dist/user_manager_ua.js.map +0 -1
  89. package/dist/validate_filter.d.ts +0 -5
  90. package/dist/validate_filter.js +0 -82
  91. package/dist/validate_filter.js.map +0 -1
@@ -1,1113 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.MonitoredItem = void 0;
13
- /**
14
- * @module node-opcua-server
15
- */
16
- const events_1 = require("events");
17
- const chalk = require("chalk");
18
- const node_opcua_assert_1 = require("node-opcua-assert");
19
- const node_opcua_address_space_1 = require("node-opcua-address-space");
20
- const node_opcua_service_filter_1 = require("node-opcua-service-filter");
21
- const node_opcua_data_model_1 = require("node-opcua-data-model");
22
- const node_opcua_data_model_2 = require("node-opcua-data-model");
23
- const node_opcua_data_value_1 = require("node-opcua-data-value");
24
- const node_opcua_debug_1 = require("node-opcua-debug");
25
- const node_opcua_numeric_range_1 = require("node-opcua-numeric-range");
26
- const node_opcua_object_registry_1 = require("node-opcua-object-registry");
27
- const node_opcua_service_filter_2 = require("node-opcua-service-filter");
28
- const node_opcua_service_read_1 = require("node-opcua-service-read");
29
- const node_opcua_service_subscription_1 = require("node-opcua-service-subscription");
30
- const node_opcua_service_subscription_2 = require("node-opcua-service-subscription");
31
- const node_opcua_status_code_1 = require("node-opcua-status-code");
32
- const node_opcua_types_1 = require("node-opcua-types");
33
- const node_opcua_variant_1 = require("node-opcua-variant");
34
- const node_sampler_1 = require("./node_sampler");
35
- const validate_filter_1 = require("./validate_filter");
36
- const check_where_clause_on_address_space_1 = require("./filter/check_where_clause_on_address_space");
37
- const defaultItemToMonitor = new node_opcua_service_read_1.ReadValueId({
38
- attributeId: node_opcua_data_model_2.AttributeIds.Value,
39
- indexRange: undefined
40
- });
41
- const debugLog = (0, node_opcua_debug_1.make_debugLog)(__filename);
42
- const doDebug = (0, node_opcua_debug_1.checkDebugFlag)(__filename);
43
- const doDebug2 = doDebug && false;
44
- const warningLog = (0, node_opcua_debug_1.make_warningLog)(__filename);
45
- function _adjust_sampling_interval(samplingInterval, node_minimumSamplingInterval) {
46
- (0, node_opcua_assert_1.assert)(typeof node_minimumSamplingInterval === "number", "expecting a number");
47
- if (samplingInterval === 0) {
48
- return node_minimumSamplingInterval === 0
49
- ? samplingInterval
50
- : Math.max(MonitoredItem.minimumSamplingInterval, node_minimumSamplingInterval);
51
- }
52
- (0, node_opcua_assert_1.assert)(samplingInterval >= 0, " this case should have been prevented outside");
53
- samplingInterval = samplingInterval || MonitoredItem.defaultSamplingInterval;
54
- samplingInterval = Math.max(samplingInterval, MonitoredItem.minimumSamplingInterval);
55
- samplingInterval = Math.min(samplingInterval, MonitoredItem.maximumSamplingInterval);
56
- samplingInterval =
57
- node_minimumSamplingInterval === 0 ? samplingInterval : Math.max(samplingInterval, node_minimumSamplingInterval);
58
- return samplingInterval;
59
- }
60
- const maxQueueSize = 5000;
61
- function _adjust_queue_size(queueSize) {
62
- queueSize = Math.min(queueSize, maxQueueSize);
63
- queueSize = Math.max(1, queueSize);
64
- return queueSize;
65
- }
66
- function _validate_parameters(monitoringParameters) {
67
- // xx assert(options instanceof MonitoringParameters);
68
- (0, node_opcua_assert_1.assert)(Object.prototype.hasOwnProperty.call(monitoringParameters, "clientHandle"));
69
- (0, node_opcua_assert_1.assert)(Object.prototype.hasOwnProperty.call(monitoringParameters, "samplingInterval"));
70
- (0, node_opcua_assert_1.assert)(isFinite(monitoringParameters.clientHandle));
71
- (0, node_opcua_assert_1.assert)(isFinite(monitoringParameters.samplingInterval));
72
- (0, node_opcua_assert_1.assert)(typeof monitoringParameters.discardOldest === "boolean");
73
- (0, node_opcua_assert_1.assert)(isFinite(monitoringParameters.queueSize));
74
- (0, node_opcua_assert_1.assert)(monitoringParameters.queueSize >= 0);
75
- }
76
- function statusCodeHasChanged(newDataValue, oldDataValue) {
77
- (0, node_opcua_assert_1.assert)(newDataValue instanceof node_opcua_data_value_1.DataValue);
78
- (0, node_opcua_assert_1.assert)(oldDataValue instanceof node_opcua_data_value_1.DataValue);
79
- return newDataValue.statusCode.value !== oldDataValue.statusCode.value;
80
- }
81
- function valueHasChanged(newDataValue, oldDataValue, deadbandType, deadbandValue) {
82
- (0, node_opcua_assert_1.assert)(newDataValue instanceof node_opcua_data_value_1.DataValue);
83
- (0, node_opcua_assert_1.assert)(oldDataValue instanceof node_opcua_data_value_1.DataValue);
84
- switch (deadbandType) {
85
- case node_opcua_service_subscription_2.DeadbandType.None:
86
- (0, node_opcua_assert_1.assert)(newDataValue.value instanceof node_opcua_variant_1.Variant);
87
- (0, node_opcua_assert_1.assert)(newDataValue.value instanceof node_opcua_variant_1.Variant);
88
- // No Deadband calculation should be applied.
89
- return (0, node_opcua_service_subscription_2.isOutsideDeadbandNone)(oldDataValue.value, newDataValue.value);
90
- case node_opcua_service_subscription_2.DeadbandType.Absolute:
91
- // AbsoluteDeadband
92
- return (0, node_opcua_service_subscription_2.isOutsideDeadbandAbsolute)(oldDataValue.value, newDataValue.value, deadbandValue);
93
- default: {
94
- // Percent_2 PercentDeadband (This type is specified in Part 8).
95
- (0, node_opcua_assert_1.assert)(deadbandType === node_opcua_service_subscription_2.DeadbandType.Percent);
96
- // The range of the deadbandValue is from 0.0 to 100.0 Percent.
97
- (0, node_opcua_assert_1.assert)(deadbandValue >= 0 && deadbandValue <= 100);
98
- // DeadbandType = PercentDeadband
99
- // For this type of deadband the deadbandValue is defined as the percentage of the EURange. That is,
100
- // it applies only to AnalogItems with an EURange Property that defines the typical value range for the
101
- // item. This range shall be multiplied with the deadbandValue and then compared to the actual value change
102
- // to determine the need for a data change notification. The following pseudo code shows how the deadband
103
- // is calculated:
104
- // DataChange if (absolute value of (last cached value - current value) >
105
- // (deadbandValue/100.0) * ((high-low) of EURange)))
106
- //
107
- // StatusCode BadDeadbandFilterInvalid (see Table 27).
108
- // If the Value of the MonitoredItem is an array, then the deadband calculation logic shall be applied to
109
- // each element of the array. If an element that requires a DataChange is found, then no further
110
- // deadband checking is necessary and the entire array shall be returned.
111
- (0, node_opcua_assert_1.assert)(this.node !== null, "expecting a valid address_space object here to get access the the EURange");
112
- const euRangeNode = this.node.getChildByName("EURange");
113
- if (euRangeNode && euRangeNode.nodeClass === node_opcua_data_model_1.NodeClass.Variable) {
114
- // double,double
115
- const rangeVariant = euRangeNode.readValue().value;
116
- return (0, node_opcua_service_subscription_2.isOutsideDeadbandPercent)(oldDataValue.value, newDataValue.value, deadbandValue, rangeVariant.value);
117
- }
118
- else {
119
- console.log("EURange is not of type Variable");
120
- }
121
- return true;
122
- }
123
- }
124
- }
125
- function timestampHasChanged(t1, t2) {
126
- if (t1 || !t2 || t2 || !t1) {
127
- return true;
128
- }
129
- if (!t1 || !t2) {
130
- return false;
131
- }
132
- return t1.getTime() !== t2.getTime();
133
- }
134
- function apply_dataChange_filter(newDataValue, oldDataValue) {
135
- var _a;
136
- /* istanbul ignore next */
137
- if (!this.filter || !(this.filter instanceof node_opcua_service_subscription_2.DataChangeFilter)) {
138
- throw new Error("Internal Error");
139
- }
140
- const trigger = this.filter.trigger;
141
- // istanbul ignore next
142
- if (doDebug) {
143
- try {
144
- debugLog("filter pass ?", node_opcua_service_subscription_2.DataChangeTrigger[trigger], (_a = this.oldDataValue) === null || _a === void 0 ? void 0 : _a.toString(), newDataValue.toString());
145
- if (trigger === node_opcua_service_subscription_2.DataChangeTrigger.Status ||
146
- trigger === node_opcua_service_subscription_2.DataChangeTrigger.StatusValue ||
147
- trigger === node_opcua_service_subscription_2.DataChangeTrigger.StatusValueTimestamp) {
148
- debugLog("statusCodeHasChanged ", statusCodeHasChanged(newDataValue, oldDataValue));
149
- }
150
- if (trigger === node_opcua_service_subscription_2.DataChangeTrigger.StatusValue || trigger === node_opcua_service_subscription_2.DataChangeTrigger.StatusValueTimestamp) {
151
- debugLog("valueHasChanged ", valueHasChanged.call(this, newDataValue, oldDataValue, this.filter.deadbandType, this.filter.deadbandValue));
152
- }
153
- if (trigger === node_opcua_service_subscription_2.DataChangeTrigger.StatusValueTimestamp) {
154
- debugLog("timestampHasChanged ", timestampHasChanged(newDataValue.sourceTimestamp, oldDataValue.sourceTimestamp));
155
- }
156
- }
157
- catch (err) {
158
- warningLog(err);
159
- }
160
- }
161
- switch (trigger) {
162
- case node_opcua_service_subscription_2.DataChangeTrigger.Status: {
163
- //
164
- // Status
165
- // Report a notification ONLY if the StatusCode associated with
166
- // the value changes. See Table 166 for StatusCodes defined in
167
- // this standard. Part 8 specifies additional StatusCodes that are
168
- // valid in particular for device data.
169
- return statusCodeHasChanged(newDataValue, oldDataValue);
170
- }
171
- case node_opcua_service_subscription_2.DataChangeTrigger.StatusValue: {
172
- // filtering value changes.
173
- // change. The Deadband filter can be used in addition for
174
- // Report a notification if either the StatusCode or the value
175
- // StatusValue
176
- // This is the default setting if no filter is set.
177
- return (statusCodeHasChanged(newDataValue, oldDataValue) ||
178
- valueHasChanged.call(this, newDataValue, oldDataValue, this.filter.deadbandType, this.filter.deadbandValue));
179
- }
180
- default: {
181
- // StatusValueTimestamp
182
- // Report a notification if either StatusCode, value or the
183
- // SourceTimestamp change.
184
- //
185
- // If a Deadband filter is specified,this trigger has the same behavior as STATUS_VALUE_1.
186
- //
187
- // If the DataChangeFilter is not applied to the monitored item, STATUS_VALUE_1
188
- // is the default reporting behavior
189
- (0, node_opcua_assert_1.assert)(trigger === node_opcua_service_subscription_2.DataChangeTrigger.StatusValueTimestamp);
190
- return (timestampHasChanged(newDataValue.sourceTimestamp, oldDataValue.sourceTimestamp) ||
191
- statusCodeHasChanged(newDataValue, oldDataValue) ||
192
- valueHasChanged.call(this, newDataValue, oldDataValue, this.filter.deadbandType, this.filter.deadbandValue));
193
- }
194
- }
195
- }
196
- const s = (a) => JSON.stringify(a, null, " ");
197
- function safeGuardRegiter(monitoredItem) {
198
- var _a, _b;
199
- monitoredItem.oldDataValue._$monitoredItem = (_b = (_a = monitoredItem.node) === null || _a === void 0 ? void 0 : _a.nodeId) === null || _b === void 0 ? void 0 : _b.toString();
200
- monitoredItem._$safeGuard = s(monitoredItem.oldDataValue);
201
- }
202
- function safeGuardVerify(monitoredItem) {
203
- if (monitoredItem._$safeGuard) {
204
- const verif = s(monitoredItem.oldDataValue || "");
205
- if (verif !== monitoredItem._$safeGuard) {
206
- console.log(verif, monitoredItem._$safeGuard);
207
- throw new Error("Internal error: DataValue has been altereed !!!");
208
- }
209
- }
210
- }
211
- function apply_filter(newDataValue) {
212
- if (!this.oldDataValue) {
213
- return true; // keep
214
- }
215
- // istanbul ignore next
216
- doDebug && safeGuardVerify(this);
217
- if (this.filter instanceof node_opcua_service_subscription_2.DataChangeFilter) {
218
- return apply_dataChange_filter.call(this, newDataValue, this.oldDataValue);
219
- }
220
- else {
221
- // if filter not set, by default report changes to Status or Value only
222
- if (newDataValue.statusCode.value !== this.oldDataValue.statusCode.value) {
223
- return true; // Keep because statusCode has changed ...
224
- }
225
- return !(0, node_opcua_variant_1.sameVariant)(newDataValue.value, this.oldDataValue.value);
226
- }
227
- }
228
- function setSemanticChangeBit(notification) {
229
- if (notification instanceof node_opcua_service_subscription_1.MonitoredItemNotification) {
230
- notification.value.statusCode = node_opcua_status_code_1.StatusCode.makeStatusCode(notification.value.statusCode || node_opcua_status_code_1.StatusCodes.Good, "SemanticChanged");
231
- }
232
- else if (notification instanceof node_opcua_data_value_1.DataValue) {
233
- notification.statusCode = node_opcua_status_code_1.StatusCode.makeStatusCode(notification.statusCode || node_opcua_status_code_1.StatusCodes.Good, "SemanticChanged");
234
- }
235
- }
236
- const useCommonTimer = true;
237
- function isSourceNewerThan(a, b) {
238
- var _a, _b;
239
- if (!b) {
240
- return true;
241
- }
242
- const at = ((_a = a.sourceTimestamp) === null || _a === void 0 ? void 0 : _a.getTime()) || 0;
243
- const bt = ((_b = b.sourceTimestamp) === null || _b === void 0 ? void 0 : _b.getTime()) || 0;
244
- if (at === bt) {
245
- return a.sourcePicoseconds > b.sourcePicoseconds;
246
- }
247
- return at > bt;
248
- }
249
- /**
250
- * a server side monitored item
251
- *
252
- * - Once created, the MonitoredItem will raised an "samplingEvent" event every "samplingInterval" millisecond
253
- * until {{#crossLink "MonitoredItem/terminate:method"}}{{/crossLink}} is called.
254
- *
255
- * - It is up to the event receiver to call {{#crossLink "MonitoredItem/recordValue:method"}}{{/crossLink}}.
256
- *
257
- */
258
- class MonitoredItem extends events_1.EventEmitter {
259
- get node() {
260
- return this._node;
261
- }
262
- set node(someNode) {
263
- throw new Error("Unexpected way to set node");
264
- }
265
- constructor(options) {
266
- super();
267
- this.samplingInterval = -1;
268
- this.discardOldest = true;
269
- this.queueSize = 0;
270
- this.samplingFunc = null;
271
- this._is_sampling = false;
272
- (0, node_opcua_assert_1.assert)(Object.prototype.hasOwnProperty.call(options, "monitoredItemId"));
273
- (0, node_opcua_assert_1.assert)(!options.monitoringMode, "use setMonitoring mode explicitly to activate the monitored item");
274
- options.itemToMonitor = options.itemToMonitor || defaultItemToMonitor;
275
- this._samplingId = undefined;
276
- this.clientHandle = 0; // invalid
277
- this.filter = null;
278
- this._set_parameters(options);
279
- this.monitoredItemId = options.monitoredItemId; // ( known as serverHandle)
280
- this.queue = [];
281
- this.overflow = false;
282
- this.oldDataValue = new node_opcua_data_value_1.DataValue({ statusCode: node_opcua_status_code_1.StatusCodes.BadDataUnavailable }); // unset initially
283
- // user has to call setMonitoringMode
284
- this.monitoringMode = node_opcua_service_subscription_1.MonitoringMode.Invalid;
285
- this.timestampsToReturn = (0, node_opcua_data_value_1.coerceTimestampsToReturn)(options.timestampsToReturn);
286
- this.itemToMonitor = options.itemToMonitor;
287
- this._node = null;
288
- this._semantic_version = 0;
289
- if (doDebug) {
290
- debugLog("Monitoring ", options.itemToMonitor.toString());
291
- }
292
- this._on_node_disposed_listener = null;
293
- MonitoredItem.registry.register(this);
294
- }
295
- setNode(node) {
296
- (0, node_opcua_assert_1.assert)(!this.node || this.node === node, "node already set");
297
- this._node = node;
298
- this._semantic_version = node.semantic_version;
299
- this._on_node_disposed_listener = () => this._on_node_disposed(this._node);
300
- this._node.on("dispose", this._on_node_disposed_listener);
301
- }
302
- setMonitoringMode(monitoringMode) {
303
- (0, node_opcua_assert_1.assert)(monitoringMode !== node_opcua_service_subscription_1.MonitoringMode.Invalid);
304
- if (monitoringMode === this.monitoringMode) {
305
- // nothing to do
306
- return;
307
- }
308
- const old_monitoringMode = this.monitoringMode;
309
- this.monitoringMode = monitoringMode;
310
- if (this.monitoringMode === node_opcua_service_subscription_1.MonitoringMode.Disabled) {
311
- this._stop_sampling();
312
- // OPCUA 1.03 part 4 : $5.12.4
313
- // setting the mode to DISABLED causes all queued Notifications to be deleted
314
- this._empty_queue();
315
- }
316
- else {
317
- (0, node_opcua_assert_1.assert)(this.monitoringMode === node_opcua_service_subscription_1.MonitoringMode.Sampling || this.monitoringMode === node_opcua_service_subscription_1.MonitoringMode.Reporting);
318
- // OPCUA 1.03 part 4 : $5.12.1.3
319
- // When a MonitoredItem is enabled (i.e. when the MonitoringMode is changed from DISABLED to
320
- // SAMPLING or REPORTING) or it is created in the enabled state, the Server shall report the first
321
- // sample as soon as possible and the time of this sample becomes the starting point for the next
322
- // sampling interval.
323
- const recordInitialValue = old_monitoringMode === node_opcua_service_subscription_1.MonitoringMode.Invalid || old_monitoringMode === node_opcua_service_subscription_1.MonitoringMode.Disabled;
324
- const installEventHandler = old_monitoringMode === node_opcua_service_subscription_1.MonitoringMode.Invalid;
325
- this._start_sampling(recordInitialValue);
326
- }
327
- }
328
- /**
329
- * Terminate the MonitoredItem.
330
- * @method terminate
331
- *
332
- * This will stop the internal sampling timer.
333
- */
334
- terminate() {
335
- this._stop_sampling();
336
- }
337
- dispose() {
338
- if (doDebug) {
339
- debugLog("DISPOSING MONITORED ITEM", this._node.nodeId.toString());
340
- }
341
- this._stop_sampling();
342
- MonitoredItem.registry.unregister(this);
343
- if (this._on_node_disposed_listener) {
344
- this._node.removeListener("dispose", this._on_node_disposed_listener);
345
- this._on_node_disposed_listener = null;
346
- }
347
- // x assert(this._samplingId === null,"Sampling Id must be null");
348
- this.oldDataValue = undefined;
349
- this.queue = [];
350
- this.itemToMonitor = null;
351
- this.filter = null;
352
- this.monitoredItemId = 0;
353
- this._node = null;
354
- this._semantic_version = 0;
355
- this.$subscription = undefined;
356
- this.removeAllListeners();
357
- (0, node_opcua_assert_1.assert)(!this._samplingId);
358
- (0, node_opcua_assert_1.assert)(!this._value_changed_callback);
359
- (0, node_opcua_assert_1.assert)(!this._semantic_changed_callback);
360
- (0, node_opcua_assert_1.assert)(!this._attribute_changed_callback);
361
- (0, node_opcua_assert_1.assert)(!this._on_opcua_event_received_callback);
362
- this._on_opcua_event_received_callback = null;
363
- this._attribute_changed_callback = null;
364
- this._semantic_changed_callback = null;
365
- this._on_opcua_event_received_callback = null;
366
- }
367
- get isSampling() {
368
- return (!!this._samplingId ||
369
- typeof this._value_changed_callback === "function" ||
370
- typeof this._attribute_changed_callback === "function");
371
- }
372
- toString() {
373
- var _a;
374
- let str = "";
375
- str += `monitored item nodeId : ${(_a = this.node) === null || _a === void 0 ? void 0 : _a.nodeId.toString()} \n`;
376
- str += ` sampling interval : ${this.samplingInterval} \n`;
377
- str += ` monitoredItemId : ${this.monitoredItemId} \n`;
378
- return str;
379
- }
380
- /**
381
- * @param dataValue the whole dataValue
382
- * @param skipChangeTest indicates whether recordValue should not check that dataValue is really
383
- * different from previous one, ( by checking timestamps but also variant value)
384
- * @private
385
- *
386
- * Notes:
387
- * - recordValue can only be called within timer event
388
- * - for performance reason, dataValue may be a shared value with the underlying node,
389
- * therefore recordValue must clone the dataValue to make sure it retains a snapshot
390
- * of the contain at the time recordValue was called.
391
- *
392
- * return true if the value has been recorded, false if not.
393
- *
394
- * Value will not be recorded :
395
- * * if the range do not overlap
396
- * * is !skipChangeTest and value is equal to previous value
397
- *
398
- */
399
- // eslint-disable-next-line complexity, max-statements
400
- recordValue(dataValue, skipChangeTest, indexRange) {
401
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
402
- if (!this.itemToMonitor) {
403
- // we must have a valid itemToMonitor(have this monitoredItem been disposed already ?)
404
- // istanbul ignore next
405
- doDebug && debugLog("recordValue => Rejected", (_a = this.node) === null || _a === void 0 ? void 0 : _a.browseName.toString(), " because no itemToMonitor");
406
- return false;
407
- }
408
- (0, node_opcua_assert_1.assert)(dataValue !== this.oldDataValue, "recordValue expects different dataValue to be provided");
409
- (0, node_opcua_assert_1.assert)(!dataValue.value || !this.oldDataValue || dataValue.value !== this.oldDataValue.value, "recordValue expects different dataValue.value to be provided");
410
- (0, node_opcua_assert_1.assert)(!dataValue.value || dataValue.value.isValid(), "expecting a valid variant value");
411
- const hasSemanticChanged = this.node && this.node.semantic_version !== this._semantic_version;
412
- // xx console.log("`\n----------------------------",skipChangeTest,this.clientHandle,
413
- // this.node.listenerCount("value_changed"),this.node.nodeId.toString());
414
- // xx console.log("events ---- ",this.node.eventNames().join("-"));
415
- // xx console.log("indexRange = ",indexRange ? indexRange.toString() :"");
416
- // xx console.log("this.itemToMonitor.indexRange = ",this.itemToMonitor.indexRange.toString());
417
- if (!hasSemanticChanged && indexRange && this.itemToMonitor.indexRange) {
418
- // we just ignore changes that do not fall within our range
419
- // ( unless semantic bit has changed )
420
- if (!node_opcua_numeric_range_1.NumericRange.overlap(indexRange, this.itemToMonitor.indexRange)) {
421
- // istanbul ignore next
422
- doDebug && debugLog("recordValue => Rejected", (_b = this.node) === null || _b === void 0 ? void 0 : _b.browseName.toString(), " because no range not overlap");
423
- return false; // no overlap !
424
- }
425
- }
426
- // extract the range that we are interested with
427
- dataValue = (0, node_opcua_data_value_1.extractRange)(dataValue, this.itemToMonitor.indexRange);
428
- // istanbul ignore next
429
- if (doDebug2) {
430
- debugLog("MonitoredItem#recordValue", this.node.nodeId.toString(), this.node.browseName.toString(), " has Changed = ", !(0, node_opcua_data_value_1.sameDataValue)(dataValue, this.oldDataValue), "skipChangeTest = ", skipChangeTest, "hasSemanticChanged = ", hasSemanticChanged);
431
- }
432
- // if semantic has changed, value need to be enqueued regardless of other assumptions
433
- if (hasSemanticChanged) {
434
- debugLog("_enqueue_value => because hasSemanticChanged");
435
- setSemanticChangeBit(dataValue);
436
- this._semantic_version = this.node.semantic_version;
437
- this._enqueue_value(dataValue);
438
- // istanbul ignore next
439
- doDebug && debugLog("recordValue => OK ", (_c = this.node) === null || _c === void 0 ? void 0 : _c.browseName.toString(), " because hasSemanticChanged");
440
- return true;
441
- }
442
- const useIndexRange = this.itemToMonitor.indexRange && !this.itemToMonitor.indexRange.isEmpty();
443
- if (!skipChangeTest) {
444
- const hasChanged = !(0, node_opcua_data_value_1.sameDataValue)(dataValue, this.oldDataValue);
445
- if (!hasChanged) {
446
- // istanbul ignore next
447
- doDebug2 &&
448
- debugLog("recordValue => Rejected ", (_d = this.node) === null || _d === void 0 ? void 0 : _d.browseName.toString(), " because !skipChangeTest && sameDataValue");
449
- return false;
450
- }
451
- }
452
- if (!apply_filter.call(this, dataValue)) {
453
- // istanbul ignore next
454
- if (doDebug) {
455
- debugLog("recordValue => Rejected ", (_e = this.node) === null || _e === void 0 ? void 0 : _e.browseName.toString(), " because apply_filter");
456
- debugLog("current Value =>", (_f = this.oldDataValue) === null || _f === void 0 ? void 0 : _f.toString());
457
- debugLog("propoped Value =>", dataValue === null || dataValue === void 0 ? void 0 : dataValue.toString());
458
- debugLog("propoped Value =>", dataValue == this.oldDataValue, dataValue.value === ((_g = this.oldDataValue) === null || _g === void 0 ? void 0 : _g.value));
459
- }
460
- return false;
461
- }
462
- if (useIndexRange) {
463
- // when an indexRange is provided , make sure that no record happens unless
464
- // extracted variant in the selected range has really changed.
465
- // istanbul ignore next
466
- if (doDebug) {
467
- debugLog("Current : ", this.oldDataValue.toString());
468
- debugLog("New : ", dataValue.toString());
469
- debugLog("indexRange=", indexRange);
470
- }
471
- if ((0, node_opcua_variant_1.sameVariant)(dataValue.value, this.oldDataValue.value)) {
472
- // istanbul ignore next
473
- doDebug &&
474
- debugLog("recordValue => Rejected ", (_h = this.node) === null || _h === void 0 ? void 0 : _h.browseName.toString(), " because useIndexRange && sameVariant");
475
- return false;
476
- }
477
- }
478
- // processTriggerItems
479
- this.triggerLinkedItems();
480
- // store last value
481
- this._enqueue_value(dataValue);
482
- // istanbul ignore next
483
- doDebug && debugLog("recordValue => OK ", (_j = this.node) === null || _j === void 0 ? void 0 : _j.browseName.toString());
484
- return true;
485
- }
486
- hasLinkItem(linkedMonitoredItemId) {
487
- if (!this._linkedItems) {
488
- return false;
489
- }
490
- return this._linkedItems.findIndex((x) => x === linkedMonitoredItemId) > 0;
491
- }
492
- addLinkItem(linkedMonitoredItemId) {
493
- if (linkedMonitoredItemId === this.monitoredItemId) {
494
- return node_opcua_status_code_1.StatusCodes.BadMonitoredItemIdInvalid;
495
- }
496
- this._linkedItems = this._linkedItems || [];
497
- if (this.hasLinkItem(linkedMonitoredItemId)) {
498
- return node_opcua_status_code_1.StatusCodes.BadMonitoredItemIdInvalid; // nothing to do
499
- }
500
- this._linkedItems.push(linkedMonitoredItemId);
501
- return node_opcua_status_code_1.StatusCodes.Good;
502
- }
503
- removeLinkItem(linkedMonitoredItemId) {
504
- if (!this._linkedItems || linkedMonitoredItemId === this.monitoredItemId) {
505
- return node_opcua_status_code_1.StatusCodes.BadMonitoredItemIdInvalid;
506
- }
507
- const index = this._linkedItems.findIndex((x) => x === linkedMonitoredItemId);
508
- if (index === -1) {
509
- return node_opcua_status_code_1.StatusCodes.BadMonitoredItemIdInvalid;
510
- }
511
- this._linkedItems.splice(index, 1);
512
- return node_opcua_status_code_1.StatusCodes.Good;
513
- }
514
- /**
515
- * @internals
516
- */
517
- triggerLinkedItems() {
518
- var _a, _b;
519
- if (!this.$subscription || !this._linkedItems) {
520
- return;
521
- }
522
- // see https://reference.opcfoundation.org/v104/Core/docs/Part4/5.12.1/#5.12.1.6
523
- for (const linkItem of this._linkedItems) {
524
- const linkedMonitoredItem = this.$subscription.getMonitoredItem(linkItem);
525
- if (!linkedMonitoredItem) {
526
- // monitoredItem may have been deleted
527
- continue;
528
- }
529
- if (linkedMonitoredItem.monitoringMode === node_opcua_service_subscription_1.MonitoringMode.Disabled) {
530
- continue;
531
- }
532
- if (linkedMonitoredItem.monitoringMode === node_opcua_service_subscription_1.MonitoringMode.Reporting) {
533
- continue;
534
- }
535
- (0, node_opcua_assert_1.assert)(linkedMonitoredItem.monitoringMode === node_opcua_service_subscription_1.MonitoringMode.Sampling);
536
- // istanbul ignore next
537
- if (doDebug) {
538
- debugLog("triggerLinkedItems => ", (_a = this.node) === null || _a === void 0 ? void 0 : _a.nodeId.toString(), (_b = linkedMonitoredItem.node) === null || _b === void 0 ? void 0 : _b.nodeId.toString());
539
- }
540
- linkedMonitoredItem.trigger();
541
- }
542
- }
543
- get hasMonitoredItemNotifications() {
544
- return this.queue.length > 0 || (this._triggeredNotifications !== undefined && this._triggeredNotifications.length > 0);
545
- }
546
- /**
547
- * @internals
548
- */
549
- trigger() {
550
- setImmediate(() => {
551
- this._triggeredNotifications = this._triggeredNotifications || [];
552
- const notifications = this.extractMonitoredItemNotifications(true);
553
- this._triggeredNotifications = [].concat(this._triggeredNotifications, notifications);
554
- });
555
- }
556
- extractMonitoredItemNotifications(bForce = false) {
557
- if (!bForce && this.monitoringMode === node_opcua_service_subscription_1.MonitoringMode.Sampling && this._triggeredNotifications) {
558
- const notifications1 = this._triggeredNotifications;
559
- this._triggeredNotifications = undefined;
560
- return notifications1;
561
- }
562
- if (!bForce && this.monitoringMode !== node_opcua_service_subscription_1.MonitoringMode.Reporting) {
563
- return [];
564
- }
565
- const notifications = this.queue;
566
- this._empty_queue();
567
- // apply semantic changed bit if necessary
568
- if (notifications.length > 0 && this.node && this._semantic_version < this.node.semantic_version) {
569
- const dataValue = notifications[notifications.length - 1];
570
- setSemanticChangeBit(dataValue);
571
- (0, node_opcua_assert_1.assert)(this.node.nodeClass === node_opcua_data_model_1.NodeClass.Variable);
572
- this._semantic_version = this.node.semantic_version;
573
- }
574
- return notifications;
575
- }
576
- modify(timestampsToReturn, monitoringParameters) {
577
- (0, node_opcua_assert_1.assert)(monitoringParameters instanceof node_opcua_service_subscription_1.MonitoringParameters);
578
- const old_samplingInterval = this.samplingInterval;
579
- this.timestampsToReturn = timestampsToReturn || this.timestampsToReturn;
580
- if (old_samplingInterval !== 0 && monitoringParameters.samplingInterval === 0) {
581
- monitoringParameters.samplingInterval = MonitoredItem.minimumSamplingInterval; // fastest possible
582
- }
583
- // spec says: Illegal request values for parameters that can be revised do not generate errors. Instead the
584
- // server will choose default values and indicate them in the corresponding revised parameter
585
- this._set_parameters(monitoringParameters);
586
- this._adjust_queue_to_match_new_queue_size();
587
- this._adjustSampling(old_samplingInterval);
588
- if (monitoringParameters.filter) {
589
- const statusCodeFilter = (0, validate_filter_1.validateFilter)(monitoringParameters.filter, this.itemToMonitor, this.node);
590
- if (statusCodeFilter.isNot(node_opcua_status_code_1.StatusCodes.Good)) {
591
- return new node_opcua_service_subscription_1.MonitoredItemModifyResult({
592
- statusCode: statusCodeFilter
593
- });
594
- }
595
- }
596
- // validate filter
597
- // note : The DataChangeFilter does not have an associated result structure.
598
- const filterResult = null; // new subscription_service.DataChangeFilter
599
- return new node_opcua_service_subscription_1.MonitoredItemModifyResult({
600
- filterResult,
601
- revisedQueueSize: this.queueSize,
602
- revisedSamplingInterval: this.samplingInterval,
603
- statusCode: node_opcua_status_code_1.StatusCodes.Good
604
- });
605
- }
606
- resendInitialValues() {
607
- return __awaiter(this, void 0, void 0, function* () {
608
- // the first Publish response(s) after the TransferSubscriptions call shall contain the current values of all
609
- // Monitored Items in the Subscription where the Monitoring Mode is set to Reporting.
610
- // the first Publish response after the TransferSubscriptions call shall contain only the value changes since
611
- // the last Publish response was sent.
612
- // This parameter only applies to MonitoredItems used for monitoring Attribute changes.
613
- return this._start_sampling(true);
614
- });
615
- }
616
- getSessionContext() {
617
- const session = this._getSession();
618
- if (!session) {
619
- return null;
620
- }
621
- const sessionContext = session.sessionContext;
622
- return sessionContext;
623
- }
624
- /**
625
- * @method _on_sampling_timer
626
- * @private
627
- */
628
- _on_sampling_timer() {
629
- if (this.monitoringMode === node_opcua_service_subscription_1.MonitoringMode.Disabled) {
630
- return;
631
- }
632
- const sessionContext = this.getSessionContext();
633
- if (!sessionContext) {
634
- return;
635
- }
636
- // istanbul ignore next
637
- if (doDebug2) {
638
- debugLog("MonitoredItem#_on_sampling_timer", this.node ? this.node.nodeId.toString() : "null", " isSampling?=", this._is_sampling);
639
- }
640
- if (this._samplingId) {
641
- (0, node_opcua_assert_1.assert)(this.monitoringMode === node_opcua_service_subscription_1.MonitoringMode.Sampling || this.monitoringMode === node_opcua_service_subscription_1.MonitoringMode.Reporting);
642
- if (this._is_sampling) {
643
- // previous sampling call is not yet completed..
644
- // there is nothing we can do about it except waiting until next tick.
645
- // note : see also issue #156 on github
646
- // Note: some server returns GoodOverload here
647
- const statusCode = node_opcua_status_code_1.StatusCodes.GoodOverload;
648
- return;
649
- }
650
- // xx console.log("xxxx ON SAMPLING");
651
- (0, node_opcua_assert_1.assert)(!this._is_sampling, "sampling func shall not be re-entrant !! fix it");
652
- // istanbul ignore next
653
- if (!this.samplingFunc) {
654
- throw new Error("internal error : missing samplingFunc");
655
- }
656
- this._is_sampling = true;
657
- this.samplingFunc.call(this, sessionContext, this.oldDataValue, (err, newDataValue) => {
658
- if (!this._samplingId) {
659
- // item has been disposed. The monitored item has been disposed while the async sampling func
660
- // was taking place ... just ignore this
661
- return;
662
- }
663
- // istanbull ignore next
664
- if (err) {
665
- console.log(" SAMPLING ERROR =>", err);
666
- }
667
- else {
668
- // only record value if source timestamp is newer
669
- // xx if (newDataValue && isSourceNewerThan(newDataValue, this.oldDataValue)) {
670
- this._on_value_changed(newDataValue);
671
- // xx }
672
- }
673
- this._is_sampling = false;
674
- });
675
- }
676
- else {
677
- /* istanbul ignore next */
678
- debugLog("_on_sampling_timer call but MonitoredItem has been terminated !!! ");
679
- }
680
- }
681
- _stop_sampling() {
682
- // debugLog("MonitoredItem#_stop_sampling");
683
- /* istanbul ignore next */
684
- if (!this.node) {
685
- throw new Error("Internal Error");
686
- }
687
- if (this._on_opcua_event_received_callback) {
688
- (0, node_opcua_assert_1.assert)(typeof this._on_opcua_event_received_callback === "function");
689
- this.node.removeListener("event", this._on_opcua_event_received_callback);
690
- this._on_opcua_event_received_callback = null;
691
- }
692
- if (this._attribute_changed_callback) {
693
- (0, node_opcua_assert_1.assert)(typeof this._attribute_changed_callback === "function");
694
- const event_name = (0, node_opcua_address_space_1.makeAttributeEventName)(this.itemToMonitor.attributeId);
695
- this.node.removeListener(event_name, this._attribute_changed_callback);
696
- this._attribute_changed_callback = null;
697
- }
698
- if (this._value_changed_callback) {
699
- // samplingInterval was 0 for a exception-based data Item
700
- // we setup a event listener that we need to unwind here
701
- (0, node_opcua_assert_1.assert)(typeof this._value_changed_callback === "function");
702
- (0, node_opcua_assert_1.assert)(!this._samplingId);
703
- this.node.removeListener("value_changed", this._value_changed_callback);
704
- this._value_changed_callback = null;
705
- }
706
- if (this._semantic_changed_callback) {
707
- (0, node_opcua_assert_1.assert)(typeof this._semantic_changed_callback === "function");
708
- (0, node_opcua_assert_1.assert)(!this._samplingId);
709
- this.node.removeListener("semantic_changed", this._semantic_changed_callback);
710
- this._semantic_changed_callback = null;
711
- }
712
- if (this._samplingId) {
713
- this._clear_timer();
714
- }
715
- (0, node_opcua_assert_1.assert)(!this._samplingId);
716
- (0, node_opcua_assert_1.assert)(!this._value_changed_callback);
717
- (0, node_opcua_assert_1.assert)(!this._semantic_changed_callback);
718
- (0, node_opcua_assert_1.assert)(!this._attribute_changed_callback);
719
- (0, node_opcua_assert_1.assert)(!this._on_opcua_event_received_callback);
720
- }
721
- _on_value_changed(dataValue, indexRange) {
722
- (0, node_opcua_assert_1.assert)(dataValue instanceof node_opcua_data_value_1.DataValue);
723
- this.recordValue(dataValue, false, indexRange);
724
- }
725
- _on_semantic_changed() {
726
- const dataValue = this.node.readValue();
727
- this._on_value_changed(dataValue);
728
- }
729
- _on_opcua_event(eventData) {
730
- // TO DO : => Improve Filtering, bearing in mind that ....
731
- // Release 1.04 8 OPC Unified Architecture, Part 9
732
- // 4.5 Condition state synchronization
733
- // To ensure a Client is always informed, the three special EventTypes
734
- // (RefreshEndEventType, RefreshStartEventType and RefreshRequiredEventType)
735
- // ignore the Event content filtering associated with a Subscription and will always be
736
- // delivered to the Client.
737
- var _a;
738
- // istanbul ignore next
739
- if (!this.filter || !(this.filter instanceof node_opcua_service_filter_2.EventFilter)) {
740
- throw new Error("Internal Error : a EventFilter is requested");
741
- }
742
- const addressSpace = (_a = eventData.$eventDataSource) === null || _a === void 0 ? void 0 : _a.addressSpace;
743
- if (!(0, check_where_clause_on_address_space_1.checkWhereClauseOnAdressSpace)(addressSpace, node_opcua_address_space_1.SessionContext.defaultContext, this.filter.whereClause, eventData)) {
744
- return;
745
- }
746
- const selectClauses = this.filter.selectClauses ? this.filter.selectClauses : [];
747
- const eventFields = (0, node_opcua_service_filter_1.extractEventFields)(node_opcua_address_space_1.SessionContext.defaultContext, selectClauses, eventData);
748
- // istanbul ignore next
749
- if (doDebug) {
750
- console.log(" RECEIVED INTERNAL EVENT THAT WE ARE MONITORING");
751
- console.log(this.filter ? this.filter.toString() : "no filter");
752
- eventFields.forEach((e) => {
753
- console.log(e.toString());
754
- });
755
- }
756
- this._enqueue_event(eventFields);
757
- }
758
- _getSession() {
759
- if (!this.$subscription) {
760
- return null;
761
- }
762
- if (!this.$subscription.$session) {
763
- return null;
764
- }
765
- return this.$subscription.$session;
766
- }
767
- _start_sampling(recordInitialValue) {
768
- // istanbul ignore next
769
- if (!this.node) {
770
- throw new Error("Internal Error");
771
- }
772
- setImmediate(() => this.__start_sampling(recordInitialValue));
773
- }
774
- __acquireInitialValue(sessionContext, callback) {
775
- var _a;
776
- // aquire initial value from the variable/object not itself or from the last known value if we have
777
- // one already
778
- (0, node_opcua_assert_1.assert)(this.itemToMonitor.attributeId === node_opcua_data_model_2.AttributeIds.Value);
779
- (0, node_opcua_assert_1.assert)(this.node);
780
- if (((_a = this.node) === null || _a === void 0 ? void 0 : _a.nodeClass) !== node_opcua_data_model_1.NodeClass.Variable) {
781
- return callback(new Error("Invalid "));
782
- }
783
- const variable = this.node;
784
- if (!this.oldDataValue || this.oldDataValue.statusCode.value == node_opcua_status_code_1.StatusCodes.BadDataUnavailable.value) {
785
- variable.readValueAsync(sessionContext, (err, dataValue) => {
786
- callback(err, dataValue);
787
- });
788
- }
789
- else {
790
- const o = this.oldDataValue;
791
- this.oldDataValue = new node_opcua_data_value_1.DataValue({ statusCode: node_opcua_status_code_1.StatusCodes.BadDataUnavailable });
792
- // istanbul ignore next
793
- if (doDebug) {
794
- safeGuardRegiter(this);
795
- }
796
- callback(null, o);
797
- }
798
- }
799
- __start_sampling(recordInitialValue) {
800
- // istanbul ignore next
801
- if (!this.node) {
802
- return; // we just want to ignore here ...
803
- }
804
- const sessionContext = this.getSessionContext();
805
- // istanbul ignore next
806
- if (!sessionContext) {
807
- return;
808
- }
809
- this._stop_sampling();
810
- if (this.itemToMonitor.attributeId === node_opcua_data_model_2.AttributeIds.EventNotifier) {
811
- // istanbul ignore next
812
- if (doDebug) {
813
- debugLog("xxxxxx monitoring EventNotifier on", this.node.nodeId.toString(), this.node.browseName.toString());
814
- }
815
- if (!this._on_opcua_event_received_callback) {
816
- // we are monitoring OPCUA Event
817
- this._on_opcua_event_received_callback = this._on_opcua_event.bind(this);
818
- this.node.on("event", this._on_opcua_event_received_callback);
819
- }
820
- return;
821
- }
822
- if (this.itemToMonitor.attributeId !== node_opcua_data_model_2.AttributeIds.Value) {
823
- // sampling interval only applies to Value Attributes.
824
- this.samplingInterval = 0; // turned to exception-based regardless of requested sampling interval
825
- // non value attribute only react on value change
826
- if (!this._attribute_changed_callback) {
827
- this._attribute_changed_callback = this._on_value_changed.bind(this);
828
- const event_name = (0, node_opcua_address_space_1.makeAttributeEventName)(this.itemToMonitor.attributeId);
829
- this.node.on(event_name, this._attribute_changed_callback);
830
- }
831
- if (recordInitialValue) {
832
- // read initial value
833
- const dataValue = this.node.readAttribute(sessionContext, this.itemToMonitor.attributeId);
834
- this.recordValue(dataValue, true);
835
- }
836
- return;
837
- }
838
- if (this.samplingInterval === 0) {
839
- // we have a exception-based dataItem : event based model, so we do not need a timer
840
- // rather , we setup the "value_changed_event";
841
- if (!this._value_changed_callback) {
842
- (0, node_opcua_assert_1.assert)(!this._semantic_changed_callback);
843
- this._value_changed_callback = this._on_value_changed.bind(this);
844
- this._semantic_changed_callback = this._on_semantic_changed.bind(this);
845
- this.node.on("value_changed", this._value_changed_callback);
846
- this.node.on("semantic_changed", this._semantic_changed_callback);
847
- }
848
- // initiate first read
849
- if (recordInitialValue) {
850
- this.__acquireInitialValue(sessionContext, (err, dataValue) => {
851
- if (err) {
852
- warningLog(err.message);
853
- }
854
- if (!err && dataValue) {
855
- this.recordValue(dataValue.clone(), true);
856
- }
857
- });
858
- }
859
- }
860
- else {
861
- if (recordInitialValue) {
862
- this.__acquireInitialValue(sessionContext, (err, dataValue) => {
863
- if (err) {
864
- warningLog(err.message);
865
- }
866
- if (!err && dataValue) {
867
- this.recordValue(dataValue, true);
868
- }
869
- this._set_timer();
870
- });
871
- }
872
- else {
873
- this._set_timer();
874
- }
875
- }
876
- }
877
- _set_parameters(monitoredParameters) {
878
- _validate_parameters(monitoredParameters);
879
- // only change clientHandle if it is valid (0<X<MAX)
880
- if (monitoredParameters.clientHandle !== 0 && monitoredParameters.clientHandle !== 4294967295) {
881
- this.clientHandle = monitoredParameters.clientHandle;
882
- }
883
- // The Server may support data that is collected based on a sampling model or generated based on an
884
- // exception-based model. The fastest supported sampling interval may be equal to 0, which indicates
885
- // that the data item is exception-based rather than being sampled at some period. An exception-based
886
- // model means that the underlying system does not require sampling and reports data changes.
887
- if (this.node && this.node.nodeClass === node_opcua_data_model_1.NodeClass.Variable) {
888
- const variable = this.node;
889
- this.samplingInterval = _adjust_sampling_interval(monitoredParameters.samplingInterval, variable.minimumSamplingInterval || 0);
890
- }
891
- else {
892
- this.samplingInterval = _adjust_sampling_interval(monitoredParameters.samplingInterval, 0);
893
- }
894
- this.discardOldest = monitoredParameters.discardOldest;
895
- this.queueSize = _adjust_queue_size(monitoredParameters.queueSize);
896
- // change filter
897
- this.filter = monitoredParameters.filter || null;
898
- }
899
- _setOverflowBit(notification) {
900
- if (Object.prototype.hasOwnProperty.call(notification, "value")) {
901
- (0, node_opcua_assert_1.assert)(notification.value.statusCode.equals(node_opcua_status_code_1.StatusCodes.Good));
902
- notification.value.statusCode = node_opcua_status_code_1.StatusCode.makeStatusCode(notification.value.statusCode, "Overflow | InfoTypeDataValue");
903
- (0, node_opcua_assert_1.assert)((0, node_opcua_data_value_1.sameStatusCode)(notification.value.statusCode, node_opcua_status_code_1.StatusCodes.GoodWithOverflowBit));
904
- (0, node_opcua_assert_1.assert)(notification.value.statusCode.hasOverflowBit);
905
- }
906
- // console.log(chalk.cyan("Setting Over"), !!this.$subscription, !!this.$subscription!.subscriptionDiagnostics);
907
- if (this.$subscription && this.$subscription.subscriptionDiagnostics) {
908
- this.$subscription.subscriptionDiagnostics.monitoringQueueOverflowCount++;
909
- }
910
- // to do eventQueueOverFlowCount
911
- }
912
- _enqueue_notification(notification) {
913
- if (this.queueSize === 1) {
914
- // https://reference.opcfoundation.org/v104/Core/docs/Part4/5.12.1/#5.12.1.5
915
- // If the queue size is one, the queue becomes a buffer that always contains the newest
916
- // Notification. In this case, if the sampling interval of the MonitoredItem is faster
917
- // than the publishing interval of the Subscription, the MonitoredItem will be over
918
- // sampling and the Client will always receive the most up-to-date value.
919
- // The discard policy is ignored if the queue size is one.
920
- // ensure queue size
921
- if (!this.queue || this.queue.length !== 1) {
922
- this.queue = [];
923
- }
924
- this.queue[0] = notification;
925
- (0, node_opcua_assert_1.assert)(this.queue.length === 1);
926
- }
927
- else {
928
- if (this.discardOldest) {
929
- // push new value to queue
930
- this.queue.push(notification);
931
- if (this.queue.length > this.queueSize) {
932
- this.overflow = true;
933
- this.queue.shift(); // remove front element
934
- // set overflow bit
935
- this._setOverflowBit(this.queue[0]);
936
- }
937
- }
938
- else {
939
- if (this.queue.length < this.queueSize) {
940
- this.queue.push(notification);
941
- }
942
- else {
943
- this.overflow = true;
944
- this._setOverflowBit(notification);
945
- this.queue[this.queue.length - 1] = notification;
946
- }
947
- }
948
- }
949
- (0, node_opcua_assert_1.assert)(this.queue.length >= 1);
950
- }
951
- _makeDataChangeNotification(dataValue) {
952
- if (this.clientHandle === -1 || this.clientHandle === 4294967295) {
953
- debugLog("Invalid client handle");
954
- }
955
- const attributeId = this.itemToMonitor.attributeId;
956
- // if dataFilter is specified ....
957
- if (this.filter && this.filter instanceof node_opcua_service_subscription_2.DataChangeFilter) {
958
- if (this.filter.trigger === node_opcua_service_subscription_2.DataChangeTrigger.Status) {
959
- /** */
960
- }
961
- }
962
- dataValue = (0, node_opcua_data_value_1.apply_timestamps)(dataValue, this.timestampsToReturn, attributeId);
963
- return new node_opcua_service_subscription_1.MonitoredItemNotification({
964
- clientHandle: this.clientHandle,
965
- value: dataValue
966
- });
967
- }
968
- /**
969
- * @method _enqueue_value
970
- * @param dataValue {DataValue} the dataValue to enqueue
971
- * @private
972
- */
973
- _enqueue_value(dataValue) {
974
- // preconditions:
975
- if (doDebug) {
976
- debugLog("_enqueue_value = ", dataValue.toString());
977
- }
978
- (0, node_opcua_assert_1.assert)(dataValue instanceof node_opcua_data_value_1.DataValue);
979
- // lets verify that, if status code is good then we have a valid Variant in the dataValue
980
- (0, node_opcua_assert_1.assert)(!dataValue.statusCode.isGoodish() || dataValue.value instanceof node_opcua_variant_1.Variant);
981
- // xx assert(isGoodish(dataValue.statusCode) || util.isNullOrUndefined(dataValue.value) );
982
- // let's check that data Value is really a different object
983
- // we may end up with corrupted queue if dataValue are recycled and stored as is in notifications
984
- (0, node_opcua_assert_1.assert)(dataValue !== this.oldDataValue, "dataValue cannot be the same object twice!");
985
- // Xx // todo ERN !!!! PLEASE CHECK this !!!
986
- // Xx // let make a clone, so we have a snapshot
987
- // Xx dataValue = dataValue.clone();
988
- // let's check that data Value is really a different object
989
- // we may end up with corrupted queue if dataValue are recycled and stored as is in notifications
990
- (0, node_opcua_assert_1.assert)(!this.oldDataValue || !dataValue.value || dataValue.value !== this.oldDataValue.value, "dataValue cannot be the same object twice!");
991
- if (!(!this.oldDataValue ||
992
- !this.oldDataValue.value ||
993
- !dataValue.value ||
994
- !(dataValue.value.value instanceof Object) ||
995
- dataValue.value.value !== this.oldDataValue.value.value) &&
996
- !(dataValue.value.value instanceof Date)) {
997
- throw new Error("dataValue.value.value cannot be the same object twice! " +
998
- this.node.browseName.toString() +
999
- " " +
1000
- dataValue.toString() +
1001
- " " +
1002
- chalk.cyan(this.oldDataValue.toString()));
1003
- }
1004
- // istanbul ignore next
1005
- if (doDebug) {
1006
- debugLog("MonitoredItem#_enqueue_value", this.node.nodeId.toString());
1007
- safeGuardVerify(this);
1008
- }
1009
- this.oldDataValue = dataValue.clone();
1010
- // istanbul ignore next
1011
- if (doDebug) {
1012
- safeGuardRegiter(this);
1013
- }
1014
- const notification = this._makeDataChangeNotification(this.oldDataValue);
1015
- this._enqueue_notification(notification);
1016
- }
1017
- _makeEventFieldList(eventFields) {
1018
- (0, node_opcua_assert_1.assert)(Array.isArray(eventFields));
1019
- return new node_opcua_types_1.EventFieldList({
1020
- clientHandle: this.clientHandle,
1021
- eventFields
1022
- });
1023
- }
1024
- _enqueue_event(eventFields) {
1025
- if (doDebug) {
1026
- debugLog(" MonitoredItem#_enqueue_event");
1027
- }
1028
- const notification = this._makeEventFieldList(eventFields);
1029
- this._enqueue_notification(notification);
1030
- }
1031
- _empty_queue() {
1032
- // empty queue
1033
- this.queue = [];
1034
- this.overflow = false;
1035
- }
1036
- _clear_timer() {
1037
- if (this._samplingId) {
1038
- if (useCommonTimer) {
1039
- (0, node_sampler_1.removeFromTimer)(this);
1040
- }
1041
- else {
1042
- clearInterval(this._samplingId);
1043
- }
1044
- this._samplingId = undefined;
1045
- }
1046
- }
1047
- _set_timer() {
1048
- if (!this.itemToMonitor) {
1049
- // item has already been deleted
1050
- // so do not create the timer !
1051
- return;
1052
- }
1053
- (0, node_opcua_assert_1.assert)(this.samplingInterval >= MonitoredItem.minimumSamplingInterval);
1054
- (0, node_opcua_assert_1.assert)(!this._samplingId);
1055
- if (useCommonTimer) {
1056
- this._samplingId = (0, node_sampler_1.appendToTimer)(this);
1057
- }
1058
- else {
1059
- // settle periodic sampling
1060
- this._samplingId = setInterval(() => {
1061
- this._on_sampling_timer();
1062
- }, this.samplingInterval);
1063
- }
1064
- // xx console.log("MonitoredItem#_set_timer",this._samplingId);
1065
- }
1066
- _adjust_queue_to_match_new_queue_size() {
1067
- // adjust queue size if necessary
1068
- if (this.queueSize < this.queue.length) {
1069
- if (this.discardOldest) {
1070
- this.queue.splice(0, this.queue.length - this.queueSize);
1071
- }
1072
- else {
1073
- const lastElement = this.queue[this.queue.length - 1];
1074
- // only keep queueSize first element, discard others
1075
- this.queue.splice(this.queueSize);
1076
- this.queue[this.queue.length - 1] = lastElement;
1077
- }
1078
- }
1079
- if (this.queueSize <= 1) {
1080
- this.overflow = false;
1081
- // unset OverFlowBit
1082
- if (this.queue.length === 1) {
1083
- if (this.queue[0] instanceof node_opcua_service_subscription_1.MonitoredItemNotification) {
1084
- const el = this.queue[0];
1085
- if (el.value.statusCode.hasOverflowBit) {
1086
- el.value.statusCode.unset("Overflow | InfoTypeDataValue");
1087
- }
1088
- }
1089
- }
1090
- }
1091
- (0, node_opcua_assert_1.assert)(this.queue.length <= this.queueSize);
1092
- }
1093
- _adjustSampling(old_samplingInterval) {
1094
- if (old_samplingInterval !== this.samplingInterval) {
1095
- this._start_sampling(false);
1096
- }
1097
- }
1098
- _on_node_disposed(node) {
1099
- this._on_value_changed(new node_opcua_data_value_1.DataValue({
1100
- sourceTimestamp: new Date(),
1101
- statusCode: node_opcua_status_code_1.StatusCodes.BadNodeIdInvalid
1102
- }));
1103
- this._stop_sampling();
1104
- node.removeListener("dispose", this._on_node_disposed_listener);
1105
- this._on_node_disposed_listener = null;
1106
- }
1107
- }
1108
- exports.MonitoredItem = MonitoredItem;
1109
- MonitoredItem.registry = new node_opcua_object_registry_1.ObjectRegistry();
1110
- MonitoredItem.minimumSamplingInterval = 50; // 50 ms as a minimum sampling interval
1111
- MonitoredItem.defaultSamplingInterval = 1500; // 1500 ms as a default sampling interval
1112
- MonitoredItem.maximumSamplingInterval = 1000 * 60 * 60; // 1 hour !
1113
- //# sourceMappingURL=monitored_item.js.map