node-opcua-client 2.64.1 → 2.65.0

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