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