node-opcua-client 2.97.0 → 2.98.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 (78) hide show
  1. package/dist/alarms_and_conditions/client_alarm.d.ts +49 -49
  2. package/dist/alarms_and_conditions/client_alarm.js +109 -109
  3. package/dist/alarms_and_conditions/client_alarm_list.d.ts +25 -25
  4. package/dist/alarms_and_conditions/client_alarm_list.js +97 -97
  5. package/dist/alarms_and_conditions/client_alarm_tools.d.ts +4 -4
  6. package/dist/alarms_and_conditions/client_alarm_tools.js +156 -156
  7. package/dist/alarms_and_conditions/client_alarm_tools_acknowledge_all_conditions.d.ts +18 -18
  8. package/dist/alarms_and_conditions/client_alarm_tools_acknowledge_all_conditions.js +192 -192
  9. package/dist/alarms_and_conditions/client_alarm_tools_dump_event.d.ts +9 -9
  10. package/dist/alarms_and_conditions/client_alarm_tools_dump_event.js +72 -72
  11. package/dist/alarms_and_conditions/client_alarm_tools_dump_event.js.map +1 -1
  12. package/dist/alarms_and_conditions/client_alarm_tools_extractConditionFields.d.ts +3 -3
  13. package/dist/alarms_and_conditions/client_alarm_tools_extractConditionFields.js +118 -118
  14. package/dist/alarms_and_conditions/client_tools.d.ts +7 -7
  15. package/dist/alarms_and_conditions/client_tools.js +179 -179
  16. package/dist/client_base.d.ts +277 -277
  17. package/dist/client_base.js +14 -14
  18. package/dist/client_base.js.map +1 -1
  19. package/dist/client_monitored_item.d.ts +21 -21
  20. package/dist/client_monitored_item.js +11 -11
  21. package/dist/client_monitored_item_base.d.ts +39 -39
  22. package/dist/client_monitored_item_base.js +2 -2
  23. package/dist/client_monitored_item_group.d.ts +21 -21
  24. package/dist/client_monitored_item_group.js +13 -13
  25. package/dist/client_monitored_item_toolbox.d.ts +15 -15
  26. package/dist/client_monitored_item_toolbox.js +116 -116
  27. package/dist/client_session.d.ts +529 -529
  28. package/dist/client_session.js +10 -10
  29. package/dist/client_session_keepalive_manager.d.ts +34 -34
  30. package/dist/client_session_keepalive_manager.js +149 -149
  31. package/dist/client_subscription.d.ts +241 -241
  32. package/dist/client_subscription.js +14 -14
  33. package/dist/client_subscription.js.map +1 -1
  34. package/dist/client_utils.d.ts +22 -22
  35. package/dist/client_utils.js +87 -87
  36. package/dist/common.d.ts +17 -17
  37. package/dist/common.js +5 -5
  38. package/dist/index.d.ts +56 -56
  39. package/dist/index.js +94 -94
  40. package/dist/opcua_client.d.ts +118 -118
  41. package/dist/opcua_client.js +33 -33
  42. package/dist/private/client_base_impl.d.ts +160 -160
  43. package/dist/private/client_base_impl.js +1348 -1348
  44. package/dist/private/client_monitored_item_base_impl.d.ts +3 -3
  45. package/dist/private/client_monitored_item_base_impl.js +4 -4
  46. package/dist/private/client_monitored_item_group_impl.d.ts +53 -53
  47. package/dist/private/client_monitored_item_group_impl.js +159 -159
  48. package/dist/private/client_monitored_item_impl.d.ts +93 -93
  49. package/dist/private/client_monitored_item_impl.js +304 -304
  50. package/dist/private/client_publish_engine.d.ts +62 -62
  51. package/dist/private/client_publish_engine.js +408 -408
  52. package/dist/private/client_publish_engine.js.map +1 -1
  53. package/dist/private/client_session_impl.d.ts +631 -631
  54. package/dist/private/client_session_impl.js +1348 -1348
  55. package/dist/private/client_subscription_impl.d.ts +93 -93
  56. package/dist/private/client_subscription_impl.js +763 -763
  57. package/dist/private/i_private_client.d.ts +21 -21
  58. package/dist/private/i_private_client.js +2 -2
  59. package/dist/private/opcua_client_impl.d.ts +166 -166
  60. package/dist/private/opcua_client_impl.js +1000 -1000
  61. package/dist/private/opcua_client_impl.js.map +1 -1
  62. package/dist/private/performance.d.ts +1 -1
  63. package/dist/private/performance.js +18 -18
  64. package/dist/reconnection.d.ts +9 -9
  65. package/dist/reconnection.js +381 -381
  66. package/dist/tools/findservers.d.ts +20 -20
  67. package/dist/tools/findservers.js +61 -61
  68. package/dist/tools/read_history_server_capabilities.d.ts +6 -6
  69. package/dist/tools/read_history_server_capabilities.js +98 -98
  70. package/dist/user_identity_info.d.ts +1 -1
  71. package/dist/user_identity_info.js +2 -2
  72. package/dist/verify.d.ts +5 -5
  73. package/dist/verify.js +134 -134
  74. package/package.json +49 -45
  75. package/source/alarms_and_conditions/client_alarm_tools_dump_event.ts +1 -1
  76. package/.nycrc.json +0 -14
  77. package/test_helpers/create_certificates.js +0 -1
  78. package/typedoc.js +0 -20
@@ -1,39 +1,39 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ClientMonitoredItem_create = exports.ClientSubscriptionImpl = void 0;
4
- /**
5
- * @module node-opcua-client-private
6
- */
7
- // tslint:disable:unified-signatures
8
- const events_1 = require("events");
9
- const async = require("async");
10
- const chalk = require("chalk");
11
- const node_opcua_assert_1 = require("node-opcua-assert");
12
- const node_opcua_data_model_1 = require("node-opcua-data-model");
13
- const node_opcua_debug_1 = require("node-opcua-debug");
14
- const node_opcua_nodeid_1 = require("node-opcua-nodeid");
15
- const node_opcua_service_read_1 = require("node-opcua-service-read");
16
- const node_opcua_service_subscription_1 = require("node-opcua-service-subscription");
17
- const node_opcua_status_code_1 = require("node-opcua-status-code");
18
- const utils = require("node-opcua-utils");
19
- const node_opcua_client_dynamic_extension_object_1 = require("node-opcua-client-dynamic-extension-object");
20
- const node_opcua_pseudo_session_1 = require("node-opcua-pseudo-session");
21
- const client_subscription_1 = require("../client_subscription");
22
- const client_monitored_item_toolbox_1 = require("../client_monitored_item_toolbox");
23
- const client_monitored_item_group_impl_1 = require("./client_monitored_item_group_impl");
24
- const client_monitored_item_impl_1 = require("./client_monitored_item_impl");
25
- const performance_1 = require("./performance");
26
- const debugLog = (0, node_opcua_debug_1.make_debugLog)(__filename);
27
- const doDebug = (0, node_opcua_debug_1.checkDebugFlag)(__filename);
28
- const warningLog = (0, node_opcua_debug_1.make_warningLog)(__filename);
29
- const PENDING_SUBSCRIPTION_ID = 0xc0cac01a;
30
- const TERMINATED_SUBSCRIPTION_ID = 0xc0cac01b;
31
- const TERMINATING_SUBSCRIPTION_ID = 0xc0cac01c;
32
- const minimumMaxKeepAliveCount = 3;
33
- function displayKeepAliveWarning(sessionTimeout, maxKeepAliveCount, publishingInterval) {
34
- const keepAliveInterval = maxKeepAliveCount * publishingInterval;
35
- // istanbul ignore next
36
- if (sessionTimeout < keepAliveInterval) {
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ClientMonitoredItem_create = exports.ClientSubscriptionImpl = void 0;
4
+ /**
5
+ * @module node-opcua-client-private
6
+ */
7
+ // tslint:disable:unified-signatures
8
+ const events_1 = require("events");
9
+ const async = require("async");
10
+ const chalk = require("chalk");
11
+ const node_opcua_assert_1 = require("node-opcua-assert");
12
+ const node_opcua_data_model_1 = require("node-opcua-data-model");
13
+ const node_opcua_debug_1 = require("node-opcua-debug");
14
+ const node_opcua_nodeid_1 = require("node-opcua-nodeid");
15
+ const node_opcua_service_read_1 = require("node-opcua-service-read");
16
+ const node_opcua_service_subscription_1 = require("node-opcua-service-subscription");
17
+ const node_opcua_status_code_1 = require("node-opcua-status-code");
18
+ const utils = require("node-opcua-utils");
19
+ const node_opcua_client_dynamic_extension_object_1 = require("node-opcua-client-dynamic-extension-object");
20
+ const node_opcua_pseudo_session_1 = require("node-opcua-pseudo-session");
21
+ const client_subscription_1 = require("../client_subscription");
22
+ const client_monitored_item_toolbox_1 = require("../client_monitored_item_toolbox");
23
+ const client_monitored_item_group_impl_1 = require("./client_monitored_item_group_impl");
24
+ const client_monitored_item_impl_1 = require("./client_monitored_item_impl");
25
+ const performance_1 = require("./performance");
26
+ const debugLog = (0, node_opcua_debug_1.make_debugLog)(__filename);
27
+ const doDebug = (0, node_opcua_debug_1.checkDebugFlag)(__filename);
28
+ const warningLog = (0, node_opcua_debug_1.make_warningLog)(__filename);
29
+ const PENDING_SUBSCRIPTION_ID = 0xc0cac01a;
30
+ const TERMINATED_SUBSCRIPTION_ID = 0xc0cac01b;
31
+ const TERMINATING_SUBSCRIPTION_ID = 0xc0cac01c;
32
+ const minimumMaxKeepAliveCount = 3;
33
+ function displayKeepAliveWarning(sessionTimeout, maxKeepAliveCount, publishingInterval) {
34
+ const keepAliveInterval = maxKeepAliveCount * publishingInterval;
35
+ // istanbul ignore next
36
+ if (sessionTimeout < keepAliveInterval) {
37
37
  warningLog(chalk.yellowBright(`[NODE-OPCUA-W09] The subscription parameters are not compatible with the session timeout !
38
38
  session timeout = ${sessionTimeout} milliseconds
39
39
  maxKeepAliveCount = ${maxKeepAliveCount}
@@ -42,18 +42,18 @@ function displayKeepAliveWarning(sessionTimeout, maxKeepAliveCount, publishingIn
42
42
  It is important that the session timeout ( ${chalk.red(sessionTimeout)} ms) is largely greater than :
43
43
  (maxKeepAliveCount*publishingInterval = ${chalk.red(keepAliveInterval)} ms),
44
44
  otherwise you may experience unexpected disconnection from the server if your monitored items are not
45
- changing frequently.`));
46
- if (sessionTimeout < 3000 && publishingInterval <= 1000) {
47
- warningLog(`[NODE-OPCUA-W10] You'll need to increase your sessionTimeout significantly.`);
48
- }
49
- if (sessionTimeout >= 3000 &&
50
- sessionTimeout < publishingInterval * minimumMaxKeepAliveCount &&
51
- maxKeepAliveCount <= minimumMaxKeepAliveCount + 2) {
52
- warningLog(`[NODE-OPCUA-W11] your publishingInterval interval is probably too large, consider reducing it.`);
53
- }
54
- const idealMaxKeepAliveCount = Math.max(4, Math.floor((sessionTimeout * 0.8) / publishingInterval - 0.5));
55
- const idealPublishingInternal = Math.min(publishingInterval, sessionTimeout / (idealMaxKeepAliveCount + 3));
56
- const idealKeepAliveInterval = idealMaxKeepAliveCount * publishingInterval;
45
+ changing frequently.`));
46
+ if (sessionTimeout < 3000 && publishingInterval <= 1000) {
47
+ warningLog(`[NODE-OPCUA-W10] You'll need to increase your sessionTimeout significantly.`);
48
+ }
49
+ if (sessionTimeout >= 3000 &&
50
+ sessionTimeout < publishingInterval * minimumMaxKeepAliveCount &&
51
+ maxKeepAliveCount <= minimumMaxKeepAliveCount + 2) {
52
+ warningLog(`[NODE-OPCUA-W11] your publishingInterval interval is probably too large, consider reducing it.`);
53
+ }
54
+ const idealMaxKeepAliveCount = Math.max(4, Math.floor((sessionTimeout * 0.8) / publishingInterval - 0.5));
55
+ const idealPublishingInternal = Math.min(publishingInterval, sessionTimeout / (idealMaxKeepAliveCount + 3));
56
+ const idealKeepAliveInterval = idealMaxKeepAliveCount * publishingInterval;
57
57
  warningLog(`[NODE-OPCUA-W12] An ideal value for maxKeepAliveCount could be ${idealMaxKeepAliveCount}.
58
58
  An ideal value for publishingInterval could be ${idealPublishingInternal} ms.
59
59
  This will make your subscription emit a keep alive signal every ${idealKeepAliveInterval} ms
@@ -62,719 +62,719 @@ function displayKeepAliveWarning(sessionTimeout, maxKeepAliveCount, publishingIn
62
62
  const client = OPCUAClient.create({
63
63
  requestedSessionTimeout: 30* 60* 1000, // 30 minutes
64
64
  });
65
- `);
66
- if (!client_subscription_1.ClientSubscription.ignoreNextWarning) {
67
- throw new Error("[NODE-OPCUA-W09] The subscription parameters are not compatible with the session timeout ");
68
- }
69
- return true;
70
- }
71
- return false;
72
- }
73
- function createMonitoredItemsAndRespectOperationalLimits(session, createMonitorItemsRequest, callback) {
74
- (0, node_opcua_pseudo_session_1.readOperationLimits)(session)
75
- .then((operationalLimits) => {
76
- (0, node_opcua_pseudo_session_1.createMonitoredItemsLimit)(operationalLimits.maxMonitoredItemsPerCall || 0, session, createMonitorItemsRequest)
77
- .then((createMonitoredItemResponse) => callback(null, createMonitoredItemResponse))
78
- .catch(callback);
79
- })
80
- .catch(callback);
81
- }
82
- class ClientSubscriptionImpl extends events_1.EventEmitter {
83
- /**
84
- * the associated session
85
- * @property session
86
- * @type {ClientSession}
87
- */
88
- get session() {
89
- (0, node_opcua_assert_1.assert)(this.publishEngine.session, "expecting a valid session here");
90
- return this.publishEngine.session;
91
- }
92
- get hasSession() {
93
- return !!this.publishEngine.session;
94
- }
95
- get isActive() {
96
- return !(this.subscriptionId === PENDING_SUBSCRIPTION_ID ||
97
- this.subscriptionId === TERMINATED_SUBSCRIPTION_ID ||
98
- this.subscriptionId === TERMINATING_SUBSCRIPTION_ID);
99
- }
100
- constructor(session, options) {
101
- super();
102
- this.monitoredItemGroups = [];
103
- this.timeoutHint = 0;
104
- this._nextClientHandle = 0;
105
- const sessionImpl = session;
106
- this.publishEngine = sessionImpl.getPublishEngine();
107
- this.lastSequenceNumber = -1;
108
- options = options || {};
109
- options.requestedPublishingInterval = options.requestedPublishingInterval || 100;
110
- options.requestedLifetimeCount = options.requestedLifetimeCount || 60;
111
- options.requestedMaxKeepAliveCount = options.requestedMaxKeepAliveCount || 10;
112
- options.requestedMaxKeepAliveCount = Math.max(options.requestedMaxKeepAliveCount, minimumMaxKeepAliveCount);
113
- // perform some verification
114
- const warningEmitted = displayKeepAliveWarning(session.timeout, options.requestedMaxKeepAliveCount, options.requestedPublishingInterval);
115
- // istanbul ignore next
116
- if (warningEmitted) {
117
- warningLog(JSON.stringify(Object.assign({}, options), null, " "));
118
- }
119
- options.maxNotificationsPerPublish = utils.isNullOrUndefined(options.maxNotificationsPerPublish)
120
- ? 0
121
- : options.maxNotificationsPerPublish;
122
- options.publishingEnabled = !!options.publishingEnabled;
123
- options.priority = options.priority || 1;
124
- this.publishingInterval = options.requestedPublishingInterval;
125
- this.lifetimeCount = options.requestedLifetimeCount;
126
- this.maxKeepAliveCount = options.requestedMaxKeepAliveCount;
127
- this.maxNotificationsPerPublish = options.maxNotificationsPerPublish || 0;
128
- this.publishingEnabled = options.publishingEnabled;
129
- this.priority = options.priority;
130
- this.subscriptionId = PENDING_SUBSCRIPTION_ID;
131
- this._nextClientHandle = 0;
132
- this.monitoredItems = {};
133
- this.lastRequestSentTime = new Date(1, 1, 1970);
134
- /**
135
- * set to True when the server has notified us that this subscription has timed out
136
- * ( maxLifeCounter x published interval without being able to process a PublishRequest
137
- * @property hasTimedOut
138
- * @type {boolean}
139
- */
140
- this.hasTimedOut = false;
141
- setImmediate(() => {
142
- this.__create_subscription((err) => {
143
- if (!err) {
144
- setImmediate(() => {
145
- /**
146
- * notify the observers that the subscription has now started
147
- * @event started
148
- */
149
- this.emit("started", this.subscriptionId);
150
- });
151
- }
152
- else {
153
- setImmediate(() => {
154
- /**
155
- * notify the observers that the subscription has now failed
156
- * @event failed
157
- */
158
- this.emit("error", err);
159
- });
160
- }
161
- });
162
- });
163
- }
164
- terminate(...args) {
165
- debugLog("Terminating client subscription ", this.subscriptionId);
166
- const callback = args[0];
167
- (0, node_opcua_assert_1.assert)(typeof callback === "function", "expecting a callback function");
168
- if (this.subscriptionId === TERMINATED_SUBSCRIPTION_ID || this.subscriptionId === TERMINATING_SUBSCRIPTION_ID) {
169
- // already terminated... just ignore
170
- return callback(new Error("Already Terminated"));
171
- }
172
- if (isFinite(this.subscriptionId)) {
173
- const subscriptionId = this.subscriptionId;
174
- this.subscriptionId = TERMINATING_SUBSCRIPTION_ID;
175
- this.publishEngine.unregisterSubscription(subscriptionId);
176
- if (!this.hasSession) {
177
- return this._terminate_step2(callback);
178
- }
179
- const session = this.session;
180
- if (!session) {
181
- return callback(new Error("no session"));
182
- }
183
- session.deleteSubscriptions({
184
- subscriptionIds: [subscriptionId]
185
- }, (err, response) => {
186
- if (response && response.results[0] !== node_opcua_status_code_1.StatusCodes.Good) {
187
- debugLog("warning: deleteSubscription returned ", response.results);
188
- }
189
- if (err) {
190
- /**
191
- * notify the observers that an error has occurred
192
- * @event internal_error
193
- * @param err the error
194
- */
195
- this.emit("internal_error", err);
196
- }
197
- this._terminate_step2(callback);
198
- });
199
- }
200
- else {
201
- debugLog("subscriptionId is not value ", this.subscriptionId);
202
- (0, node_opcua_assert_1.assert)(this.subscriptionId === PENDING_SUBSCRIPTION_ID);
203
- this._terminate_step2(callback);
204
- }
205
- }
206
- /**
207
- * @method nextClientHandle
208
- */
209
- nextClientHandle() {
210
- this._nextClientHandle += 1;
211
- return this._nextClientHandle;
212
- }
213
- monitor(...args) {
214
- const itemToMonitor = args[0];
215
- const requestedParameters = args[1];
216
- const timestampsToReturn = args[2];
217
- const monitoringMode = typeof args[3] === "function" ? node_opcua_service_subscription_1.MonitoringMode.Reporting : args[3];
218
- const done = (typeof args[3] === "function" ? args[3] : args[4]);
219
- (0, node_opcua_assert_1.assert)(typeof done === "function", "expecting a function here");
220
- itemToMonitor.nodeId = (0, node_opcua_nodeid_1.resolveNodeId)(itemToMonitor.nodeId);
221
- const monitoredItem = ClientMonitoredItem_create(this, itemToMonitor, requestedParameters, timestampsToReturn, monitoringMode, (err1, monitoredItem2) => {
222
- if (err1) {
223
- return done && done(err1);
224
- }
225
- done(err1 || null, monitoredItem);
226
- });
227
- }
228
- monitorItems(...args) {
229
- const itemsToMonitor = args[0];
230
- const requestedParameters = args[1];
231
- const timestampsToReturn = args[2];
232
- const done = args[3];
233
- const monitoredItemGroup = new client_monitored_item_group_impl_1.ClientMonitoredItemGroupImpl(this, itemsToMonitor, requestedParameters, timestampsToReturn);
234
- this._wait_for_subscription_to_be_ready((err) => {
235
- if (err) {
236
- return done(err);
237
- }
238
- monitoredItemGroup._monitor((err1) => {
239
- if (err1) {
240
- return done && done(err1);
241
- }
242
- done(err1, monitoredItemGroup);
243
- });
244
- });
245
- }
246
- _delete_monitored_items(monitoredItems, callback) {
247
- (0, node_opcua_assert_1.assert)(typeof callback === "function");
248
- (0, node_opcua_assert_1.assert)(Array.isArray(monitoredItems));
249
- (0, node_opcua_assert_1.assert)(this.isActive);
250
- for (const monitoredItem of monitoredItems) {
251
- this._remove(monitoredItem);
252
- }
253
- const session = this.session;
254
- session.deleteMonitoredItems({
255
- monitoredItemIds: monitoredItems.map((monitoredItem) => monitoredItem.monitoredItemId),
256
- subscriptionId: this.subscriptionId
257
- }, (err, response) => {
258
- callback(err);
259
- });
260
- }
261
- setPublishingMode(...args) {
262
- const publishingEnabled = args[0];
263
- const callback = args[1];
264
- (0, node_opcua_assert_1.assert)(typeof callback === "function");
265
- const session = this.session;
266
- if (!session) {
267
- return callback(new Error("no session"));
268
- }
269
- const subscriptionId = this.subscriptionId;
270
- session.setPublishingMode(publishingEnabled, subscriptionId, (err, statusCode) => {
271
- if (err) {
272
- return callback(err);
273
- }
274
- /* istanbul ignore next */
275
- if (!statusCode) {
276
- return callback(new Error("Internal Error"));
277
- }
278
- if (statusCode.isNotGood()) {
279
- return callback(null, statusCode);
280
- }
281
- callback(null, node_opcua_status_code_1.StatusCodes.Good);
282
- });
283
- }
284
- setTriggering(...args) {
285
- const triggeringItem = args[0];
286
- const linksToAdd = args[1];
287
- const linksToRemove = args[2];
288
- const callback = args[3];
289
- (0, node_opcua_assert_1.assert)(typeof callback === "function");
290
- const session = this.session;
291
- if (!session) {
292
- return callback(new Error("no session"));
293
- }
294
- const subscriptionId = this.subscriptionId;
295
- const triggeringItemId = triggeringItem.monitoredItemId;
296
- const setTriggeringRequest = new node_opcua_service_subscription_1.SetTriggeringRequest({
297
- linksToAdd: linksToAdd ? linksToAdd.map((i) => i.monitoredItemId) : null,
298
- linksToRemove: linksToRemove ? linksToRemove.map((i) => i.monitoredItemId) : null,
299
- subscriptionId,
300
- triggeringItemId
301
- });
302
- session.setTriggering(setTriggeringRequest, (err, response) => {
303
- if (err) {
304
- if (response) {
305
- // use soft error, no exceptions
306
- return callback(null, response);
307
- }
308
- else {
309
- return callback(err);
310
- }
311
- }
312
- // istanbul ignore next
313
- if (!response) {
314
- return callback(new Error("Internal Error"));
315
- }
316
- callback(null, response);
317
- });
318
- }
319
- modify(...args) {
320
- const modifySubscriptionRequest = args[0];
321
- const callback = args[1];
322
- const session = this.session;
323
- if (!session) {
324
- return callback(new Error("no session"));
325
- }
326
- modifySubscriptionRequest.subscriptionId = this.subscriptionId;
327
- modifySubscriptionRequest.priority =
328
- modifySubscriptionRequest.priority === undefined ? this.priority : modifySubscriptionRequest.priority;
329
- modifySubscriptionRequest.requestedLifetimeCount =
330
- modifySubscriptionRequest.requestedLifetimeCount === undefined
331
- ? this.lifetimeCount
332
- : modifySubscriptionRequest.requestedLifetimeCount;
333
- modifySubscriptionRequest.requestedMaxKeepAliveCount =
334
- modifySubscriptionRequest.requestedMaxKeepAliveCount === undefined
335
- ? this.maxKeepAliveCount
336
- : modifySubscriptionRequest.requestedMaxKeepAliveCount;
337
- modifySubscriptionRequest.requestedPublishingInterval =
338
- modifySubscriptionRequest.requestedPublishingInterval === undefined
339
- ? this.publishingInterval
340
- : modifySubscriptionRequest.requestedPublishingInterval;
341
- modifySubscriptionRequest.maxNotificationsPerPublish =
342
- modifySubscriptionRequest.maxNotificationsPerPublish === undefined
343
- ? this.maxNotificationsPerPublish
344
- : modifySubscriptionRequest.maxNotificationsPerPublish;
345
- session.modifySubscription(modifySubscriptionRequest, (err, response) => {
346
- if (err || !response) {
347
- return callback(err);
348
- }
349
- this.publishingInterval = response.revisedPublishingInterval;
350
- this.lifetimeCount = response.revisedLifetimeCount;
351
- this.maxKeepAliveCount = response.revisedMaxKeepAliveCount;
352
- callback(null, response);
353
- });
354
- }
355
- getMonitoredItems(...args) {
356
- this.session.getMonitoredItems(this.subscriptionId, args[0]);
357
- }
358
- /**
359
- * utility function to recreate new subscription
360
- * @method recreateSubscriptionAndMonitoredItem
361
- */
362
- recreateSubscriptionAndMonitoredItem(callback) {
363
- debugLog("ClientSubscription#recreateSubscriptionAndMonitoredItem");
364
- if (this.subscriptionId === TERMINATED_SUBSCRIPTION_ID) {
365
- debugLog("Subscription is not in a valid state");
366
- return callback();
367
- }
368
- const oldMonitoredItems = this.monitoredItems;
369
- this.publishEngine.unregisterSubscription(this.subscriptionId);
370
- async.series([
371
- (innerCallback) => {
372
- this.__create_subscription(innerCallback);
373
- },
374
- (innerCallback) => {
375
- const test = this.publishEngine.getSubscription(this.subscriptionId);
376
- debugLog("recreating ", Object.keys(oldMonitoredItems).length, " monitored Items");
377
- // re-create monitored items
378
- const itemsToCreate = [];
379
- for (const monitoredItem of Object.values(oldMonitoredItems)) {
380
- (0, node_opcua_assert_1.assert)(monitoredItem.monitoringParameters.clientHandle > 0);
381
- itemsToCreate.push({
382
- itemToMonitor: monitoredItem.itemToMonitor,
383
- monitoringMode: monitoredItem.monitoringMode,
384
- requestedParameters: monitoredItem.monitoringParameters
385
- });
386
- }
387
- const createMonitorItemsRequest = new node_opcua_service_subscription_1.CreateMonitoredItemsRequest({
388
- itemsToCreate,
389
- subscriptionId: this.subscriptionId,
390
- timestampsToReturn: node_opcua_service_read_1.TimestampsToReturn.Both // this.timestampsToReturn,
391
- });
392
- const session = this.session;
393
- // istanbul ignore next
394
- if (!session) {
395
- return innerCallback(new Error("no session"));
396
- }
397
- debugLog("Recreating ", itemsToCreate.length, " monitored items");
398
- createMonitoredItemsAndRespectOperationalLimits(session, createMonitorItemsRequest, (err, response) => {
399
- if (err) {
400
- debugLog("Recreating monitored item has failed with ", err.message);
401
- return innerCallback(err);
402
- }
403
- /* istanbul ignore next */
404
- if (!response) {
405
- return innerCallback(new Error("Internal Error"));
406
- }
407
- const monitoredItemResults = response.results || [];
408
- monitoredItemResults.forEach((monitoredItemResult, index) => {
409
- const itemToCreate = itemsToCreate[index];
410
- /* istanbul ignore next */
411
- if (!itemToCreate || !itemToCreate.requestedParameters) {
412
- throw new Error("Internal Error");
413
- }
414
- const clientHandle = itemToCreate.requestedParameters.clientHandle;
415
- /* istanbul ignore next */
416
- if (!clientHandle) {
417
- throw new Error("Internal Error");
418
- }
419
- const monitoredItem = this.monitoredItems[clientHandle];
420
- if (monitoredItem) {
421
- monitoredItem._applyResult(monitoredItemResult);
422
- }
423
- else {
424
- warningLog("cannot find monitored item for clientHandle !:", clientHandle);
425
- }
426
- });
427
- innerCallback();
428
- });
429
- }
430
- ], (err) => {
431
- if (err) {
432
- warningLog(err.message);
433
- }
434
- callback(err);
435
- });
436
- }
437
- toString() {
438
- let str = "";
439
- str += "subscriptionId : " + this.subscriptionId + "\n";
440
- str += "publishingInterval : " + this.publishingInterval + "\n";
441
- str += "lifetimeCount : " + this.lifetimeCount + "\n";
442
- str += "maxKeepAliveCount : " + this.maxKeepAliveCount + "\n";
443
- str += "hasTimedOut : " + this.hasTimedOut + "\n";
444
- const timeToLive = this.lifetimeCount * this.publishingInterval;
445
- str += "timeToLive : " + timeToLive + "\n";
446
- str += "lastRequestSentTime : " + this.lastRequestSentTime.toString() + "\n";
447
- const duration = Date.now() - this.lastRequestSentTime.getTime();
448
- const extra = duration - timeToLive > 0
449
- ? chalk.red(" expired since " + (duration - timeToLive) / 1000 + " seconds")
450
- : chalk.green(" valid for " + -(duration - timeToLive) / 1000 + " seconds");
451
- str += "timeSinceLast PR : " + duration + "ms" + extra + "\n";
452
- str += "has expired : " + (duration > timeToLive) + "\n";
453
- str += "(session timeout : " + this.session.timeout + " ms)\n";
454
- str += "(maxKeepAliveCount*publishingInterval: " + this.publishingInterval * this.session.timeout + " ms)\n";
455
- return str;
456
- }
457
- /**
458
- * returns the approximated remaining life time of this subscription in milliseconds
459
- */
460
- evaluateRemainingLifetime() {
461
- const now = Date.now();
462
- const timeout = this.publishingInterval * this.lifetimeCount;
463
- const expiryTime = this.lastRequestSentTime.getTime() + timeout;
464
- return Math.max(0, expiryTime - now);
465
- }
466
- _add_monitored_item(clientHandle, monitoredItem) {
467
- (0, node_opcua_assert_1.assert)(this.isActive, "subscription must be active and not terminated");
468
- (0, node_opcua_assert_1.assert)(monitoredItem.monitoringParameters.clientHandle === clientHandle);
469
- this.monitoredItems[clientHandle] = monitoredItem;
470
- /**
471
- * notify the observers that a new monitored item has been added to the subscription.
472
- * @event item_added
473
- * @param the monitored item.
474
- */
475
- this.emit("item_added", monitoredItem);
476
- }
477
- _add_monitored_items_group(monitoredItemGroup) {
478
- this.monitoredItemGroups.push(monitoredItemGroup);
479
- }
480
- _wait_for_subscription_to_be_ready(done) {
481
- let _watchDogCount = 0;
482
- const waitForSubscriptionAndMonitor = () => {
483
- _watchDogCount++;
484
- if (this.subscriptionId === PENDING_SUBSCRIPTION_ID) {
485
- // the subscriptionID is not yet known because the server hasn't replied yet
486
- // let postpone this call, a little bit, to let things happen
487
- setImmediate(waitForSubscriptionAndMonitor);
488
- }
489
- else if (this.subscriptionId === TERMINATED_SUBSCRIPTION_ID) {
490
- // the subscription has been terminated in the meantime
491
- // this indicates a potential issue in the code using this api.
492
- if (typeof done === "function") {
493
- done(new Error("subscription has been deleted"));
494
- }
495
- }
496
- else {
497
- done();
498
- }
499
- };
500
- setImmediate(waitForSubscriptionAndMonitor);
501
- }
502
- __create_subscription(callback) {
503
- (0, node_opcua_assert_1.assert)(typeof callback === "function");
504
- // istanbul ignore next
505
- if (!this.hasSession) {
506
- return callback(new Error("No Session"));
507
- }
508
- const session = this.session;
509
- debugLog(chalk.yellow.bold("ClientSubscription created "));
510
- const request = new node_opcua_service_subscription_1.CreateSubscriptionRequest({
511
- maxNotificationsPerPublish: this.maxNotificationsPerPublish,
512
- priority: this.priority,
513
- publishingEnabled: this.publishingEnabled,
514
- requestedLifetimeCount: this.lifetimeCount,
515
- requestedMaxKeepAliveCount: this.maxKeepAliveCount,
516
- requestedPublishingInterval: this.publishingInterval
517
- });
518
- session.createSubscription(request, (err, response) => {
519
- if (err) {
520
- /* istanbul ignore next */
521
- this.emit("internal_error", err);
522
- if (callback) {
523
- return callback(err);
524
- }
525
- return;
526
- }
527
- /* istanbul ignore next */
528
- if (!response) {
529
- return callback(new Error("internal error"));
530
- }
531
- if (!this.hasSession) {
532
- return callback(new Error("createSubscription has failed = > no session"));
533
- }
534
- (0, node_opcua_assert_1.assert)(this.hasSession);
535
- this.subscriptionId = response.subscriptionId;
536
- this.publishingInterval = response.revisedPublishingInterval;
537
- this.lifetimeCount = response.revisedLifetimeCount;
538
- this.maxKeepAliveCount = response.revisedMaxKeepAliveCount;
539
- this.timeoutHint = Math.min((this.maxKeepAliveCount + 10) * this.publishingInterval * 2, 0x7ffff);
540
- displayKeepAliveWarning(this.session.timeout, this.maxKeepAliveCount, this.publishingInterval);
541
- client_subscription_1.ClientSubscription.ignoreNextWarning = false;
542
- if (doDebug) {
543
- debugLog(chalk.yellow.bold("registering callback"));
544
- debugLog(chalk.yellow.bold("publishingInterval "), this.publishingInterval);
545
- debugLog(chalk.yellow.bold("lifetimeCount "), this.lifetimeCount);
546
- debugLog(chalk.yellow.bold("maxKeepAliveCount "), this.maxKeepAliveCount);
547
- debugLog(chalk.yellow.bold("publish request timeout hint = "), this.timeoutHint);
548
- debugLog(chalk.yellow.bold("hasTimedOut "), this.hasTimedOut);
549
- debugLog(chalk.yellow.bold("timeoutHint for publish request "), this.timeoutHint);
550
- }
551
- this.publishEngine.registerSubscription(this);
552
- if (callback) {
553
- callback();
554
- }
555
- });
556
- }
557
- __on_publish_response_DataChangeNotification(notification) {
558
- (0, node_opcua_assert_1.assert)(notification.schema.name === "DataChangeNotification");
559
- const monitoredItems = notification.monitoredItems || [];
560
- let repeated = 0;
561
- for (const monitoredItem of monitoredItems) {
562
- const monitorItemObj = this.monitoredItems[monitoredItem.clientHandle];
563
- if (monitorItemObj) {
564
- if (monitorItemObj.itemToMonitor.attributeId === node_opcua_data_model_1.AttributeIds.EventNotifier) {
565
- warningLog(chalk.yellow("Warning"), chalk.cyan(" Server send a DataChangeNotification for an EventNotifier." + " EventNotificationList was expected"));
566
- warningLog(chalk.cyan(" the Server may not be fully OPCUA compliant"), chalk.yellow(". This notification will be ignored."));
567
- }
568
- else {
569
- const monitoredItemImpl = monitorItemObj;
570
- monitoredItemImpl._notify_value_change(monitoredItem.value);
571
- }
572
- }
573
- else {
574
- repeated += 1;
575
- if (repeated === 1) {
576
- warningLog("Receiving a notification for a unknown monitoredItem with clientHandle ", monitoredItem.clientHandle);
577
- }
578
- }
579
- }
580
- // istanbul ignore next
581
- if (repeated > 1) {
582
- warningLog("previous message repeated", repeated, "times");
583
- }
584
- }
585
- __on_publish_response_StatusChangeNotification(notification) {
586
- (0, node_opcua_assert_1.assert)(notification.schema.name === "StatusChangeNotification");
587
- debugLog("Client has received a Status Change Notification ", notification.status.toString());
588
- if (notification.status === node_opcua_status_code_1.StatusCodes.GoodSubscriptionTransferred) {
589
- // OPCUA UA Spec 1.0.3 : part 3 - page 82 - 5.13.7 TransferSubscriptions:
590
- // If the Server transfers the Subscription to the new Session, the Server shall issue
591
- // a StatusChangeNotification notificationMessage with the status code
592
- // Good_SubscriptionTransferred to the old Session.
593
- debugLog("ClientSubscription#__on_publish_response_StatusChangeNotification : GoodSubscriptionTransferred");
594
- // may be it has been transferred after a reconnection.... in this case should do nothing about it
595
- }
596
- if (notification.status === node_opcua_status_code_1.StatusCodes.BadTimeout) {
597
- // the server tells use that the subscription has timed out ..
598
- // this mean that this subscription has been closed on the server side and cannot process any
599
- // new PublishRequest.
600
- //
601
- // from Spec OPCUA Version 1.03 Part 4 - 5.13.1.1 Description : Page 69:
602
- //
603
- // h. Subscriptions have a lifetime counter that counts the number of consecutive publishing cycles in
604
- // which there have been no Publish requests available to send a Publish response for the
605
- // Subscription. Any Service call that uses the SubscriptionId or the processing of a Publish
606
- // response resets the lifetime counter of this Subscription. When this counter reaches the value
607
- // calculated for the lifetime of a Subscription based on the MaxKeepAliveCount parameter in the
608
- // CreateSubscription Service (5.13.2), the Subscription is closed. Closing the Subscription causes
609
- // its MonitoredItems to be deleted. In addition the Server shall issue a StatusChangeNotification
610
- // notificationMessage with the status code BadTimeout.
611
- //
612
- this.hasTimedOut = true;
613
- this.terminate(() => {
614
- /* empty */
615
- });
616
- }
617
- /**
618
- * notify the observers that the server has send a status changed notification (such as BadTimeout )
619
- * @event status_changed
620
- */
621
- this.emit("status_changed", notification.status, notification.diagnosticInfo);
622
- }
623
- __on_publish_response_EventNotificationList(notification) {
624
- (0, node_opcua_assert_1.assert)(notification.schema.name === "EventNotificationList");
625
- const events = notification.events || [];
626
- for (const event of events) {
627
- const monitorItemObj = this.monitoredItems[event.clientHandle];
628
- (0, node_opcua_assert_1.assert)(monitorItemObj, "Expecting a monitored item");
629
- const monitoredItemImpl = monitorItemObj;
630
- monitoredItemImpl._notify_event(event.eventFields || []);
631
- }
632
- }
633
- onNotificationMessage(notificationMessage) {
634
- (0, node_opcua_assert_1.assert)(Object.prototype.hasOwnProperty.call(notificationMessage, "sequenceNumber"));
635
- this.lastSequenceNumber = notificationMessage.sequenceNumber;
636
- this.emit("raw_notification", notificationMessage);
637
- const notificationData = (notificationMessage.notificationData || []);
638
- if (notificationData.length === 0) {
639
- // this is a keep alive message
640
- debugLog(chalk.yellow("Client : received a keep alive notification from client"));
641
- /**
642
- * notify the observers that a keep alive Publish Response has been received from the server.
643
- * @event keepalive
644
- */
645
- this.emit("keepalive");
646
- }
647
- else {
648
- /**
649
- * notify the observers that some notifications has been received from the server in a PublishResponse
650
- * each modified monitored Item
651
- * @event received_notifications
652
- */
653
- this.emit("received_notifications", notificationMessage);
654
- // let publish a global event
655
- (0, node_opcua_client_dynamic_extension_object_1.promoteOpaqueStructureInNotificationData)(this.session, notificationData).then(() => {
656
- (0, performance_1.detectLongOperation)(() => {
657
- // now process all notifications
658
- for (const notification of notificationData) {
659
- // istanbul ignore next
660
- if (!notification) {
661
- continue;
662
- }
663
- // DataChangeNotification / StatusChangeNotification / EventNotification
664
- switch (notification.schema.name) {
665
- case "DataChangeNotification":
666
- // now inform each individual monitored item
667
- this.__on_publish_response_DataChangeNotification(notification);
668
- break;
669
- case "StatusChangeNotification":
670
- this.__on_publish_response_StatusChangeNotification(notification);
671
- break;
672
- case "EventNotificationList":
673
- this.__on_publish_response_EventNotificationList(notification);
674
- break;
675
- default:
676
- warningLog(" Invalid notification :", notification.toString());
677
- }
678
- }
679
- }, (duration) => {
680
- const s = (a) => {
681
- const b = a;
682
- b.$_slowNotifCount = b.$_slowNotifCount || 0;
683
- b.$_maxDuration = b.$_maxDuration || 0;
684
- return b;
685
- };
686
- s(this).$_maxDuration = Math.max(s(this).$_maxDuration, duration);
687
- if (s(this).$_slowNotifCount > 0 && s(this).$_slowNotifCount % 1000 !== 0)
688
- return;
689
- s(this).$_slowNotifCount++;
690
- warningLog(`[NODE-OPCUA-W32]}: monitored.item event handler takes too much time : operation duration ${duration} ms [repeated ${s(this).$_slowNotifCount} times]\n please ensure that your monitoreItem event handler is not blocking the event loop.`);
691
- });
692
- });
693
- }
694
- }
695
- _terminate_step2(callback) {
696
- const monitoredItems = Object.values(this.monitoredItems);
697
- for (const monitoredItem of monitoredItems) {
698
- this._remove(monitoredItem);
699
- }
700
- const monitoredItemGroups = this.monitoredItemGroups;
701
- for (const monitoredItemGroup of monitoredItemGroups) {
702
- this._removeGroup(monitoredItemGroup);
703
- }
704
- (0, node_opcua_assert_1.assert)(Object.values(this.monitoredItems).length === 0);
705
- setImmediate(() => {
706
- /**
707
- * notify the observers that the client subscription has terminated
708
- * @event terminated
709
- */
710
- this.subscriptionId = TERMINATED_SUBSCRIPTION_ID;
711
- this.emit("terminated");
712
- callback();
713
- });
714
- }
715
- _remove(monitoredItem) {
716
- const clientHandle = monitoredItem.monitoringParameters.clientHandle;
717
- (0, node_opcua_assert_1.assert)(clientHandle > 0);
718
- if (!Object.prototype.hasOwnProperty.call(this.monitoredItems, clientHandle)) {
719
- return; // may be monitoredItem failed to be created ....
720
- }
721
- (0, node_opcua_assert_1.assert)(Object.prototype.hasOwnProperty.call(this.monitoredItems, clientHandle));
722
- const priv = monitoredItem;
723
- priv._terminate_and_emit();
724
- }
725
- _removeGroup(monitoredItemGroup) {
726
- monitoredItemGroup._terminate_and_emit();
727
- this.monitoredItemGroups = this.monitoredItemGroups.filter((obj) => obj !== monitoredItemGroup);
728
- }
729
- /**
730
- * @private
731
- * @param itemToMonitor
732
- * @param monitoringParameters
733
- * @param timestampsToReturn
734
- */
735
- _createMonitoredItem(itemToMonitor, monitoringParameters, timestampsToReturn, monitoringMode = node_opcua_service_subscription_1.MonitoringMode.Reporting) {
736
- /* istanbul ignore next*/
737
- const monitoredItem = new client_monitored_item_impl_1.ClientMonitoredItemImpl(this, itemToMonitor, monitoringParameters, timestampsToReturn, monitoringMode);
738
- return monitoredItem;
739
- }
740
- }
741
- exports.ClientSubscriptionImpl = ClientSubscriptionImpl;
742
- function ClientMonitoredItem_create(subscription, itemToMonitor, monitoringParameters, timestampsToReturn, monitoringMode = node_opcua_service_subscription_1.MonitoringMode.Reporting, callback) {
743
- const monitoredItem = new client_monitored_item_impl_1.ClientMonitoredItemImpl(subscription, itemToMonitor, monitoringParameters, timestampsToReturn, monitoringMode);
744
- setImmediate(() => {
745
- subscription._wait_for_subscription_to_be_ready((err) => {
746
- if (err) {
747
- if (callback) {
748
- callback(err);
749
- }
750
- return;
751
- }
752
- client_monitored_item_toolbox_1.ClientMonitoredItemToolbox._toolbox_monitor(subscription, timestampsToReturn, [monitoredItem], (err1) => {
753
- if (err1) {
754
- monitoredItem._terminate_and_emit(err1);
755
- }
756
- if (callback) {
757
- callback(err1, monitoredItem);
758
- }
759
- });
760
- });
761
- });
762
- return monitoredItem;
763
- }
764
- exports.ClientMonitoredItem_create = ClientMonitoredItem_create;
765
- // tslint:disable:no-var-requires
766
- // tslint:disable:max-line-length
767
- const thenify = require("thenify");
768
- const opts = { multiArgs: false };
769
- ClientSubscriptionImpl.prototype.setPublishingMode = thenify.withCallback(ClientSubscriptionImpl.prototype.setPublishingMode);
770
- ClientSubscriptionImpl.prototype.monitor = thenify.withCallback(ClientSubscriptionImpl.prototype.monitor);
771
- ClientSubscriptionImpl.prototype.monitorItems = thenify.withCallback(ClientSubscriptionImpl.prototype.monitorItems);
772
- ClientSubscriptionImpl.prototype.setTriggering = thenify.withCallback(ClientSubscriptionImpl.prototype.setTriggering);
773
- ClientSubscriptionImpl.prototype.modify = thenify.withCallback(ClientSubscriptionImpl.prototype.modify);
774
- ClientSubscriptionImpl.prototype.recreateSubscriptionAndMonitoredItem = thenify.withCallback(ClientSubscriptionImpl.prototype.recreateSubscriptionAndMonitoredItem);
775
- ClientSubscriptionImpl.prototype.terminate = thenify.withCallback(ClientSubscriptionImpl.prototype.terminate);
776
- ClientSubscriptionImpl.prototype.getMonitoredItems = thenify.withCallback(ClientSubscriptionImpl.prototype.getMonitoredItems);
777
- client_subscription_1.ClientSubscription.create = (clientSession, options) => {
778
- return new ClientSubscriptionImpl(clientSession, options);
779
- };
65
+ `);
66
+ if (!client_subscription_1.ClientSubscription.ignoreNextWarning) {
67
+ throw new Error("[NODE-OPCUA-W09] The subscription parameters are not compatible with the session timeout ");
68
+ }
69
+ return true;
70
+ }
71
+ return false;
72
+ }
73
+ function createMonitoredItemsAndRespectOperationalLimits(session, createMonitorItemsRequest, callback) {
74
+ (0, node_opcua_pseudo_session_1.readOperationLimits)(session)
75
+ .then((operationalLimits) => {
76
+ (0, node_opcua_pseudo_session_1.createMonitoredItemsLimit)(operationalLimits.maxMonitoredItemsPerCall || 0, session, createMonitorItemsRequest)
77
+ .then((createMonitoredItemResponse) => callback(null, createMonitoredItemResponse))
78
+ .catch(callback);
79
+ })
80
+ .catch(callback);
81
+ }
82
+ class ClientSubscriptionImpl extends events_1.EventEmitter {
83
+ /**
84
+ * the associated session
85
+ * @property session
86
+ * @type {ClientSession}
87
+ */
88
+ get session() {
89
+ (0, node_opcua_assert_1.assert)(this.publishEngine.session, "expecting a valid session here");
90
+ return this.publishEngine.session;
91
+ }
92
+ get hasSession() {
93
+ return !!this.publishEngine.session;
94
+ }
95
+ get isActive() {
96
+ return !(this.subscriptionId === PENDING_SUBSCRIPTION_ID ||
97
+ this.subscriptionId === TERMINATED_SUBSCRIPTION_ID ||
98
+ this.subscriptionId === TERMINATING_SUBSCRIPTION_ID);
99
+ }
100
+ constructor(session, options) {
101
+ super();
102
+ this.monitoredItemGroups = [];
103
+ this.timeoutHint = 0;
104
+ this._nextClientHandle = 0;
105
+ const sessionImpl = session;
106
+ this.publishEngine = sessionImpl.getPublishEngine();
107
+ this.lastSequenceNumber = -1;
108
+ options = options || {};
109
+ options.requestedPublishingInterval = options.requestedPublishingInterval || 100;
110
+ options.requestedLifetimeCount = options.requestedLifetimeCount || 60;
111
+ options.requestedMaxKeepAliveCount = options.requestedMaxKeepAliveCount || 10;
112
+ options.requestedMaxKeepAliveCount = Math.max(options.requestedMaxKeepAliveCount, minimumMaxKeepAliveCount);
113
+ // perform some verification
114
+ const warningEmitted = displayKeepAliveWarning(session.timeout, options.requestedMaxKeepAliveCount, options.requestedPublishingInterval);
115
+ // istanbul ignore next
116
+ if (warningEmitted) {
117
+ warningLog(JSON.stringify(Object.assign({}, options), null, " "));
118
+ }
119
+ options.maxNotificationsPerPublish = utils.isNullOrUndefined(options.maxNotificationsPerPublish)
120
+ ? 0
121
+ : options.maxNotificationsPerPublish;
122
+ options.publishingEnabled = !!options.publishingEnabled;
123
+ options.priority = options.priority || 1;
124
+ this.publishingInterval = options.requestedPublishingInterval;
125
+ this.lifetimeCount = options.requestedLifetimeCount;
126
+ this.maxKeepAliveCount = options.requestedMaxKeepAliveCount;
127
+ this.maxNotificationsPerPublish = options.maxNotificationsPerPublish || 0;
128
+ this.publishingEnabled = options.publishingEnabled;
129
+ this.priority = options.priority;
130
+ this.subscriptionId = PENDING_SUBSCRIPTION_ID;
131
+ this._nextClientHandle = 0;
132
+ this.monitoredItems = {};
133
+ this.lastRequestSentTime = new Date(1, 1, 1970);
134
+ /**
135
+ * set to True when the server has notified us that this subscription has timed out
136
+ * ( maxLifeCounter x published interval without being able to process a PublishRequest
137
+ * @property hasTimedOut
138
+ * @type {boolean}
139
+ */
140
+ this.hasTimedOut = false;
141
+ setImmediate(() => {
142
+ this.__create_subscription((err) => {
143
+ if (!err) {
144
+ setImmediate(() => {
145
+ /**
146
+ * notify the observers that the subscription has now started
147
+ * @event started
148
+ */
149
+ this.emit("started", this.subscriptionId);
150
+ });
151
+ }
152
+ else {
153
+ setImmediate(() => {
154
+ /**
155
+ * notify the observers that the subscription has now failed
156
+ * @event failed
157
+ */
158
+ this.emit("error", err);
159
+ });
160
+ }
161
+ });
162
+ });
163
+ }
164
+ terminate(...args) {
165
+ debugLog("Terminating client subscription ", this.subscriptionId);
166
+ const callback = args[0];
167
+ (0, node_opcua_assert_1.assert)(typeof callback === "function", "expecting a callback function");
168
+ if (this.subscriptionId === TERMINATED_SUBSCRIPTION_ID || this.subscriptionId === TERMINATING_SUBSCRIPTION_ID) {
169
+ // already terminated... just ignore
170
+ return callback(new Error("Already Terminated"));
171
+ }
172
+ if (isFinite(this.subscriptionId)) {
173
+ const subscriptionId = this.subscriptionId;
174
+ this.subscriptionId = TERMINATING_SUBSCRIPTION_ID;
175
+ this.publishEngine.unregisterSubscription(subscriptionId);
176
+ if (!this.hasSession) {
177
+ return this._terminate_step2(callback);
178
+ }
179
+ const session = this.session;
180
+ if (!session) {
181
+ return callback(new Error("no session"));
182
+ }
183
+ session.deleteSubscriptions({
184
+ subscriptionIds: [subscriptionId]
185
+ }, (err, response) => {
186
+ if (response && response.results[0] !== node_opcua_status_code_1.StatusCodes.Good) {
187
+ debugLog("warning: deleteSubscription returned ", response.results);
188
+ }
189
+ if (err) {
190
+ /**
191
+ * notify the observers that an error has occurred
192
+ * @event internal_error
193
+ * @param err the error
194
+ */
195
+ this.emit("internal_error", err);
196
+ }
197
+ this._terminate_step2(callback);
198
+ });
199
+ }
200
+ else {
201
+ debugLog("subscriptionId is not value ", this.subscriptionId);
202
+ (0, node_opcua_assert_1.assert)(this.subscriptionId === PENDING_SUBSCRIPTION_ID);
203
+ this._terminate_step2(callback);
204
+ }
205
+ }
206
+ /**
207
+ * @method nextClientHandle
208
+ */
209
+ nextClientHandle() {
210
+ this._nextClientHandle += 1;
211
+ return this._nextClientHandle;
212
+ }
213
+ monitor(...args) {
214
+ const itemToMonitor = args[0];
215
+ const requestedParameters = args[1];
216
+ const timestampsToReturn = args[2];
217
+ const monitoringMode = typeof args[3] === "function" ? node_opcua_service_subscription_1.MonitoringMode.Reporting : args[3];
218
+ const done = (typeof args[3] === "function" ? args[3] : args[4]);
219
+ (0, node_opcua_assert_1.assert)(typeof done === "function", "expecting a function here");
220
+ itemToMonitor.nodeId = (0, node_opcua_nodeid_1.resolveNodeId)(itemToMonitor.nodeId);
221
+ const monitoredItem = ClientMonitoredItem_create(this, itemToMonitor, requestedParameters, timestampsToReturn, monitoringMode, (err1, monitoredItem2) => {
222
+ if (err1) {
223
+ return done && done(err1);
224
+ }
225
+ done(err1 || null, monitoredItem);
226
+ });
227
+ }
228
+ monitorItems(...args) {
229
+ const itemsToMonitor = args[0];
230
+ const requestedParameters = args[1];
231
+ const timestampsToReturn = args[2];
232
+ const done = args[3];
233
+ const monitoredItemGroup = new client_monitored_item_group_impl_1.ClientMonitoredItemGroupImpl(this, itemsToMonitor, requestedParameters, timestampsToReturn);
234
+ this._wait_for_subscription_to_be_ready((err) => {
235
+ if (err) {
236
+ return done(err);
237
+ }
238
+ monitoredItemGroup._monitor((err1) => {
239
+ if (err1) {
240
+ return done && done(err1);
241
+ }
242
+ done(err1, monitoredItemGroup);
243
+ });
244
+ });
245
+ }
246
+ _delete_monitored_items(monitoredItems, callback) {
247
+ (0, node_opcua_assert_1.assert)(typeof callback === "function");
248
+ (0, node_opcua_assert_1.assert)(Array.isArray(monitoredItems));
249
+ (0, node_opcua_assert_1.assert)(this.isActive);
250
+ for (const monitoredItem of monitoredItems) {
251
+ this._remove(monitoredItem);
252
+ }
253
+ const session = this.session;
254
+ session.deleteMonitoredItems({
255
+ monitoredItemIds: monitoredItems.map((monitoredItem) => monitoredItem.monitoredItemId),
256
+ subscriptionId: this.subscriptionId
257
+ }, (err, response) => {
258
+ callback(err);
259
+ });
260
+ }
261
+ setPublishingMode(...args) {
262
+ const publishingEnabled = args[0];
263
+ const callback = args[1];
264
+ (0, node_opcua_assert_1.assert)(typeof callback === "function");
265
+ const session = this.session;
266
+ if (!session) {
267
+ return callback(new Error("no session"));
268
+ }
269
+ const subscriptionId = this.subscriptionId;
270
+ session.setPublishingMode(publishingEnabled, subscriptionId, (err, statusCode) => {
271
+ if (err) {
272
+ return callback(err);
273
+ }
274
+ /* istanbul ignore next */
275
+ if (!statusCode) {
276
+ return callback(new Error("Internal Error"));
277
+ }
278
+ if (statusCode.isNotGood()) {
279
+ return callback(null, statusCode);
280
+ }
281
+ callback(null, node_opcua_status_code_1.StatusCodes.Good);
282
+ });
283
+ }
284
+ setTriggering(...args) {
285
+ const triggeringItem = args[0];
286
+ const linksToAdd = args[1];
287
+ const linksToRemove = args[2];
288
+ const callback = args[3];
289
+ (0, node_opcua_assert_1.assert)(typeof callback === "function");
290
+ const session = this.session;
291
+ if (!session) {
292
+ return callback(new Error("no session"));
293
+ }
294
+ const subscriptionId = this.subscriptionId;
295
+ const triggeringItemId = triggeringItem.monitoredItemId;
296
+ const setTriggeringRequest = new node_opcua_service_subscription_1.SetTriggeringRequest({
297
+ linksToAdd: linksToAdd ? linksToAdd.map((i) => i.monitoredItemId) : null,
298
+ linksToRemove: linksToRemove ? linksToRemove.map((i) => i.monitoredItemId) : null,
299
+ subscriptionId,
300
+ triggeringItemId
301
+ });
302
+ session.setTriggering(setTriggeringRequest, (err, response) => {
303
+ if (err) {
304
+ if (response) {
305
+ // use soft error, no exceptions
306
+ return callback(null, response);
307
+ }
308
+ else {
309
+ return callback(err);
310
+ }
311
+ }
312
+ // istanbul ignore next
313
+ if (!response) {
314
+ return callback(new Error("Internal Error"));
315
+ }
316
+ callback(null, response);
317
+ });
318
+ }
319
+ modify(...args) {
320
+ const modifySubscriptionRequest = args[0];
321
+ const callback = args[1];
322
+ const session = this.session;
323
+ if (!session) {
324
+ return callback(new Error("no session"));
325
+ }
326
+ modifySubscriptionRequest.subscriptionId = this.subscriptionId;
327
+ modifySubscriptionRequest.priority =
328
+ modifySubscriptionRequest.priority === undefined ? this.priority : modifySubscriptionRequest.priority;
329
+ modifySubscriptionRequest.requestedLifetimeCount =
330
+ modifySubscriptionRequest.requestedLifetimeCount === undefined
331
+ ? this.lifetimeCount
332
+ : modifySubscriptionRequest.requestedLifetimeCount;
333
+ modifySubscriptionRequest.requestedMaxKeepAliveCount =
334
+ modifySubscriptionRequest.requestedMaxKeepAliveCount === undefined
335
+ ? this.maxKeepAliveCount
336
+ : modifySubscriptionRequest.requestedMaxKeepAliveCount;
337
+ modifySubscriptionRequest.requestedPublishingInterval =
338
+ modifySubscriptionRequest.requestedPublishingInterval === undefined
339
+ ? this.publishingInterval
340
+ : modifySubscriptionRequest.requestedPublishingInterval;
341
+ modifySubscriptionRequest.maxNotificationsPerPublish =
342
+ modifySubscriptionRequest.maxNotificationsPerPublish === undefined
343
+ ? this.maxNotificationsPerPublish
344
+ : modifySubscriptionRequest.maxNotificationsPerPublish;
345
+ session.modifySubscription(modifySubscriptionRequest, (err, response) => {
346
+ if (err || !response) {
347
+ return callback(err);
348
+ }
349
+ this.publishingInterval = response.revisedPublishingInterval;
350
+ this.lifetimeCount = response.revisedLifetimeCount;
351
+ this.maxKeepAliveCount = response.revisedMaxKeepAliveCount;
352
+ callback(null, response);
353
+ });
354
+ }
355
+ getMonitoredItems(...args) {
356
+ this.session.getMonitoredItems(this.subscriptionId, args[0]);
357
+ }
358
+ /**
359
+ * utility function to recreate new subscription
360
+ * @method recreateSubscriptionAndMonitoredItem
361
+ */
362
+ recreateSubscriptionAndMonitoredItem(callback) {
363
+ debugLog("ClientSubscription#recreateSubscriptionAndMonitoredItem");
364
+ if (this.subscriptionId === TERMINATED_SUBSCRIPTION_ID) {
365
+ debugLog("Subscription is not in a valid state");
366
+ return callback();
367
+ }
368
+ const oldMonitoredItems = this.monitoredItems;
369
+ this.publishEngine.unregisterSubscription(this.subscriptionId);
370
+ async.series([
371
+ (innerCallback) => {
372
+ this.__create_subscription(innerCallback);
373
+ },
374
+ (innerCallback) => {
375
+ const test = this.publishEngine.getSubscription(this.subscriptionId);
376
+ debugLog("recreating ", Object.keys(oldMonitoredItems).length, " monitored Items");
377
+ // re-create monitored items
378
+ const itemsToCreate = [];
379
+ for (const monitoredItem of Object.values(oldMonitoredItems)) {
380
+ (0, node_opcua_assert_1.assert)(monitoredItem.monitoringParameters.clientHandle > 0);
381
+ itemsToCreate.push({
382
+ itemToMonitor: monitoredItem.itemToMonitor,
383
+ monitoringMode: monitoredItem.monitoringMode,
384
+ requestedParameters: monitoredItem.monitoringParameters
385
+ });
386
+ }
387
+ const createMonitorItemsRequest = new node_opcua_service_subscription_1.CreateMonitoredItemsRequest({
388
+ itemsToCreate,
389
+ subscriptionId: this.subscriptionId,
390
+ timestampsToReturn: node_opcua_service_read_1.TimestampsToReturn.Both // this.timestampsToReturn,
391
+ });
392
+ const session = this.session;
393
+ // istanbul ignore next
394
+ if (!session) {
395
+ return innerCallback(new Error("no session"));
396
+ }
397
+ debugLog("Recreating ", itemsToCreate.length, " monitored items");
398
+ createMonitoredItemsAndRespectOperationalLimits(session, createMonitorItemsRequest, (err, response) => {
399
+ if (err) {
400
+ debugLog("Recreating monitored item has failed with ", err.message);
401
+ return innerCallback(err);
402
+ }
403
+ /* istanbul ignore next */
404
+ if (!response) {
405
+ return innerCallback(new Error("Internal Error"));
406
+ }
407
+ const monitoredItemResults = response.results || [];
408
+ monitoredItemResults.forEach((monitoredItemResult, index) => {
409
+ const itemToCreate = itemsToCreate[index];
410
+ /* istanbul ignore next */
411
+ if (!itemToCreate || !itemToCreate.requestedParameters) {
412
+ throw new Error("Internal Error");
413
+ }
414
+ const clientHandle = itemToCreate.requestedParameters.clientHandle;
415
+ /* istanbul ignore next */
416
+ if (!clientHandle) {
417
+ throw new Error("Internal Error");
418
+ }
419
+ const monitoredItem = this.monitoredItems[clientHandle];
420
+ if (monitoredItem) {
421
+ monitoredItem._applyResult(monitoredItemResult);
422
+ }
423
+ else {
424
+ warningLog("cannot find monitored item for clientHandle !:", clientHandle);
425
+ }
426
+ });
427
+ innerCallback();
428
+ });
429
+ }
430
+ ], (err) => {
431
+ if (err) {
432
+ warningLog(err.message);
433
+ }
434
+ callback(err);
435
+ });
436
+ }
437
+ toString() {
438
+ let str = "";
439
+ str += "subscriptionId : " + this.subscriptionId + "\n";
440
+ str += "publishingInterval : " + this.publishingInterval + "\n";
441
+ str += "lifetimeCount : " + this.lifetimeCount + "\n";
442
+ str += "maxKeepAliveCount : " + this.maxKeepAliveCount + "\n";
443
+ str += "hasTimedOut : " + this.hasTimedOut + "\n";
444
+ const timeToLive = this.lifetimeCount * this.publishingInterval;
445
+ str += "timeToLive : " + timeToLive + "\n";
446
+ str += "lastRequestSentTime : " + this.lastRequestSentTime.toString() + "\n";
447
+ const duration = Date.now() - this.lastRequestSentTime.getTime();
448
+ const extra = duration - timeToLive > 0
449
+ ? chalk.red(" expired since " + (duration - timeToLive) / 1000 + " seconds")
450
+ : chalk.green(" valid for " + -(duration - timeToLive) / 1000 + " seconds");
451
+ str += "timeSinceLast PR : " + duration + "ms" + extra + "\n";
452
+ str += "has expired : " + (duration > timeToLive) + "\n";
453
+ str += "(session timeout : " + this.session.timeout + " ms)\n";
454
+ str += "(maxKeepAliveCount*publishingInterval: " + this.publishingInterval * this.session.timeout + " ms)\n";
455
+ return str;
456
+ }
457
+ /**
458
+ * returns the approximated remaining life time of this subscription in milliseconds
459
+ */
460
+ evaluateRemainingLifetime() {
461
+ const now = Date.now();
462
+ const timeout = this.publishingInterval * this.lifetimeCount;
463
+ const expiryTime = this.lastRequestSentTime.getTime() + timeout;
464
+ return Math.max(0, expiryTime - now);
465
+ }
466
+ _add_monitored_item(clientHandle, monitoredItem) {
467
+ (0, node_opcua_assert_1.assert)(this.isActive, "subscription must be active and not terminated");
468
+ (0, node_opcua_assert_1.assert)(monitoredItem.monitoringParameters.clientHandle === clientHandle);
469
+ this.monitoredItems[clientHandle] = monitoredItem;
470
+ /**
471
+ * notify the observers that a new monitored item has been added to the subscription.
472
+ * @event item_added
473
+ * @param the monitored item.
474
+ */
475
+ this.emit("item_added", monitoredItem);
476
+ }
477
+ _add_monitored_items_group(monitoredItemGroup) {
478
+ this.monitoredItemGroups.push(monitoredItemGroup);
479
+ }
480
+ _wait_for_subscription_to_be_ready(done) {
481
+ let _watchDogCount = 0;
482
+ const waitForSubscriptionAndMonitor = () => {
483
+ _watchDogCount++;
484
+ if (this.subscriptionId === PENDING_SUBSCRIPTION_ID) {
485
+ // the subscriptionID is not yet known because the server hasn't replied yet
486
+ // let postpone this call, a little bit, to let things happen
487
+ setImmediate(waitForSubscriptionAndMonitor);
488
+ }
489
+ else if (this.subscriptionId === TERMINATED_SUBSCRIPTION_ID) {
490
+ // the subscription has been terminated in the meantime
491
+ // this indicates a potential issue in the code using this api.
492
+ if (typeof done === "function") {
493
+ done(new Error("subscription has been deleted"));
494
+ }
495
+ }
496
+ else {
497
+ done();
498
+ }
499
+ };
500
+ setImmediate(waitForSubscriptionAndMonitor);
501
+ }
502
+ __create_subscription(callback) {
503
+ (0, node_opcua_assert_1.assert)(typeof callback === "function");
504
+ // istanbul ignore next
505
+ if (!this.hasSession) {
506
+ return callback(new Error("No Session"));
507
+ }
508
+ const session = this.session;
509
+ debugLog(chalk.yellow.bold("ClientSubscription created "));
510
+ const request = new node_opcua_service_subscription_1.CreateSubscriptionRequest({
511
+ maxNotificationsPerPublish: this.maxNotificationsPerPublish,
512
+ priority: this.priority,
513
+ publishingEnabled: this.publishingEnabled,
514
+ requestedLifetimeCount: this.lifetimeCount,
515
+ requestedMaxKeepAliveCount: this.maxKeepAliveCount,
516
+ requestedPublishingInterval: this.publishingInterval
517
+ });
518
+ session.createSubscription(request, (err, response) => {
519
+ if (err) {
520
+ /* istanbul ignore next */
521
+ this.emit("internal_error", err);
522
+ if (callback) {
523
+ return callback(err);
524
+ }
525
+ return;
526
+ }
527
+ /* istanbul ignore next */
528
+ if (!response) {
529
+ return callback(new Error("internal error"));
530
+ }
531
+ if (!this.hasSession) {
532
+ return callback(new Error("createSubscription has failed = > no session"));
533
+ }
534
+ (0, node_opcua_assert_1.assert)(this.hasSession);
535
+ this.subscriptionId = response.subscriptionId;
536
+ this.publishingInterval = response.revisedPublishingInterval;
537
+ this.lifetimeCount = response.revisedLifetimeCount;
538
+ this.maxKeepAliveCount = response.revisedMaxKeepAliveCount;
539
+ this.timeoutHint = Math.min((this.maxKeepAliveCount + 10) * this.publishingInterval * 2, 0x7ffff);
540
+ displayKeepAliveWarning(this.session.timeout, this.maxKeepAliveCount, this.publishingInterval);
541
+ client_subscription_1.ClientSubscription.ignoreNextWarning = false;
542
+ if (doDebug) {
543
+ debugLog(chalk.yellow.bold("registering callback"));
544
+ debugLog(chalk.yellow.bold("publishingInterval "), this.publishingInterval);
545
+ debugLog(chalk.yellow.bold("lifetimeCount "), this.lifetimeCount);
546
+ debugLog(chalk.yellow.bold("maxKeepAliveCount "), this.maxKeepAliveCount);
547
+ debugLog(chalk.yellow.bold("publish request timeout hint = "), this.timeoutHint);
548
+ debugLog(chalk.yellow.bold("hasTimedOut "), this.hasTimedOut);
549
+ debugLog(chalk.yellow.bold("timeoutHint for publish request "), this.timeoutHint);
550
+ }
551
+ this.publishEngine.registerSubscription(this);
552
+ if (callback) {
553
+ callback();
554
+ }
555
+ });
556
+ }
557
+ __on_publish_response_DataChangeNotification(notification) {
558
+ (0, node_opcua_assert_1.assert)(notification.schema.name === "DataChangeNotification");
559
+ const monitoredItems = notification.monitoredItems || [];
560
+ let repeated = 0;
561
+ for (const monitoredItem of monitoredItems) {
562
+ const monitorItemObj = this.monitoredItems[monitoredItem.clientHandle];
563
+ if (monitorItemObj) {
564
+ if (monitorItemObj.itemToMonitor.attributeId === node_opcua_data_model_1.AttributeIds.EventNotifier) {
565
+ warningLog(chalk.yellow("Warning"), chalk.cyan(" Server send a DataChangeNotification for an EventNotifier." + " EventNotificationList was expected"));
566
+ warningLog(chalk.cyan(" the Server may not be fully OPCUA compliant"), chalk.yellow(". This notification will be ignored."));
567
+ }
568
+ else {
569
+ const monitoredItemImpl = monitorItemObj;
570
+ monitoredItemImpl._notify_value_change(monitoredItem.value);
571
+ }
572
+ }
573
+ else {
574
+ repeated += 1;
575
+ if (repeated === 1) {
576
+ warningLog("Receiving a notification for a unknown monitoredItem with clientHandle ", monitoredItem.clientHandle);
577
+ }
578
+ }
579
+ }
580
+ // istanbul ignore next
581
+ if (repeated > 1) {
582
+ warningLog("previous message repeated", repeated, "times");
583
+ }
584
+ }
585
+ __on_publish_response_StatusChangeNotification(notification) {
586
+ (0, node_opcua_assert_1.assert)(notification.schema.name === "StatusChangeNotification");
587
+ debugLog("Client has received a Status Change Notification ", notification.status.toString());
588
+ if (notification.status === node_opcua_status_code_1.StatusCodes.GoodSubscriptionTransferred) {
589
+ // OPCUA UA Spec 1.0.3 : part 3 - page 82 - 5.13.7 TransferSubscriptions:
590
+ // If the Server transfers the Subscription to the new Session, the Server shall issue
591
+ // a StatusChangeNotification notificationMessage with the status code
592
+ // Good_SubscriptionTransferred to the old Session.
593
+ debugLog("ClientSubscription#__on_publish_response_StatusChangeNotification : GoodSubscriptionTransferred");
594
+ // may be it has been transferred after a reconnection.... in this case should do nothing about it
595
+ }
596
+ if (notification.status === node_opcua_status_code_1.StatusCodes.BadTimeout) {
597
+ // the server tells use that the subscription has timed out ..
598
+ // this mean that this subscription has been closed on the server side and cannot process any
599
+ // new PublishRequest.
600
+ //
601
+ // from Spec OPCUA Version 1.03 Part 4 - 5.13.1.1 Description : Page 69:
602
+ //
603
+ // h. Subscriptions have a lifetime counter that counts the number of consecutive publishing cycles in
604
+ // which there have been no Publish requests available to send a Publish response for the
605
+ // Subscription. Any Service call that uses the SubscriptionId or the processing of a Publish
606
+ // response resets the lifetime counter of this Subscription. When this counter reaches the value
607
+ // calculated for the lifetime of a Subscription based on the MaxKeepAliveCount parameter in the
608
+ // CreateSubscription Service (5.13.2), the Subscription is closed. Closing the Subscription causes
609
+ // its MonitoredItems to be deleted. In addition the Server shall issue a StatusChangeNotification
610
+ // notificationMessage with the status code BadTimeout.
611
+ //
612
+ this.hasTimedOut = true;
613
+ this.terminate(() => {
614
+ /* empty */
615
+ });
616
+ }
617
+ /**
618
+ * notify the observers that the server has send a status changed notification (such as BadTimeout )
619
+ * @event status_changed
620
+ */
621
+ this.emit("status_changed", notification.status, notification.diagnosticInfo);
622
+ }
623
+ __on_publish_response_EventNotificationList(notification) {
624
+ (0, node_opcua_assert_1.assert)(notification.schema.name === "EventNotificationList");
625
+ const events = notification.events || [];
626
+ for (const event of events) {
627
+ const monitorItemObj = this.monitoredItems[event.clientHandle];
628
+ (0, node_opcua_assert_1.assert)(monitorItemObj, "Expecting a monitored item");
629
+ const monitoredItemImpl = monitorItemObj;
630
+ monitoredItemImpl._notify_event(event.eventFields || []);
631
+ }
632
+ }
633
+ onNotificationMessage(notificationMessage) {
634
+ (0, node_opcua_assert_1.assert)(Object.prototype.hasOwnProperty.call(notificationMessage, "sequenceNumber"));
635
+ this.lastSequenceNumber = notificationMessage.sequenceNumber;
636
+ this.emit("raw_notification", notificationMessage);
637
+ const notificationData = (notificationMessage.notificationData || []);
638
+ if (notificationData.length === 0) {
639
+ // this is a keep alive message
640
+ debugLog(chalk.yellow("Client : received a keep alive notification from client"));
641
+ /**
642
+ * notify the observers that a keep alive Publish Response has been received from the server.
643
+ * @event keepalive
644
+ */
645
+ this.emit("keepalive");
646
+ }
647
+ else {
648
+ /**
649
+ * notify the observers that some notifications has been received from the server in a PublishResponse
650
+ * each modified monitored Item
651
+ * @event received_notifications
652
+ */
653
+ this.emit("received_notifications", notificationMessage);
654
+ // let publish a global event
655
+ (0, node_opcua_client_dynamic_extension_object_1.promoteOpaqueStructureInNotificationData)(this.session, notificationData).then(() => {
656
+ (0, performance_1.detectLongOperation)(() => {
657
+ // now process all notifications
658
+ for (const notification of notificationData) {
659
+ // istanbul ignore next
660
+ if (!notification) {
661
+ continue;
662
+ }
663
+ // DataChangeNotification / StatusChangeNotification / EventNotification
664
+ switch (notification.schema.name) {
665
+ case "DataChangeNotification":
666
+ // now inform each individual monitored item
667
+ this.__on_publish_response_DataChangeNotification(notification);
668
+ break;
669
+ case "StatusChangeNotification":
670
+ this.__on_publish_response_StatusChangeNotification(notification);
671
+ break;
672
+ case "EventNotificationList":
673
+ this.__on_publish_response_EventNotificationList(notification);
674
+ break;
675
+ default:
676
+ warningLog(" Invalid notification :", notification.toString());
677
+ }
678
+ }
679
+ }, (duration) => {
680
+ const s = (a) => {
681
+ const b = a;
682
+ b.$_slowNotifCount = b.$_slowNotifCount || 0;
683
+ b.$_maxDuration = b.$_maxDuration || 0;
684
+ return b;
685
+ };
686
+ s(this).$_maxDuration = Math.max(s(this).$_maxDuration, duration);
687
+ if (s(this).$_slowNotifCount > 0 && s(this).$_slowNotifCount % 1000 !== 0)
688
+ return;
689
+ s(this).$_slowNotifCount++;
690
+ warningLog(`[NODE-OPCUA-W32]}: monitored.item event handler takes too much time : operation duration ${duration} ms [repeated ${s(this).$_slowNotifCount} times]\n please ensure that your monitoreItem event handler is not blocking the event loop.`);
691
+ });
692
+ });
693
+ }
694
+ }
695
+ _terminate_step2(callback) {
696
+ const monitoredItems = Object.values(this.monitoredItems);
697
+ for (const monitoredItem of monitoredItems) {
698
+ this._remove(monitoredItem);
699
+ }
700
+ const monitoredItemGroups = this.monitoredItemGroups;
701
+ for (const monitoredItemGroup of monitoredItemGroups) {
702
+ this._removeGroup(monitoredItemGroup);
703
+ }
704
+ (0, node_opcua_assert_1.assert)(Object.values(this.monitoredItems).length === 0);
705
+ setImmediate(() => {
706
+ /**
707
+ * notify the observers that the client subscription has terminated
708
+ * @event terminated
709
+ */
710
+ this.subscriptionId = TERMINATED_SUBSCRIPTION_ID;
711
+ this.emit("terminated");
712
+ callback();
713
+ });
714
+ }
715
+ _remove(monitoredItem) {
716
+ const clientHandle = monitoredItem.monitoringParameters.clientHandle;
717
+ (0, node_opcua_assert_1.assert)(clientHandle > 0);
718
+ if (!Object.prototype.hasOwnProperty.call(this.monitoredItems, clientHandle)) {
719
+ return; // may be monitoredItem failed to be created ....
720
+ }
721
+ (0, node_opcua_assert_1.assert)(Object.prototype.hasOwnProperty.call(this.monitoredItems, clientHandle));
722
+ const priv = monitoredItem;
723
+ priv._terminate_and_emit();
724
+ }
725
+ _removeGroup(monitoredItemGroup) {
726
+ monitoredItemGroup._terminate_and_emit();
727
+ this.monitoredItemGroups = this.monitoredItemGroups.filter((obj) => obj !== monitoredItemGroup);
728
+ }
729
+ /**
730
+ * @private
731
+ * @param itemToMonitor
732
+ * @param monitoringParameters
733
+ * @param timestampsToReturn
734
+ */
735
+ _createMonitoredItem(itemToMonitor, monitoringParameters, timestampsToReturn, monitoringMode = node_opcua_service_subscription_1.MonitoringMode.Reporting) {
736
+ /* istanbul ignore next*/
737
+ const monitoredItem = new client_monitored_item_impl_1.ClientMonitoredItemImpl(this, itemToMonitor, monitoringParameters, timestampsToReturn, monitoringMode);
738
+ return monitoredItem;
739
+ }
740
+ }
741
+ exports.ClientSubscriptionImpl = ClientSubscriptionImpl;
742
+ function ClientMonitoredItem_create(subscription, itemToMonitor, monitoringParameters, timestampsToReturn, monitoringMode = node_opcua_service_subscription_1.MonitoringMode.Reporting, callback) {
743
+ const monitoredItem = new client_monitored_item_impl_1.ClientMonitoredItemImpl(subscription, itemToMonitor, monitoringParameters, timestampsToReturn, monitoringMode);
744
+ setImmediate(() => {
745
+ subscription._wait_for_subscription_to_be_ready((err) => {
746
+ if (err) {
747
+ if (callback) {
748
+ callback(err);
749
+ }
750
+ return;
751
+ }
752
+ client_monitored_item_toolbox_1.ClientMonitoredItemToolbox._toolbox_monitor(subscription, timestampsToReturn, [monitoredItem], (err1) => {
753
+ if (err1) {
754
+ monitoredItem._terminate_and_emit(err1);
755
+ }
756
+ if (callback) {
757
+ callback(err1, monitoredItem);
758
+ }
759
+ });
760
+ });
761
+ });
762
+ return monitoredItem;
763
+ }
764
+ exports.ClientMonitoredItem_create = ClientMonitoredItem_create;
765
+ // tslint:disable:no-var-requires
766
+ // tslint:disable:max-line-length
767
+ const thenify = require("thenify");
768
+ const opts = { multiArgs: false };
769
+ ClientSubscriptionImpl.prototype.setPublishingMode = thenify.withCallback(ClientSubscriptionImpl.prototype.setPublishingMode);
770
+ ClientSubscriptionImpl.prototype.monitor = thenify.withCallback(ClientSubscriptionImpl.prototype.monitor);
771
+ ClientSubscriptionImpl.prototype.monitorItems = thenify.withCallback(ClientSubscriptionImpl.prototype.monitorItems);
772
+ ClientSubscriptionImpl.prototype.setTriggering = thenify.withCallback(ClientSubscriptionImpl.prototype.setTriggering);
773
+ ClientSubscriptionImpl.prototype.modify = thenify.withCallback(ClientSubscriptionImpl.prototype.modify);
774
+ ClientSubscriptionImpl.prototype.recreateSubscriptionAndMonitoredItem = thenify.withCallback(ClientSubscriptionImpl.prototype.recreateSubscriptionAndMonitoredItem);
775
+ ClientSubscriptionImpl.prototype.terminate = thenify.withCallback(ClientSubscriptionImpl.prototype.terminate);
776
+ ClientSubscriptionImpl.prototype.getMonitoredItems = thenify.withCallback(ClientSubscriptionImpl.prototype.getMonitoredItems);
777
+ client_subscription_1.ClientSubscription.create = (clientSession, options) => {
778
+ return new ClientSubscriptionImpl(clientSession, options);
779
+ };
780
780
  //# sourceMappingURL=client_subscription_impl.js.map