node-opcua-client 2.74.0 → 2.76.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 (77) hide show
  1. package/dist/alarms_and_conditions/client_alarm.d.ts +49 -45
  2. package/dist/alarms_and_conditions/client_alarm.js +109 -101
  3. package/dist/alarms_and_conditions/client_alarm.js.map +1 -1
  4. package/dist/alarms_and_conditions/client_alarm_list.d.ts +25 -25
  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 +156 -152
  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 +192 -190
  12. package/dist/alarms_and_conditions/client_alarm_tools_acknowledge_all_conditions.js.map +1 -1
  13. package/dist/alarms_and_conditions/client_alarm_tools_dump_event.d.ts +9 -9
  14. package/dist/alarms_and_conditions/client_alarm_tools_dump_event.js +73 -73
  15. package/dist/alarms_and_conditions/client_alarm_tools_extractConditionFields.d.ts +3 -8
  16. package/dist/alarms_and_conditions/client_alarm_tools_extractConditionFields.js +118 -120
  17. package/dist/alarms_and_conditions/client_alarm_tools_extractConditionFields.js.map +1 -1
  18. package/dist/alarms_and_conditions/client_tools.d.ts +7 -7
  19. package/dist/alarms_and_conditions/client_tools.js +180 -180
  20. package/dist/client_base.d.ts +277 -277
  21. package/dist/client_base.js +14 -14
  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/private/client_base_impl.d.ts +157 -157
  45. package/dist/private/client_base_impl.js +1337 -1337
  46. package/dist/private/client_monitored_item_base_impl.d.ts +3 -3
  47. package/dist/private/client_monitored_item_base_impl.js +4 -4
  48. package/dist/private/client_monitored_item_group_impl.d.ts +53 -53
  49. package/dist/private/client_monitored_item_group_impl.js +159 -159
  50. package/dist/private/client_monitored_item_impl.d.ts +93 -93
  51. package/dist/private/client_monitored_item_impl.js +305 -304
  52. package/dist/private/client_monitored_item_impl.js.map +1 -1
  53. package/dist/private/client_publish_engine.d.ts +62 -62
  54. package/dist/private/client_publish_engine.js +408 -408
  55. package/dist/private/client_session_impl.d.ts +621 -621
  56. package/dist/private/client_session_impl.js +1302 -1302
  57. package/dist/private/client_subscription_impl.d.ts +93 -93
  58. package/dist/private/client_subscription_impl.js +748 -748
  59. package/dist/private/i_private_client.d.ts +18 -18
  60. package/dist/private/i_private_client.js +2 -2
  61. package/dist/private/opcua_client_impl.d.ts +169 -169
  62. package/dist/private/opcua_client_impl.js +981 -981
  63. package/dist/reconnection.d.ts +9 -9
  64. package/dist/reconnection.js +408 -408
  65. package/dist/tools/findservers.d.ts +20 -20
  66. package/dist/tools/findservers.js +61 -61
  67. package/dist/tools/read_history_server_capabilities.d.ts +6 -6
  68. package/dist/tools/read_history_server_capabilities.js +99 -99
  69. package/dist/verify.d.ts +5 -5
  70. package/dist/verify.js +134 -134
  71. package/package.json +46 -46
  72. package/source/alarms_and_conditions/client_alarm.ts +28 -17
  73. package/source/alarms_and_conditions/client_alarm_list.ts +1 -0
  74. package/source/alarms_and_conditions/client_alarm_tools.ts +33 -23
  75. package/source/alarms_and_conditions/client_alarm_tools_acknowledge_all_conditions.ts +10 -4
  76. package/source/alarms_and_conditions/client_alarm_tools_extractConditionFields.ts +11 -11
  77. package/source/private/client_monitored_item_impl.ts +4 -3
@@ -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,705 +61,705 @@ 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
- 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
- if (response) {
304
- // use soft error, no exceptions
305
- return callback(null, response);
306
- }
307
- else {
308
- return callback(err);
309
- }
310
- }
311
- // istanbul ignore next
312
- if (!response) {
313
- return callback(new Error("Internal Error"));
314
- }
315
- callback(null, response);
316
- });
317
- }
318
- modify(...args) {
319
- const modifySubscriptionRequest = args[0];
320
- const callback = args[1];
321
- const session = this.session;
322
- if (!session) {
323
- return callback(new Error("no session"));
324
- }
325
- modifySubscriptionRequest.subscriptionId = this.subscriptionId;
326
- modifySubscriptionRequest.priority =
327
- modifySubscriptionRequest.priority === undefined ? this.priority : modifySubscriptionRequest.priority;
328
- modifySubscriptionRequest.requestedLifetimeCount =
329
- modifySubscriptionRequest.requestedLifetimeCount === undefined
330
- ? this.lifetimeCount
331
- : modifySubscriptionRequest.requestedLifetimeCount;
332
- modifySubscriptionRequest.requestedMaxKeepAliveCount =
333
- modifySubscriptionRequest.requestedMaxKeepAliveCount === undefined
334
- ? this.maxKeepAliveCount
335
- : modifySubscriptionRequest.requestedMaxKeepAliveCount;
336
- modifySubscriptionRequest.requestedPublishingInterval =
337
- modifySubscriptionRequest.requestedPublishingInterval === undefined
338
- ? this.publishingInterval
339
- : modifySubscriptionRequest.requestedPublishingInterval;
340
- modifySubscriptionRequest.maxNotificationsPerPublish =
341
- modifySubscriptionRequest.maxNotificationsPerPublish === undefined
342
- ? this.maxNotificationsPerPublish
343
- : modifySubscriptionRequest.maxNotificationsPerPublish;
344
- session.modifySubscription(modifySubscriptionRequest, (err, response) => {
345
- if (err || !response) {
346
- return callback(err);
347
- }
348
- this.publishingInterval = response.revisedPublishingInterval;
349
- this.lifetimeCount = response.revisedLifetimeCount;
350
- this.maxKeepAliveCount = response.revisedMaxKeepAliveCount;
351
- callback(null, response);
352
- });
353
- }
354
- getMonitoredItems(...args) {
355
- this.session.getMonitoredItems(this.subscriptionId, args[0]);
356
- }
357
- /**
358
- * utility function to recreate new subscription
359
- * @method recreateSubscriptionAndMonitoredItem
360
- */
361
- recreateSubscriptionAndMonitoredItem(callback) {
362
- debugLog("ClientSubscription#recreateSubscriptionAndMonitoredItem");
363
- if (this.subscriptionId === TERMINATED_SUBSCRIPTION_ID) {
364
- debugLog("Subscription is not in a valid state");
365
- return callback();
366
- }
367
- const oldMonitoredItems = this.monitoredItems;
368
- this.publishEngine.unregisterSubscription(this.subscriptionId);
369
- async.series([
370
- (innerCallback) => {
371
- this.__create_subscription(innerCallback);
372
- },
373
- (innerCallback) => {
374
- const test = this.publishEngine.getSubscription(this.subscriptionId);
375
- debugLog("recreating ", Object.keys(oldMonitoredItems).length, " monitored Items");
376
- // re-create monitored items
377
- const itemsToCreate = [];
378
- for (const monitoredItem of Object.values(oldMonitoredItems)) {
379
- (0, node_opcua_assert_1.assert)(monitoredItem.monitoringParameters.clientHandle > 0);
380
- itemsToCreate.push({
381
- itemToMonitor: monitoredItem.itemToMonitor,
382
- monitoringMode: monitoredItem.monitoringMode,
383
- requestedParameters: monitoredItem.monitoringParameters
384
- });
385
- }
386
- const createMonitorItemsRequest = new node_opcua_service_subscription_1.CreateMonitoredItemsRequest({
387
- itemsToCreate,
388
- subscriptionId: this.subscriptionId,
389
- timestampsToReturn: node_opcua_service_read_1.TimestampsToReturn.Both // this.timestampsToReturn,
390
- });
391
- const session = this.session;
392
- // istanbul ignore next
393
- if (!session) {
394
- return innerCallback(new Error("no session"));
395
- }
396
- debugLog("Recreating ", itemsToCreate.length, " monitored items");
397
- createMonitoredItemsAndRespectOperationalLimits(session, createMonitorItemsRequest, (err, response) => {
398
- if (err) {
399
- debugLog("Recreating monitored item has failed with ", err.message);
400
- return innerCallback(err);
401
- }
402
- /* istanbul ignore next */
403
- if (!response) {
404
- return innerCallback(new Error("Internal Error"));
405
- }
406
- const monitoredItemResults = response.results || [];
407
- monitoredItemResults.forEach((monitoredItemResult, index) => {
408
- const itemToCreate = itemsToCreate[index];
409
- /* istanbul ignore next */
410
- if (!itemToCreate || !itemToCreate.requestedParameters) {
411
- throw new Error("Internal Error");
412
- }
413
- const clientHandle = itemToCreate.requestedParameters.clientHandle;
414
- /* istanbul ignore next */
415
- if (!clientHandle) {
416
- throw new Error("Internal Error");
417
- }
418
- const monitoredItem = this.monitoredItems[clientHandle];
419
- if (monitoredItem) {
420
- monitoredItem._applyResult(monitoredItemResult);
421
- }
422
- else {
423
- warningLog("cannot find monitored item for clientHandle !:", clientHandle);
424
- }
425
- });
426
- innerCallback();
427
- });
428
- }
429
- ], (err) => {
430
- if (err) {
431
- warningLog(err.message);
432
- }
433
- callback(err);
434
- });
435
- }
436
- toString() {
437
- let str = "";
438
- str += "subscriptionId : " + this.subscriptionId + "\n";
439
- str += "publishingInterval : " + this.publishingInterval + "\n";
440
- str += "lifetimeCount : " + this.lifetimeCount + "\n";
441
- str += "maxKeepAliveCount : " + this.maxKeepAliveCount + "\n";
442
- str += "hasTimedOut : " + this.hasTimedOut + "\n";
443
- const timeToLive = this.lifetimeCount * this.publishingInterval;
444
- str += "timeToLive : " + timeToLive + "\n";
445
- str += "lastRequestSentTime : " + this.lastRequestSentTime.toString() + "\n";
446
- const duration = Date.now() - this.lastRequestSentTime.getTime();
447
- const extra = duration - timeToLive > 0
448
- ? chalk.red(" expired since " + (duration - timeToLive) / 1000 + " seconds")
449
- : chalk.green(" valid for " + -(duration - timeToLive) / 1000 + " seconds");
450
- str += "timeSinceLast PR : " + duration + "ms" + extra + "\n";
451
- str += "has expired : " + (duration > timeToLive) + "\n";
452
- str += "(session timeout : " + this.session.timeout + " ms)\n";
453
- str += "(maxKeepAliveCount*publishingInterval: " + this.publishingInterval * this.session.timeout + " ms)\n";
454
- return str;
455
- }
456
- /**
457
- * returns the approximated remaining life time of this subscription in milliseconds
458
- */
459
- evaluateRemainingLifetime() {
460
- const now = Date.now();
461
- const timeout = this.publishingInterval * this.lifetimeCount;
462
- const expiryTime = this.lastRequestSentTime.getTime() + timeout;
463
- return Math.max(0, expiryTime - now);
464
- }
465
- _add_monitored_item(clientHandle, monitoredItem) {
466
- (0, node_opcua_assert_1.assert)(this.isActive, "subscription must be active and not terminated");
467
- (0, node_opcua_assert_1.assert)(monitoredItem.monitoringParameters.clientHandle === clientHandle);
468
- this.monitoredItems[clientHandle] = monitoredItem;
469
- /**
470
- * notify the observers that a new monitored item has been added to the subscription.
471
- * @event item_added
472
- * @param the monitored item.
473
- */
474
- this.emit("item_added", monitoredItem);
475
- }
476
- _add_monitored_items_group(monitoredItemGroup) {
477
- this.monitoredItemGroups.push(monitoredItemGroup);
478
- }
479
- _wait_for_subscription_to_be_ready(done) {
480
- let _watchDogCount = 0;
481
- const waitForSubscriptionAndMonitor = () => {
482
- _watchDogCount++;
483
- if (this.subscriptionId === PENDING_SUBSCRIPTION_ID) {
484
- // the subscriptionID is not yet known because the server hasn't replied yet
485
- // let postpone this call, a little bit, to let things happen
486
- setImmediate(waitForSubscriptionAndMonitor);
487
- }
488
- else if (this.subscriptionId === TERMINATED_SUBSCRIPTION_ID) {
489
- // the subscription has been terminated in the meantime
490
- // this indicates a potential issue in the code using this api.
491
- if (typeof done === "function") {
492
- done(new Error("subscription has been deleted"));
493
- }
494
- }
495
- else {
496
- done();
497
- }
498
- };
499
- setImmediate(waitForSubscriptionAndMonitor);
500
- }
501
- __create_subscription(callback) {
502
- (0, node_opcua_assert_1.assert)(typeof callback === "function");
503
- // istanbul ignore next
504
- if (!this.hasSession) {
505
- return callback(new Error("No Session"));
506
- }
507
- const session = this.session;
508
- debugLog(chalk.yellow.bold("ClientSubscription created "));
509
- const request = new node_opcua_service_subscription_1.CreateSubscriptionRequest({
510
- maxNotificationsPerPublish: this.maxNotificationsPerPublish,
511
- priority: this.priority,
512
- publishingEnabled: this.publishingEnabled,
513
- requestedLifetimeCount: this.lifetimeCount,
514
- requestedMaxKeepAliveCount: this.maxKeepAliveCount,
515
- requestedPublishingInterval: this.publishingInterval
516
- });
517
- session.createSubscription(request, (err, response) => {
518
- if (err) {
519
- /* istanbul ignore next */
520
- this.emit("internal_error", err);
521
- if (callback) {
522
- return callback(err);
523
- }
524
- return;
525
- }
526
- /* istanbul ignore next */
527
- if (!response) {
528
- return callback(new Error("internal error"));
529
- }
530
- if (!this.hasSession) {
531
- return callback(new Error("createSubscription has failed = > no session"));
532
- }
533
- (0, node_opcua_assert_1.assert)(this.hasSession);
534
- this.subscriptionId = response.subscriptionId;
535
- this.publishingInterval = response.revisedPublishingInterval;
536
- this.lifetimeCount = response.revisedLifetimeCount;
537
- this.maxKeepAliveCount = response.revisedMaxKeepAliveCount;
538
- this.timeoutHint = (this.maxKeepAliveCount + 10) * this.publishingInterval;
539
- displayKeepAliveWarning(this.session.timeout, this.maxKeepAliveCount, this.publishingInterval);
540
- client_subscription_1.ClientSubscription.ignoreNextWarning = false;
541
- if (doDebug) {
542
- debugLog(chalk.yellow.bold("registering callback"));
543
- debugLog(chalk.yellow.bold("publishingInterval "), this.publishingInterval);
544
- debugLog(chalk.yellow.bold("lifetimeCount "), this.lifetimeCount);
545
- debugLog(chalk.yellow.bold("maxKeepAliveCount "), this.maxKeepAliveCount);
546
- debugLog(chalk.yellow.bold("publish request timeout hint = "), this.timeoutHint);
547
- debugLog(chalk.yellow.bold("hasTimedOut "), this.hasTimedOut);
548
- debugLog(chalk.yellow.bold("timeoutHint for publish request "), this.timeoutHint);
549
- }
550
- this.publishEngine.registerSubscription(this);
551
- if (callback) {
552
- callback();
553
- }
554
- });
555
- }
556
- __on_publish_response_DataChangeNotification(notification) {
557
- (0, node_opcua_assert_1.assert)(notification.schema.name === "DataChangeNotification");
558
- const monitoredItems = notification.monitoredItems || [];
559
- let repeated = 0;
560
- for (const monitoredItem of monitoredItems) {
561
- const monitorItemObj = this.monitoredItems[monitoredItem.clientHandle];
562
- if (monitorItemObj) {
563
- if (monitorItemObj.itemToMonitor.attributeId === node_opcua_data_model_1.AttributeIds.EventNotifier) {
564
- warningLog(chalk.yellow("Warning"), chalk.cyan(" Server send a DataChangeNotification for an EventNotifier." + " EventNotificationList was expected"));
565
- warningLog(chalk.cyan(" the Server may not be fully OPCUA compliant"), chalk.yellow(". This notification will be ignored."));
566
- }
567
- else {
568
- const monitoredItemImpl = monitorItemObj;
569
- monitoredItemImpl._notify_value_change(monitoredItem.value);
570
- }
571
- }
572
- else {
573
- repeated += 1;
574
- if (repeated === 1) {
575
- warningLog("Receiving a notification for a unknown monitoredItem with clientHandle ", monitoredItem.clientHandle);
576
- }
577
- }
578
- }
579
- // istanbul ignore next
580
- if (repeated > 1) {
581
- warningLog("previous message repeated", repeated, "times");
582
- }
583
- }
584
- __on_publish_response_StatusChangeNotification(notification) {
585
- (0, node_opcua_assert_1.assert)(notification.schema.name === "StatusChangeNotification");
586
- debugLog("Client has received a Status Change Notification ", notification.status.toString());
587
- if (notification.status === node_opcua_status_code_1.StatusCodes.GoodSubscriptionTransferred) {
588
- // OPCUA UA Spec 1.0.3 : part 3 - page 82 - 5.13.7 TransferSubscriptions:
589
- // If the Server transfers the Subscription to the new Session, the Server shall issue
590
- // a StatusChangeNotification notificationMessage with the status code
591
- // Good_SubscriptionTransferred to the old Session.
592
- debugLog("ClientSubscription#__on_publish_response_StatusChangeNotification : GoodSubscriptionTransferred");
593
- // may be it has been transferred after a reconnection.... in this case should do nothing about it
594
- }
595
- if (notification.status === node_opcua_status_code_1.StatusCodes.BadTimeout) {
596
- // the server tells use that the subscription has timed out ..
597
- // this mean that this subscription has been closed on the server side and cannot process any
598
- // new PublishRequest.
599
- //
600
- // from Spec OPCUA Version 1.03 Part 4 - 5.13.1.1 Description : Page 69:
601
- //
602
- // h. Subscriptions have a lifetime counter that counts the number of consecutive publishing cycles in
603
- // which there have been no Publish requests available to send a Publish response for the
604
- // Subscription. Any Service call that uses the SubscriptionId or the processing of a Publish
605
- // response resets the lifetime counter of this Subscription. When this counter reaches the value
606
- // calculated for the lifetime of a Subscription based on the MaxKeepAliveCount parameter in the
607
- // CreateSubscription Service (5.13.2), the Subscription is closed. Closing the Subscription causes
608
- // its MonitoredItems to be deleted. In addition the Server shall issue a StatusChangeNotification
609
- // notificationMessage with the status code BadTimeout.
610
- //
611
- this.hasTimedOut = true;
612
- this.terminate(() => {
613
- /* empty */
614
- });
615
- }
616
- /**
617
- * notify the observers that the server has send a status changed notification (such as BadTimeout )
618
- * @event status_changed
619
- */
620
- this.emit("status_changed", notification.status, notification.diagnosticInfo);
621
- }
622
- __on_publish_response_EventNotificationList(notification) {
623
- (0, node_opcua_assert_1.assert)(notification.schema.name === "EventNotificationList");
624
- const events = notification.events || [];
625
- for (const event of events) {
626
- const monitorItemObj = this.monitoredItems[event.clientHandle];
627
- (0, node_opcua_assert_1.assert)(monitorItemObj, "Expecting a monitored item");
628
- const monitoredItemImpl = monitorItemObj;
629
- monitoredItemImpl._notify_event(event.eventFields || []);
630
- }
631
- }
632
- onNotificationMessage(notificationMessage) {
633
- (0, node_opcua_assert_1.assert)(Object.prototype.hasOwnProperty.call(notificationMessage, "sequenceNumber"));
634
- this.lastSequenceNumber = notificationMessage.sequenceNumber;
635
- this.emit("raw_notification", notificationMessage);
636
- const notificationData = (notificationMessage.notificationData || []);
637
- if (notificationData.length === 0) {
638
- // this is a keep alive message
639
- debugLog(chalk.yellow("Client : received a keep alive notification from client"));
640
- /**
641
- * notify the observers that a keep alive Publish Response has been received from the server.
642
- * @event keepalive
643
- */
644
- this.emit("keepalive");
645
- }
646
- else {
647
- /**
648
- * notify the observers that some notifications has been received from the server in a PublishResponse
649
- * each modified monitored Item
650
- * @event received_notifications
651
- */
652
- this.emit("received_notifications", notificationMessage);
653
- // let publish a global event
654
- (0, node_opcua_client_dynamic_extension_object_1.promoteOpaqueStructureInNotificationData)(this.session, notificationData).then(() => {
655
- // now process all notifications
656
- for (const notification of notificationData) {
657
- // istanbul ignore next
658
- if (!notification) {
659
- continue;
660
- }
661
- // DataChangeNotification / StatusChangeNotification / EventNotification
662
- switch (notification.schema.name) {
663
- case "DataChangeNotification":
664
- // now inform each individual monitored item
665
- this.__on_publish_response_DataChangeNotification(notification);
666
- break;
667
- case "StatusChangeNotification":
668
- this.__on_publish_response_StatusChangeNotification(notification);
669
- break;
670
- case "EventNotificationList":
671
- this.__on_publish_response_EventNotificationList(notification);
672
- break;
673
- default:
674
- warningLog(" Invalid notification :", notification.toString());
675
- }
676
- }
677
- });
678
- }
679
- }
680
- _terminate_step2(callback) {
681
- const monitoredItems = Object.values(this.monitoredItems);
682
- for (const monitoredItem of monitoredItems) {
683
- this._remove(monitoredItem);
684
- }
685
- const monitoredItemGroups = this.monitoredItemGroups;
686
- for (const monitoredItemGroup of monitoredItemGroups) {
687
- this._removeGroup(monitoredItemGroup);
688
- }
689
- (0, node_opcua_assert_1.assert)(Object.values(this.monitoredItems).length === 0);
690
- setImmediate(() => {
691
- /**
692
- * notify the observers that the client subscription has terminated
693
- * @event terminated
694
- */
695
- this.subscriptionId = TERMINATED_SUBSCRIPTION_ID;
696
- this.emit("terminated");
697
- callback();
698
- });
699
- }
700
- _remove(monitoredItem) {
701
- const clientHandle = monitoredItem.monitoringParameters.clientHandle;
702
- (0, node_opcua_assert_1.assert)(clientHandle > 0);
703
- if (!Object.prototype.hasOwnProperty.call(this.monitoredItems, clientHandle)) {
704
- return; // may be monitoredItem failed to be created ....
705
- }
706
- (0, node_opcua_assert_1.assert)(Object.prototype.hasOwnProperty.call(this.monitoredItems, clientHandle));
707
- const priv = monitoredItem;
708
- priv._terminate_and_emit();
709
- }
710
- _removeGroup(monitoredItemGroup) {
711
- monitoredItemGroup._terminate_and_emit();
712
- this.monitoredItemGroups = this.monitoredItemGroups.filter((obj) => obj !== monitoredItemGroup);
713
- }
714
- /**
715
- * @private
716
- * @param itemToMonitor
717
- * @param monitoringParameters
718
- * @param timestampsToReturn
719
- */
720
- _createMonitoredItem(itemToMonitor, monitoringParameters, timestampsToReturn, monitoringMode = node_opcua_service_subscription_1.MonitoringMode.Reporting) {
721
- /* istanbul ignore next*/
722
- const monitoredItem = new client_monitored_item_impl_1.ClientMonitoredItemImpl(this, itemToMonitor, monitoringParameters, timestampsToReturn, monitoringMode);
723
- return monitoredItem;
724
- }
725
- }
726
- exports.ClientSubscriptionImpl = ClientSubscriptionImpl;
727
- function ClientMonitoredItem_create(subscription, itemToMonitor, monitoringParameters, timestampsToReturn, monitoringMode = node_opcua_service_subscription_1.MonitoringMode.Reporting, callback) {
728
- const monitoredItem = new client_monitored_item_impl_1.ClientMonitoredItemImpl(subscription, itemToMonitor, monitoringParameters, timestampsToReturn, monitoringMode);
729
- setImmediate(() => {
730
- subscription._wait_for_subscription_to_be_ready((err) => {
731
- if (err) {
732
- if (callback) {
733
- callback(err);
734
- }
735
- return;
736
- }
737
- client_monitored_item_toolbox_1.ClientMonitoredItemToolbox._toolbox_monitor(subscription, timestampsToReturn, [monitoredItem], (err1) => {
738
- if (err1) {
739
- monitoredItem._terminate_and_emit(err1);
740
- }
741
- if (callback) {
742
- callback(err1, monitoredItem);
743
- }
744
- });
745
- });
746
- });
747
- return monitoredItem;
748
- }
749
- exports.ClientMonitoredItem_create = ClientMonitoredItem_create;
750
- // tslint:disable:no-var-requires
751
- // tslint:disable:max-line-length
752
- const thenify = require("thenify");
753
- const opts = { multiArgs: false };
754
- ClientSubscriptionImpl.prototype.setPublishingMode = thenify.withCallback(ClientSubscriptionImpl.prototype.setPublishingMode);
755
- ClientSubscriptionImpl.prototype.monitor = thenify.withCallback(ClientSubscriptionImpl.prototype.monitor);
756
- ClientSubscriptionImpl.prototype.monitorItems = thenify.withCallback(ClientSubscriptionImpl.prototype.monitorItems);
757
- ClientSubscriptionImpl.prototype.setTriggering = thenify.withCallback(ClientSubscriptionImpl.prototype.setTriggering);
758
- ClientSubscriptionImpl.prototype.modify = thenify.withCallback(ClientSubscriptionImpl.prototype.modify);
759
- ClientSubscriptionImpl.prototype.recreateSubscriptionAndMonitoredItem = thenify.withCallback(ClientSubscriptionImpl.prototype.recreateSubscriptionAndMonitoredItem);
760
- ClientSubscriptionImpl.prototype.terminate = thenify.withCallback(ClientSubscriptionImpl.prototype.terminate);
761
- ClientSubscriptionImpl.prototype.getMonitoredItems = thenify.withCallback(ClientSubscriptionImpl.prototype.getMonitoredItems);
762
- client_subscription_1.ClientSubscription.create = (clientSession, options) => {
763
- return new ClientSubscriptionImpl(clientSession, options);
764
- };
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
+ if (response) {
304
+ // use soft error, no exceptions
305
+ return callback(null, response);
306
+ }
307
+ else {
308
+ return callback(err);
309
+ }
310
+ }
311
+ // istanbul ignore next
312
+ if (!response) {
313
+ return callback(new Error("Internal Error"));
314
+ }
315
+ callback(null, response);
316
+ });
317
+ }
318
+ modify(...args) {
319
+ const modifySubscriptionRequest = args[0];
320
+ const callback = args[1];
321
+ const session = this.session;
322
+ if (!session) {
323
+ return callback(new Error("no session"));
324
+ }
325
+ modifySubscriptionRequest.subscriptionId = this.subscriptionId;
326
+ modifySubscriptionRequest.priority =
327
+ modifySubscriptionRequest.priority === undefined ? this.priority : modifySubscriptionRequest.priority;
328
+ modifySubscriptionRequest.requestedLifetimeCount =
329
+ modifySubscriptionRequest.requestedLifetimeCount === undefined
330
+ ? this.lifetimeCount
331
+ : modifySubscriptionRequest.requestedLifetimeCount;
332
+ modifySubscriptionRequest.requestedMaxKeepAliveCount =
333
+ modifySubscriptionRequest.requestedMaxKeepAliveCount === undefined
334
+ ? this.maxKeepAliveCount
335
+ : modifySubscriptionRequest.requestedMaxKeepAliveCount;
336
+ modifySubscriptionRequest.requestedPublishingInterval =
337
+ modifySubscriptionRequest.requestedPublishingInterval === undefined
338
+ ? this.publishingInterval
339
+ : modifySubscriptionRequest.requestedPublishingInterval;
340
+ modifySubscriptionRequest.maxNotificationsPerPublish =
341
+ modifySubscriptionRequest.maxNotificationsPerPublish === undefined
342
+ ? this.maxNotificationsPerPublish
343
+ : modifySubscriptionRequest.maxNotificationsPerPublish;
344
+ session.modifySubscription(modifySubscriptionRequest, (err, response) => {
345
+ if (err || !response) {
346
+ return callback(err);
347
+ }
348
+ this.publishingInterval = response.revisedPublishingInterval;
349
+ this.lifetimeCount = response.revisedLifetimeCount;
350
+ this.maxKeepAliveCount = response.revisedMaxKeepAliveCount;
351
+ callback(null, response);
352
+ });
353
+ }
354
+ getMonitoredItems(...args) {
355
+ this.session.getMonitoredItems(this.subscriptionId, args[0]);
356
+ }
357
+ /**
358
+ * utility function to recreate new subscription
359
+ * @method recreateSubscriptionAndMonitoredItem
360
+ */
361
+ recreateSubscriptionAndMonitoredItem(callback) {
362
+ debugLog("ClientSubscription#recreateSubscriptionAndMonitoredItem");
363
+ if (this.subscriptionId === TERMINATED_SUBSCRIPTION_ID) {
364
+ debugLog("Subscription is not in a valid state");
365
+ return callback();
366
+ }
367
+ const oldMonitoredItems = this.monitoredItems;
368
+ this.publishEngine.unregisterSubscription(this.subscriptionId);
369
+ async.series([
370
+ (innerCallback) => {
371
+ this.__create_subscription(innerCallback);
372
+ },
373
+ (innerCallback) => {
374
+ const test = this.publishEngine.getSubscription(this.subscriptionId);
375
+ debugLog("recreating ", Object.keys(oldMonitoredItems).length, " monitored Items");
376
+ // re-create monitored items
377
+ const itemsToCreate = [];
378
+ for (const monitoredItem of Object.values(oldMonitoredItems)) {
379
+ (0, node_opcua_assert_1.assert)(monitoredItem.monitoringParameters.clientHandle > 0);
380
+ itemsToCreate.push({
381
+ itemToMonitor: monitoredItem.itemToMonitor,
382
+ monitoringMode: monitoredItem.monitoringMode,
383
+ requestedParameters: monitoredItem.monitoringParameters
384
+ });
385
+ }
386
+ const createMonitorItemsRequest = new node_opcua_service_subscription_1.CreateMonitoredItemsRequest({
387
+ itemsToCreate,
388
+ subscriptionId: this.subscriptionId,
389
+ timestampsToReturn: node_opcua_service_read_1.TimestampsToReturn.Both // this.timestampsToReturn,
390
+ });
391
+ const session = this.session;
392
+ // istanbul ignore next
393
+ if (!session) {
394
+ return innerCallback(new Error("no session"));
395
+ }
396
+ debugLog("Recreating ", itemsToCreate.length, " monitored items");
397
+ createMonitoredItemsAndRespectOperationalLimits(session, createMonitorItemsRequest, (err, response) => {
398
+ if (err) {
399
+ debugLog("Recreating monitored item has failed with ", err.message);
400
+ return innerCallback(err);
401
+ }
402
+ /* istanbul ignore next */
403
+ if (!response) {
404
+ return innerCallback(new Error("Internal Error"));
405
+ }
406
+ const monitoredItemResults = response.results || [];
407
+ monitoredItemResults.forEach((monitoredItemResult, index) => {
408
+ const itemToCreate = itemsToCreate[index];
409
+ /* istanbul ignore next */
410
+ if (!itemToCreate || !itemToCreate.requestedParameters) {
411
+ throw new Error("Internal Error");
412
+ }
413
+ const clientHandle = itemToCreate.requestedParameters.clientHandle;
414
+ /* istanbul ignore next */
415
+ if (!clientHandle) {
416
+ throw new Error("Internal Error");
417
+ }
418
+ const monitoredItem = this.monitoredItems[clientHandle];
419
+ if (monitoredItem) {
420
+ monitoredItem._applyResult(monitoredItemResult);
421
+ }
422
+ else {
423
+ warningLog("cannot find monitored item for clientHandle !:", clientHandle);
424
+ }
425
+ });
426
+ innerCallback();
427
+ });
428
+ }
429
+ ], (err) => {
430
+ if (err) {
431
+ warningLog(err.message);
432
+ }
433
+ callback(err);
434
+ });
435
+ }
436
+ toString() {
437
+ let str = "";
438
+ str += "subscriptionId : " + this.subscriptionId + "\n";
439
+ str += "publishingInterval : " + this.publishingInterval + "\n";
440
+ str += "lifetimeCount : " + this.lifetimeCount + "\n";
441
+ str += "maxKeepAliveCount : " + this.maxKeepAliveCount + "\n";
442
+ str += "hasTimedOut : " + this.hasTimedOut + "\n";
443
+ const timeToLive = this.lifetimeCount * this.publishingInterval;
444
+ str += "timeToLive : " + timeToLive + "\n";
445
+ str += "lastRequestSentTime : " + this.lastRequestSentTime.toString() + "\n";
446
+ const duration = Date.now() - this.lastRequestSentTime.getTime();
447
+ const extra = duration - timeToLive > 0
448
+ ? chalk.red(" expired since " + (duration - timeToLive) / 1000 + " seconds")
449
+ : chalk.green(" valid for " + -(duration - timeToLive) / 1000 + " seconds");
450
+ str += "timeSinceLast PR : " + duration + "ms" + extra + "\n";
451
+ str += "has expired : " + (duration > timeToLive) + "\n";
452
+ str += "(session timeout : " + this.session.timeout + " ms)\n";
453
+ str += "(maxKeepAliveCount*publishingInterval: " + this.publishingInterval * this.session.timeout + " ms)\n";
454
+ return str;
455
+ }
456
+ /**
457
+ * returns the approximated remaining life time of this subscription in milliseconds
458
+ */
459
+ evaluateRemainingLifetime() {
460
+ const now = Date.now();
461
+ const timeout = this.publishingInterval * this.lifetimeCount;
462
+ const expiryTime = this.lastRequestSentTime.getTime() + timeout;
463
+ return Math.max(0, expiryTime - now);
464
+ }
465
+ _add_monitored_item(clientHandle, monitoredItem) {
466
+ (0, node_opcua_assert_1.assert)(this.isActive, "subscription must be active and not terminated");
467
+ (0, node_opcua_assert_1.assert)(monitoredItem.monitoringParameters.clientHandle === clientHandle);
468
+ this.monitoredItems[clientHandle] = monitoredItem;
469
+ /**
470
+ * notify the observers that a new monitored item has been added to the subscription.
471
+ * @event item_added
472
+ * @param the monitored item.
473
+ */
474
+ this.emit("item_added", monitoredItem);
475
+ }
476
+ _add_monitored_items_group(monitoredItemGroup) {
477
+ this.monitoredItemGroups.push(monitoredItemGroup);
478
+ }
479
+ _wait_for_subscription_to_be_ready(done) {
480
+ let _watchDogCount = 0;
481
+ const waitForSubscriptionAndMonitor = () => {
482
+ _watchDogCount++;
483
+ if (this.subscriptionId === PENDING_SUBSCRIPTION_ID) {
484
+ // the subscriptionID is not yet known because the server hasn't replied yet
485
+ // let postpone this call, a little bit, to let things happen
486
+ setImmediate(waitForSubscriptionAndMonitor);
487
+ }
488
+ else if (this.subscriptionId === TERMINATED_SUBSCRIPTION_ID) {
489
+ // the subscription has been terminated in the meantime
490
+ // this indicates a potential issue in the code using this api.
491
+ if (typeof done === "function") {
492
+ done(new Error("subscription has been deleted"));
493
+ }
494
+ }
495
+ else {
496
+ done();
497
+ }
498
+ };
499
+ setImmediate(waitForSubscriptionAndMonitor);
500
+ }
501
+ __create_subscription(callback) {
502
+ (0, node_opcua_assert_1.assert)(typeof callback === "function");
503
+ // istanbul ignore next
504
+ if (!this.hasSession) {
505
+ return callback(new Error("No Session"));
506
+ }
507
+ const session = this.session;
508
+ debugLog(chalk.yellow.bold("ClientSubscription created "));
509
+ const request = new node_opcua_service_subscription_1.CreateSubscriptionRequest({
510
+ maxNotificationsPerPublish: this.maxNotificationsPerPublish,
511
+ priority: this.priority,
512
+ publishingEnabled: this.publishingEnabled,
513
+ requestedLifetimeCount: this.lifetimeCount,
514
+ requestedMaxKeepAliveCount: this.maxKeepAliveCount,
515
+ requestedPublishingInterval: this.publishingInterval
516
+ });
517
+ session.createSubscription(request, (err, response) => {
518
+ if (err) {
519
+ /* istanbul ignore next */
520
+ this.emit("internal_error", err);
521
+ if (callback) {
522
+ return callback(err);
523
+ }
524
+ return;
525
+ }
526
+ /* istanbul ignore next */
527
+ if (!response) {
528
+ return callback(new Error("internal error"));
529
+ }
530
+ if (!this.hasSession) {
531
+ return callback(new Error("createSubscription has failed = > no session"));
532
+ }
533
+ (0, node_opcua_assert_1.assert)(this.hasSession);
534
+ this.subscriptionId = response.subscriptionId;
535
+ this.publishingInterval = response.revisedPublishingInterval;
536
+ this.lifetimeCount = response.revisedLifetimeCount;
537
+ this.maxKeepAliveCount = response.revisedMaxKeepAliveCount;
538
+ this.timeoutHint = (this.maxKeepAliveCount + 10) * this.publishingInterval;
539
+ displayKeepAliveWarning(this.session.timeout, this.maxKeepAliveCount, this.publishingInterval);
540
+ client_subscription_1.ClientSubscription.ignoreNextWarning = false;
541
+ if (doDebug) {
542
+ debugLog(chalk.yellow.bold("registering callback"));
543
+ debugLog(chalk.yellow.bold("publishingInterval "), this.publishingInterval);
544
+ debugLog(chalk.yellow.bold("lifetimeCount "), this.lifetimeCount);
545
+ debugLog(chalk.yellow.bold("maxKeepAliveCount "), this.maxKeepAliveCount);
546
+ debugLog(chalk.yellow.bold("publish request timeout hint = "), this.timeoutHint);
547
+ debugLog(chalk.yellow.bold("hasTimedOut "), this.hasTimedOut);
548
+ debugLog(chalk.yellow.bold("timeoutHint for publish request "), this.timeoutHint);
549
+ }
550
+ this.publishEngine.registerSubscription(this);
551
+ if (callback) {
552
+ callback();
553
+ }
554
+ });
555
+ }
556
+ __on_publish_response_DataChangeNotification(notification) {
557
+ (0, node_opcua_assert_1.assert)(notification.schema.name === "DataChangeNotification");
558
+ const monitoredItems = notification.monitoredItems || [];
559
+ let repeated = 0;
560
+ for (const monitoredItem of monitoredItems) {
561
+ const monitorItemObj = this.monitoredItems[monitoredItem.clientHandle];
562
+ if (monitorItemObj) {
563
+ if (monitorItemObj.itemToMonitor.attributeId === node_opcua_data_model_1.AttributeIds.EventNotifier) {
564
+ warningLog(chalk.yellow("Warning"), chalk.cyan(" Server send a DataChangeNotification for an EventNotifier." + " EventNotificationList was expected"));
565
+ warningLog(chalk.cyan(" the Server may not be fully OPCUA compliant"), chalk.yellow(". This notification will be ignored."));
566
+ }
567
+ else {
568
+ const monitoredItemImpl = monitorItemObj;
569
+ monitoredItemImpl._notify_value_change(monitoredItem.value);
570
+ }
571
+ }
572
+ else {
573
+ repeated += 1;
574
+ if (repeated === 1) {
575
+ warningLog("Receiving a notification for a unknown monitoredItem with clientHandle ", monitoredItem.clientHandle);
576
+ }
577
+ }
578
+ }
579
+ // istanbul ignore next
580
+ if (repeated > 1) {
581
+ warningLog("previous message repeated", repeated, "times");
582
+ }
583
+ }
584
+ __on_publish_response_StatusChangeNotification(notification) {
585
+ (0, node_opcua_assert_1.assert)(notification.schema.name === "StatusChangeNotification");
586
+ debugLog("Client has received a Status Change Notification ", notification.status.toString());
587
+ if (notification.status === node_opcua_status_code_1.StatusCodes.GoodSubscriptionTransferred) {
588
+ // OPCUA UA Spec 1.0.3 : part 3 - page 82 - 5.13.7 TransferSubscriptions:
589
+ // If the Server transfers the Subscription to the new Session, the Server shall issue
590
+ // a StatusChangeNotification notificationMessage with the status code
591
+ // Good_SubscriptionTransferred to the old Session.
592
+ debugLog("ClientSubscription#__on_publish_response_StatusChangeNotification : GoodSubscriptionTransferred");
593
+ // may be it has been transferred after a reconnection.... in this case should do nothing about it
594
+ }
595
+ if (notification.status === node_opcua_status_code_1.StatusCodes.BadTimeout) {
596
+ // the server tells use that the subscription has timed out ..
597
+ // this mean that this subscription has been closed on the server side and cannot process any
598
+ // new PublishRequest.
599
+ //
600
+ // from Spec OPCUA Version 1.03 Part 4 - 5.13.1.1 Description : Page 69:
601
+ //
602
+ // h. Subscriptions have a lifetime counter that counts the number of consecutive publishing cycles in
603
+ // which there have been no Publish requests available to send a Publish response for the
604
+ // Subscription. Any Service call that uses the SubscriptionId or the processing of a Publish
605
+ // response resets the lifetime counter of this Subscription. When this counter reaches the value
606
+ // calculated for the lifetime of a Subscription based on the MaxKeepAliveCount parameter in the
607
+ // CreateSubscription Service (5.13.2), the Subscription is closed. Closing the Subscription causes
608
+ // its MonitoredItems to be deleted. In addition the Server shall issue a StatusChangeNotification
609
+ // notificationMessage with the status code BadTimeout.
610
+ //
611
+ this.hasTimedOut = true;
612
+ this.terminate(() => {
613
+ /* empty */
614
+ });
615
+ }
616
+ /**
617
+ * notify the observers that the server has send a status changed notification (such as BadTimeout )
618
+ * @event status_changed
619
+ */
620
+ this.emit("status_changed", notification.status, notification.diagnosticInfo);
621
+ }
622
+ __on_publish_response_EventNotificationList(notification) {
623
+ (0, node_opcua_assert_1.assert)(notification.schema.name === "EventNotificationList");
624
+ const events = notification.events || [];
625
+ for (const event of events) {
626
+ const monitorItemObj = this.monitoredItems[event.clientHandle];
627
+ (0, node_opcua_assert_1.assert)(monitorItemObj, "Expecting a monitored item");
628
+ const monitoredItemImpl = monitorItemObj;
629
+ monitoredItemImpl._notify_event(event.eventFields || []);
630
+ }
631
+ }
632
+ onNotificationMessage(notificationMessage) {
633
+ (0, node_opcua_assert_1.assert)(Object.prototype.hasOwnProperty.call(notificationMessage, "sequenceNumber"));
634
+ this.lastSequenceNumber = notificationMessage.sequenceNumber;
635
+ this.emit("raw_notification", notificationMessage);
636
+ const notificationData = (notificationMessage.notificationData || []);
637
+ if (notificationData.length === 0) {
638
+ // this is a keep alive message
639
+ debugLog(chalk.yellow("Client : received a keep alive notification from client"));
640
+ /**
641
+ * notify the observers that a keep alive Publish Response has been received from the server.
642
+ * @event keepalive
643
+ */
644
+ this.emit("keepalive");
645
+ }
646
+ else {
647
+ /**
648
+ * notify the observers that some notifications has been received from the server in a PublishResponse
649
+ * each modified monitored Item
650
+ * @event received_notifications
651
+ */
652
+ this.emit("received_notifications", notificationMessage);
653
+ // let publish a global event
654
+ (0, node_opcua_client_dynamic_extension_object_1.promoteOpaqueStructureInNotificationData)(this.session, notificationData).then(() => {
655
+ // now process all notifications
656
+ for (const notification of notificationData) {
657
+ // istanbul ignore next
658
+ if (!notification) {
659
+ continue;
660
+ }
661
+ // DataChangeNotification / StatusChangeNotification / EventNotification
662
+ switch (notification.schema.name) {
663
+ case "DataChangeNotification":
664
+ // now inform each individual monitored item
665
+ this.__on_publish_response_DataChangeNotification(notification);
666
+ break;
667
+ case "StatusChangeNotification":
668
+ this.__on_publish_response_StatusChangeNotification(notification);
669
+ break;
670
+ case "EventNotificationList":
671
+ this.__on_publish_response_EventNotificationList(notification);
672
+ break;
673
+ default:
674
+ warningLog(" Invalid notification :", notification.toString());
675
+ }
676
+ }
677
+ });
678
+ }
679
+ }
680
+ _terminate_step2(callback) {
681
+ const monitoredItems = Object.values(this.monitoredItems);
682
+ for (const monitoredItem of monitoredItems) {
683
+ this._remove(monitoredItem);
684
+ }
685
+ const monitoredItemGroups = this.monitoredItemGroups;
686
+ for (const monitoredItemGroup of monitoredItemGroups) {
687
+ this._removeGroup(monitoredItemGroup);
688
+ }
689
+ (0, node_opcua_assert_1.assert)(Object.values(this.monitoredItems).length === 0);
690
+ setImmediate(() => {
691
+ /**
692
+ * notify the observers that the client subscription has terminated
693
+ * @event terminated
694
+ */
695
+ this.subscriptionId = TERMINATED_SUBSCRIPTION_ID;
696
+ this.emit("terminated");
697
+ callback();
698
+ });
699
+ }
700
+ _remove(monitoredItem) {
701
+ const clientHandle = monitoredItem.monitoringParameters.clientHandle;
702
+ (0, node_opcua_assert_1.assert)(clientHandle > 0);
703
+ if (!Object.prototype.hasOwnProperty.call(this.monitoredItems, clientHandle)) {
704
+ return; // may be monitoredItem failed to be created ....
705
+ }
706
+ (0, node_opcua_assert_1.assert)(Object.prototype.hasOwnProperty.call(this.monitoredItems, clientHandle));
707
+ const priv = monitoredItem;
708
+ priv._terminate_and_emit();
709
+ }
710
+ _removeGroup(monitoredItemGroup) {
711
+ monitoredItemGroup._terminate_and_emit();
712
+ this.monitoredItemGroups = this.monitoredItemGroups.filter((obj) => obj !== monitoredItemGroup);
713
+ }
714
+ /**
715
+ * @private
716
+ * @param itemToMonitor
717
+ * @param monitoringParameters
718
+ * @param timestampsToReturn
719
+ */
720
+ _createMonitoredItem(itemToMonitor, monitoringParameters, timestampsToReturn, monitoringMode = node_opcua_service_subscription_1.MonitoringMode.Reporting) {
721
+ /* istanbul ignore next*/
722
+ const monitoredItem = new client_monitored_item_impl_1.ClientMonitoredItemImpl(this, itemToMonitor, monitoringParameters, timestampsToReturn, monitoringMode);
723
+ return monitoredItem;
724
+ }
725
+ }
726
+ exports.ClientSubscriptionImpl = ClientSubscriptionImpl;
727
+ function ClientMonitoredItem_create(subscription, itemToMonitor, monitoringParameters, timestampsToReturn, monitoringMode = node_opcua_service_subscription_1.MonitoringMode.Reporting, callback) {
728
+ const monitoredItem = new client_monitored_item_impl_1.ClientMonitoredItemImpl(subscription, itemToMonitor, monitoringParameters, timestampsToReturn, monitoringMode);
729
+ setImmediate(() => {
730
+ subscription._wait_for_subscription_to_be_ready((err) => {
731
+ if (err) {
732
+ if (callback) {
733
+ callback(err);
734
+ }
735
+ return;
736
+ }
737
+ client_monitored_item_toolbox_1.ClientMonitoredItemToolbox._toolbox_monitor(subscription, timestampsToReturn, [monitoredItem], (err1) => {
738
+ if (err1) {
739
+ monitoredItem._terminate_and_emit(err1);
740
+ }
741
+ if (callback) {
742
+ callback(err1, monitoredItem);
743
+ }
744
+ });
745
+ });
746
+ });
747
+ return monitoredItem;
748
+ }
749
+ exports.ClientMonitoredItem_create = ClientMonitoredItem_create;
750
+ // tslint:disable:no-var-requires
751
+ // tslint:disable:max-line-length
752
+ const thenify = require("thenify");
753
+ const opts = { multiArgs: false };
754
+ ClientSubscriptionImpl.prototype.setPublishingMode = thenify.withCallback(ClientSubscriptionImpl.prototype.setPublishingMode);
755
+ ClientSubscriptionImpl.prototype.monitor = thenify.withCallback(ClientSubscriptionImpl.prototype.monitor);
756
+ ClientSubscriptionImpl.prototype.monitorItems = thenify.withCallback(ClientSubscriptionImpl.prototype.monitorItems);
757
+ ClientSubscriptionImpl.prototype.setTriggering = thenify.withCallback(ClientSubscriptionImpl.prototype.setTriggering);
758
+ ClientSubscriptionImpl.prototype.modify = thenify.withCallback(ClientSubscriptionImpl.prototype.modify);
759
+ ClientSubscriptionImpl.prototype.recreateSubscriptionAndMonitoredItem = thenify.withCallback(ClientSubscriptionImpl.prototype.recreateSubscriptionAndMonitoredItem);
760
+ ClientSubscriptionImpl.prototype.terminate = thenify.withCallback(ClientSubscriptionImpl.prototype.terminate);
761
+ ClientSubscriptionImpl.prototype.getMonitoredItems = thenify.withCallback(ClientSubscriptionImpl.prototype.getMonitoredItems);
762
+ client_subscription_1.ClientSubscription.create = (clientSession, options) => {
763
+ return new ClientSubscriptionImpl(clientSession, options);
764
+ };
765
765
  //# sourceMappingURL=client_subscription_impl.js.map