node-opcua-client 2.71.0 → 2.72.2

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