node-opcua-client 2.177.0 → 2.179.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.
- package/dist/alarms_and_conditions/client_alarm_tools.js +7 -5
- package/dist/alarms_and_conditions/client_alarm_tools.js.map +1 -1
- package/dist/alarms_and_conditions/client_tools.js +38 -28
- package/dist/alarms_and_conditions/client_tools.js.map +1 -1
- package/dist/client_base.d.ts +5 -0
- package/dist/client_base.js.map +1 -1
- package/dist/client_monitored_item.d.ts +1 -1
- package/dist/client_monitored_item.js +4 -2
- package/dist/client_monitored_item.js.map +1 -1
- package/dist/client_monitored_item_group.d.ts +4 -3
- package/dist/client_monitored_item_group.js +8 -5
- package/dist/client_monitored_item_group.js.map +1 -1
- package/dist/client_monitored_item_toolbox.js +4 -2
- package/dist/client_monitored_item_toolbox.js.map +1 -1
- package/dist/client_session.d.ts +9 -2
- package/dist/client_session_keepalive_manager.d.ts +1 -1
- package/dist/client_session_keepalive_manager.js +50 -29
- package/dist/client_session_keepalive_manager.js.map +1 -1
- package/dist/client_subscription.d.ts +2 -2
- package/dist/client_subscription.js +3 -1
- package/dist/client_subscription.js.map +1 -1
- package/dist/common.d.ts +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/opcua_client.js +1 -0
- package/dist/opcua_client.js.map +1 -1
- package/dist/private/client_base_impl.js +178 -77
- package/dist/private/client_base_impl.js.map +1 -1
- package/dist/private/client_monitored_item_group_impl.d.ts +1 -0
- package/dist/private/client_monitored_item_group_impl.js +6 -8
- package/dist/private/client_monitored_item_group_impl.js.map +1 -1
- package/dist/private/client_monitored_item_impl.js +0 -4
- package/dist/private/client_monitored_item_impl.js.map +1 -1
- package/dist/private/client_publish_engine.js +62 -28
- package/dist/private/client_publish_engine.js.map +1 -1
- package/dist/private/client_session_impl.d.ts +49 -17
- package/dist/private/client_session_impl.js +240 -143
- package/dist/private/client_session_impl.js.map +1 -1
- package/dist/private/client_subscription_impl.js +15 -12
- package/dist/private/client_subscription_impl.js.map +1 -1
- package/dist/private/i_private_client.d.ts +1 -1
- package/dist/private/opcua_client_impl.js +44 -9
- package/dist/private/opcua_client_impl.js.map +1 -1
- package/dist/private/reconnection/client_publish_engine_reconnection.js +17 -7
- package/dist/private/reconnection/client_publish_engine_reconnection.js.map +1 -1
- package/dist/private/reconnection/client_subscription_reconnection.js +11 -7
- package/dist/private/reconnection/client_subscription_reconnection.js.map +1 -1
- package/dist/private/reconnection/reconnection.js +31 -14
- package/dist/private/reconnection/reconnection.js.map +1 -1
- package/dist/reverse/client_reverse_connect.js.map +1 -1
- package/dist/tools/findservers.js.map +1 -1
- package/dist/tools/read_history_server_capabilities.d.ts +2 -1
- package/dist/tools/read_history_server_capabilities.js +6 -3
- package/dist/tools/read_history_server_capabilities.js.map +1 -1
- package/package.json +50 -50
- package/source/alarms_and_conditions/client_alarm_tools.ts +10 -8
- package/source/alarms_and_conditions/client_tools.ts +71 -30
- package/source/client_base.ts +5 -1
- package/source/client_monitored_item.ts +10 -9
- package/source/client_monitored_item_base.ts +2 -8
- package/source/client_monitored_item_group.ts +13 -10
- package/source/client_monitored_item_toolbox.ts +4 -2
- package/source/client_session.ts +10 -3
- package/source/client_session_keepalive_manager.ts +72 -55
- package/source/client_subscription.ts +6 -3
- package/source/common.ts +4 -0
- package/source/index.ts +1 -1
- package/source/opcua_client.ts +1 -0
- package/source/private/client_base_impl.ts +244 -113
- package/source/private/client_monitored_item_group_impl.ts +17 -18
- package/source/private/client_monitored_item_impl.ts +0 -4
- package/source/private/client_publish_engine.ts +78 -40
- package/source/private/client_session_impl.ts +393 -236
- package/source/private/client_subscription_impl.ts +20 -25
- package/source/private/i_private_client.ts +1 -1
- package/source/private/opcua_client_impl.ts +51 -9
- package/source/private/reconnection/client_publish_engine_reconnection.ts +22 -21
- package/source/private/reconnection/client_subscription_reconnection.ts +12 -8
- package/source/private/reconnection/reconnection.ts +35 -18
- package/source/reverse/client_reverse_connect.ts +11 -3
- package/source/tools/findservers.ts +0 -1
- package/source/tools/read_history_server_capabilities.ts +9 -7
|
@@ -7,8 +7,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
7
7
|
};
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.ClientSessionImpl = void 0;
|
|
10
|
+
const node_events_1 = require("node:events");
|
|
10
11
|
const chalk_1 = __importDefault(require("chalk"));
|
|
11
|
-
const events_1 = require("events");
|
|
12
12
|
const node_opcua_assert_1 = require("node-opcua-assert");
|
|
13
13
|
const node_opcua_client_dynamic_extension_object_1 = require("node-opcua-client-dynamic-extension-object");
|
|
14
14
|
const node_opcua_data_model_1 = require("node-opcua-data-model");
|
|
@@ -34,11 +34,11 @@ const client_session_keepalive_manager_1 = require("../client_session_keepalive_
|
|
|
34
34
|
const client_publish_engine_1 = require("./client_publish_engine");
|
|
35
35
|
const client_subscription_impl_1 = require("./client_subscription_impl");
|
|
36
36
|
const reconnection_1 = require("./reconnection/reconnection");
|
|
37
|
-
const helpAPIChange = process.env.DEBUG
|
|
37
|
+
const helpAPIChange = process.env.DEBUG?.match(/API/);
|
|
38
38
|
const debugLog = (0, node_opcua_debug_1.make_debugLog)(__filename);
|
|
39
39
|
const doDebug = (0, node_opcua_debug_1.checkDebugFlag)(__filename);
|
|
40
40
|
const warningLog = (0, node_opcua_debug_1.make_warningLog)(__filename);
|
|
41
|
-
const
|
|
41
|
+
const _errorLog = (0, node_opcua_debug_1.make_errorLog)(__filename);
|
|
42
42
|
let pendingTransactionMessageDisplayed = false;
|
|
43
43
|
function coerceBrowseDescription(data) {
|
|
44
44
|
if (typeof data === "string" || data instanceof node_opcua_nodeid_1.NodeId) {
|
|
@@ -52,9 +52,10 @@ function coerceBrowseDescription(data) {
|
|
|
52
52
|
});
|
|
53
53
|
}
|
|
54
54
|
else {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
const options = data;
|
|
56
|
+
options.nodeId = (0, node_opcua_nodeid_1.resolveNodeId)(options.nodeId);
|
|
57
|
+
options.referenceTypeId = options.referenceTypeId ? (0, node_opcua_nodeid_1.resolveNodeId)(options.referenceTypeId) : null;
|
|
58
|
+
return new node_opcua_service_browse_1.BrowseDescription(options);
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
61
|
function coerceReadValueId(node) {
|
|
@@ -72,10 +73,30 @@ function coerceReadValueId(node) {
|
|
|
72
73
|
}
|
|
73
74
|
}
|
|
74
75
|
const emptyUint32Array = new Uint32Array(0);
|
|
76
|
+
/**
|
|
77
|
+
* attach the server side diagnostics to an error, so that a caller can inspect them without
|
|
78
|
+
* having to know how the channel delivered the failure.
|
|
79
|
+
*
|
|
80
|
+
* For a ServiceFault there is no `response` argument at all - the channel moved the decoded
|
|
81
|
+
* fault onto `err.response` - so fall back to it, otherwise the diagnostics of the most
|
|
82
|
+
* interesting case would always be dropped.
|
|
83
|
+
*/
|
|
84
|
+
function annotateWithDiagnostics(err, response) {
|
|
85
|
+
const annotatedError = err;
|
|
86
|
+
const source = response ?? annotatedError.response;
|
|
87
|
+
if (source?.responseHeader.serviceDiagnostics) {
|
|
88
|
+
annotatedError.serviceDiagnostics = source.responseHeader.serviceDiagnostics;
|
|
89
|
+
}
|
|
90
|
+
const responseWithDiagnosticInfos = source;
|
|
91
|
+
if (responseWithDiagnosticInfos?.diagnosticInfos) {
|
|
92
|
+
annotatedError.diagnosticsInfo = responseWithDiagnosticInfos.diagnosticInfos;
|
|
93
|
+
}
|
|
94
|
+
return annotatedError;
|
|
95
|
+
}
|
|
75
96
|
/**
|
|
76
97
|
* @class ClientSession
|
|
77
98
|
*/
|
|
78
|
-
class ClientSessionImpl extends
|
|
99
|
+
class ClientSessionImpl extends node_events_1.EventEmitter {
|
|
79
100
|
static reconnectingElement = new WeakMap();
|
|
80
101
|
timeout;
|
|
81
102
|
authenticationToken;
|
|
@@ -120,6 +141,9 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
120
141
|
this.timeout = 0;
|
|
121
142
|
}
|
|
122
143
|
getTransportSettings() {
|
|
144
|
+
if (!this._client) {
|
|
145
|
+
throw new Error("session has been closed - no transport settings available");
|
|
146
|
+
}
|
|
123
147
|
return this._client.getTransportSettings();
|
|
124
148
|
}
|
|
125
149
|
/**
|
|
@@ -128,6 +152,9 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
128
152
|
* @type {EndpointDescription}
|
|
129
153
|
*/
|
|
130
154
|
get endpoint() {
|
|
155
|
+
if (!this._client?.endpoint) {
|
|
156
|
+
throw new Error("session has been closed - no endpoint available");
|
|
157
|
+
}
|
|
131
158
|
return this._client.endpoint;
|
|
132
159
|
}
|
|
133
160
|
get subscriptionCount() {
|
|
@@ -163,18 +190,19 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
163
190
|
};
|
|
164
191
|
if (!this._client || !this.userIdentityInfo) {
|
|
165
192
|
warningLog("changeUser: invalid session");
|
|
166
|
-
return callback(null, node_opcua_status_code_1.StatusCodes.BadInternalError);
|
|
193
|
+
return callback?.(null, node_opcua_status_code_1.StatusCodes.BadInternalError);
|
|
167
194
|
}
|
|
168
195
|
const old_userIdentity = this.userIdentityInfo;
|
|
169
|
-
this._client._activateSession(this, userIdentityInfo, (err1,
|
|
196
|
+
this._client._activateSession(this, userIdentityInfo, (err1, _session2) => {
|
|
170
197
|
if (err1) {
|
|
171
198
|
this.userIdentityInfo = old_userIdentity;
|
|
172
199
|
warningLog("activate session error = ", err1.message);
|
|
173
|
-
return callback(null, node_opcua_status_code_1.StatusCodes.BadUserAccessDenied);
|
|
200
|
+
return callback?.(null, node_opcua_status_code_1.StatusCodes.BadUserAccessDenied);
|
|
174
201
|
}
|
|
175
202
|
this.userIdentityInfo = userIdentityInfo;
|
|
176
|
-
callback(null, node_opcua_status_code_1.StatusCodes.Good);
|
|
203
|
+
callback?.(null, node_opcua_status_code_1.StatusCodes.Good);
|
|
177
204
|
});
|
|
205
|
+
return undefined;
|
|
178
206
|
}
|
|
179
207
|
/**
|
|
180
208
|
* @internal
|
|
@@ -185,13 +213,13 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
185
213
|
const isArray = Array.isArray(arg0);
|
|
186
214
|
const callback = args[1];
|
|
187
215
|
(0, node_opcua_assert_1.assert)(typeof callback === "function");
|
|
188
|
-
(0, node_opcua_assert_1.assert)(isFinite(this.requestedMaxReferencesPerNode));
|
|
216
|
+
(0, node_opcua_assert_1.assert)(Number.isFinite(this.requestedMaxReferencesPerNode));
|
|
189
217
|
const nodesToBrowse = (isArray ? arg0 : [arg0]).map(coerceBrowseDescription);
|
|
190
218
|
const request = new node_opcua_service_browse_1.BrowseRequest({
|
|
191
219
|
nodesToBrowse,
|
|
192
220
|
requestedMaxReferencesPerNode: this.requestedMaxReferencesPerNode
|
|
193
221
|
});
|
|
194
|
-
this.performMessageTransaction(request, (err, response) => {
|
|
222
|
+
return this.performMessageTransaction(request, (err, response) => {
|
|
195
223
|
if (err) {
|
|
196
224
|
return callback(err);
|
|
197
225
|
}
|
|
@@ -208,8 +236,8 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
208
236
|
warningLog(chalk_1.default.yellow("warning") +
|
|
209
237
|
" BrowseResponse : the server didn't take into" +
|
|
210
238
|
" account our requestedMaxReferencesPerNode ");
|
|
211
|
-
warningLog(
|
|
212
|
-
warningLog(
|
|
239
|
+
warningLog(` this.requestedMaxReferencesPerNode= ${this.requestedMaxReferencesPerNode}`);
|
|
240
|
+
warningLog(` got ${r.references.length}for ${nodesToBrowse[i].nodeId.toString()}`);
|
|
213
241
|
warningLog(" continuationPoint ", r.continuationPoint);
|
|
214
242
|
}
|
|
215
243
|
}
|
|
@@ -232,7 +260,7 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
232
260
|
continuationPoints,
|
|
233
261
|
releaseContinuationPoints
|
|
234
262
|
});
|
|
235
|
-
this.performMessageTransaction(request, (err, response) => {
|
|
263
|
+
return this.performMessageTransaction(request, (err, response) => {
|
|
236
264
|
/* c8 ignore next */
|
|
237
265
|
if (err) {
|
|
238
266
|
return callback(err);
|
|
@@ -263,7 +291,7 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
263
291
|
nodesToRead,
|
|
264
292
|
timestampsToReturn: node_opcua_service_read_1.TimestampsToReturn.Neither
|
|
265
293
|
});
|
|
266
|
-
this.performMessageTransaction(request, (err, response) => {
|
|
294
|
+
return this.performMessageTransaction(request, (err, response) => {
|
|
267
295
|
/* c8 ignore next */
|
|
268
296
|
if (err) {
|
|
269
297
|
return callback(err);
|
|
@@ -294,9 +322,10 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
294
322
|
callback = args[4];
|
|
295
323
|
}
|
|
296
324
|
(0, node_opcua_assert_1.assert)(typeof callback === "function");
|
|
325
|
+
const cb = callback;
|
|
297
326
|
// adjust parameters
|
|
298
327
|
options.numValuesPerNode = options.numValuesPerNode || 0;
|
|
299
|
-
options.returnBounds = options.returnBounds || options.returnBounds === undefined
|
|
328
|
+
options.returnBounds = !!(options.returnBounds || options.returnBounds === undefined);
|
|
300
329
|
options.isReadModified = options.isReadModified || false;
|
|
301
330
|
options.timestampsToReturn = options.timestampsToReturn ?? node_opcua_service_read_1.TimestampsToReturn.Both;
|
|
302
331
|
const arg0 = args[0];
|
|
@@ -331,18 +360,18 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
331
360
|
});
|
|
332
361
|
request.nodesToRead = request.nodesToRead || [];
|
|
333
362
|
(0, node_opcua_assert_1.assert)(nodes.length === request.nodesToRead.length);
|
|
334
|
-
this.historyRead(request, (err, response) => {
|
|
363
|
+
return this.historyRead(request, (err, response) => {
|
|
335
364
|
/* c8 ignore next */
|
|
336
365
|
if (err) {
|
|
337
|
-
return
|
|
366
|
+
return cb(err);
|
|
338
367
|
}
|
|
339
368
|
/* c8 ignore next */
|
|
340
369
|
if (!response || !(response instanceof node_opcua_service_history_1.HistoryReadResponse)) {
|
|
341
|
-
return
|
|
370
|
+
return cb(new Error("Internal Error"));
|
|
342
371
|
}
|
|
343
372
|
response.results = response.results || [];
|
|
344
373
|
(0, node_opcua_assert_1.assert)(nodes.length === response.results.length);
|
|
345
|
-
|
|
374
|
+
cb(null, isArray ? response.results : response.results[0]);
|
|
346
375
|
});
|
|
347
376
|
}
|
|
348
377
|
historyRead(request, callback) {
|
|
@@ -350,7 +379,7 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
350
379
|
if (!callback) {
|
|
351
380
|
throw new Error("expecting a callback");
|
|
352
381
|
}
|
|
353
|
-
this.performMessageTransaction(request, (err, response) => {
|
|
382
|
+
return this.performMessageTransaction(request, (err, response) => {
|
|
354
383
|
/* c8 ignore next */
|
|
355
384
|
if (err) {
|
|
356
385
|
return callback(err);
|
|
@@ -379,7 +408,7 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
379
408
|
});
|
|
380
409
|
}
|
|
381
410
|
readAggregateValue(arg0, startTime, endTime, aggregateFn, processingInterval, ...args) {
|
|
382
|
-
const callback = typeof args[0] === "function" ? args[0] : args[1];
|
|
411
|
+
const callback = (typeof args[0] === "function" ? args[0] : args[1]);
|
|
383
412
|
(0, node_opcua_assert_1.assert)(typeof callback === "function");
|
|
384
413
|
const defaultAggregateFunction = {
|
|
385
414
|
percentDataBad: 100,
|
|
@@ -388,7 +417,7 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
388
417
|
useServerCapabilitiesDefaults: true,
|
|
389
418
|
useSlopedExtrapolation: false
|
|
390
419
|
};
|
|
391
|
-
const aggregateConfiguration = typeof args[0] === "function" ? defaultAggregateFunction : args[0];
|
|
420
|
+
const aggregateConfiguration = (typeof args[0] === "function" ? defaultAggregateFunction : args[0]);
|
|
392
421
|
const isArray = Array.isArray(arg0);
|
|
393
422
|
const nodesToRead = isArray
|
|
394
423
|
? arg0
|
|
@@ -410,8 +439,8 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
410
439
|
releaseContinuationPoints: false,
|
|
411
440
|
timestampsToReturn: node_opcua_service_read_1.TimestampsToReturn.Both
|
|
412
441
|
});
|
|
413
|
-
(0, node_opcua_assert_1.assert)(nodesToRead.length === request.nodesToRead
|
|
414
|
-
this.performMessageTransaction(request, (err, response) => {
|
|
442
|
+
(0, node_opcua_assert_1.assert)(nodesToRead.length === request.nodesToRead?.length);
|
|
443
|
+
return this.performMessageTransaction(request, (err, response) => {
|
|
415
444
|
/* c8 ignore next */
|
|
416
445
|
if (err) {
|
|
417
446
|
return callback(err);
|
|
@@ -439,7 +468,7 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
439
468
|
const callback = args[1];
|
|
440
469
|
(0, node_opcua_assert_1.assert)(typeof callback === "function");
|
|
441
470
|
const request = new node_opcua_service_write_1.WriteRequest({ nodesToWrite });
|
|
442
|
-
this.performMessageTransaction(request, (err, response) => {
|
|
471
|
+
return this.performMessageTransaction(request, (err, response) => {
|
|
443
472
|
/* c8 ignore next */
|
|
444
473
|
if (err) {
|
|
445
474
|
return callback(err, response);
|
|
@@ -468,7 +497,7 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
468
497
|
nodeId: this.resolveNodeId(nodeId),
|
|
469
498
|
value: new node_opcua_data_value_1.DataValue({ value })
|
|
470
499
|
});
|
|
471
|
-
this.write(nodeToWrite, (err, statusCode) => {
|
|
500
|
+
return this.write(nodeToWrite, (err, statusCode) => {
|
|
472
501
|
/* c8 ignore next */
|
|
473
502
|
if (err) {
|
|
474
503
|
return callback(err);
|
|
@@ -502,7 +531,8 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
502
531
|
/* c8 ignore next */
|
|
503
532
|
if (helpAPIChange) {
|
|
504
533
|
// the read method deprecation detection and warning
|
|
505
|
-
if (!((0, node_opcua_utils_1.getFunctionParameterNames)(callback)[1] === "dataValues" ||
|
|
534
|
+
if (!((0, node_opcua_utils_1.getFunctionParameterNames)(callback)[1] === "dataValues" ||
|
|
535
|
+
(0, node_opcua_utils_1.getFunctionParameterNames)(callback)[1] === "dataValue")) {
|
|
506
536
|
warningLog(chalk_1.default.red("[NODE-OPCUA-E04] the ClientSession#read API has changed !!, please fix the client code"));
|
|
507
537
|
warningLog(chalk_1.default.red(" replace ..:"));
|
|
508
538
|
warningLog(chalk_1.default.cyan(" session.read(nodesToRead,function(err,nodesToRead,results) {}"));
|
|
@@ -510,21 +540,23 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
510
540
|
warningLog(chalk_1.default.cyan(" session.read(nodesToRead,function(err,dataValues) {}"));
|
|
511
541
|
warningLog("");
|
|
512
542
|
warningLog(chalk_1.default.yellow("please make sure to refactor your code and check that " +
|
|
513
|
-
"the second argument of your callback function is named"), chalk_1.default.cyan(
|
|
543
|
+
"the second argument of your callback function is named"), chalk_1.default.cyan(`dataValue${isArray ? "s" : ""}`));
|
|
514
544
|
warningLog(chalk_1.default.cyan("to make this exception disappear"));
|
|
515
545
|
throw new Error("ERROR ClientSession#read API has changed !!, please fix the client code");
|
|
516
546
|
}
|
|
517
547
|
}
|
|
518
548
|
// coerce nodeIds
|
|
519
549
|
for (const node of nodesToRead) {
|
|
520
|
-
|
|
550
|
+
if (node.nodeId) {
|
|
551
|
+
node.nodeId = this.resolveNodeId(node.nodeId);
|
|
552
|
+
}
|
|
521
553
|
}
|
|
522
554
|
const request = new node_opcua_service_read_1.ReadRequest({
|
|
523
555
|
maxAge,
|
|
524
556
|
nodesToRead,
|
|
525
557
|
timestampsToReturn: node_opcua_service_read_1.TimestampsToReturn.Both
|
|
526
558
|
});
|
|
527
|
-
this.performMessageTransaction(request, (err, response) => {
|
|
559
|
+
return this.performMessageTransaction(request, (err, response) => {
|
|
528
560
|
/* c8 ignore next */
|
|
529
561
|
if (err) {
|
|
530
562
|
return callback(err, response);
|
|
@@ -534,7 +566,7 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
534
566
|
return callback(new Error("Internal Error"));
|
|
535
567
|
}
|
|
536
568
|
// perform ExtensionObject resolution
|
|
537
|
-
(0, node_opcua_client_dynamic_extension_object_1.promoteOpaqueStructure)(this, response.results)
|
|
569
|
+
(0, node_opcua_client_dynamic_extension_object_1.promoteOpaqueStructure)(this, response.results || [])
|
|
538
570
|
.then(() => {
|
|
539
571
|
response.results = response.results || /* c8 ignore next */ [];
|
|
540
572
|
callback(null, isArray ? response.results : response.results[0]);
|
|
@@ -546,19 +578,19 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
546
578
|
}
|
|
547
579
|
emitCloseEvent(statusCode) {
|
|
548
580
|
if (!this._closeEventHasBeenEmitted) {
|
|
549
|
-
|
|
581
|
+
// c8 ignore next
|
|
582
|
+
doDebug && debugLog("ClientSession#emitCloseEvent");
|
|
550
583
|
this._closeEventHasBeenEmitted = true;
|
|
551
584
|
this.emit("session_closed", statusCode);
|
|
552
585
|
}
|
|
553
586
|
}
|
|
554
587
|
createSubscription(options, callback) {
|
|
555
|
-
this._defaultRequest(node_opcua_service_subscription_1.CreateSubscriptionRequest, node_opcua_service_subscription_1.CreateSubscriptionResponse, options, callback);
|
|
588
|
+
return this._defaultRequest(node_opcua_service_subscription_1.CreateSubscriptionRequest, node_opcua_service_subscription_1.CreateSubscriptionResponse, options, callback);
|
|
556
589
|
}
|
|
557
590
|
createSubscription2(...args) {
|
|
558
591
|
const createSubscriptionRequest = args[0];
|
|
559
592
|
let callback = args[1];
|
|
560
593
|
const subscription = new client_subscription_impl_1.ClientSubscriptionImpl(this, createSubscriptionRequest);
|
|
561
|
-
// tslint:disable-next-line:no-empty
|
|
562
594
|
subscription.on("error", (err) => {
|
|
563
595
|
if (callback) {
|
|
564
596
|
callback(err);
|
|
@@ -572,32 +604,33 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
572
604
|
callback = null;
|
|
573
605
|
}
|
|
574
606
|
});
|
|
607
|
+
return undefined;
|
|
575
608
|
}
|
|
576
609
|
deleteSubscriptions(options, callback) {
|
|
577
|
-
this._defaultRequest(node_opcua_service_subscription_1.DeleteSubscriptionsRequest, node_opcua_service_subscription_1.DeleteSubscriptionsResponse, options, callback);
|
|
610
|
+
return this._defaultRequest(node_opcua_service_subscription_1.DeleteSubscriptionsRequest, node_opcua_service_subscription_1.DeleteSubscriptionsResponse, options, callback);
|
|
578
611
|
}
|
|
579
612
|
setTriggering(request, callback) {
|
|
580
|
-
this._defaultRequest(node_opcua_service_subscription_1.SetTriggeringRequest, node_opcua_service_subscription_1.SetTriggeringResponse, request, callback);
|
|
613
|
+
return this._defaultRequest(node_opcua_service_subscription_1.SetTriggeringRequest, node_opcua_service_subscription_1.SetTriggeringResponse, request, callback);
|
|
581
614
|
}
|
|
582
615
|
/**
|
|
583
616
|
*/
|
|
584
617
|
transferSubscriptions(options, callback) {
|
|
585
|
-
this._defaultRequest(node_opcua_service_subscription_1.TransferSubscriptionsRequest, node_opcua_service_subscription_1.TransferSubscriptionsResponse, options, callback);
|
|
618
|
+
return this._defaultRequest(node_opcua_service_subscription_1.TransferSubscriptionsRequest, node_opcua_service_subscription_1.TransferSubscriptionsResponse, options, callback);
|
|
586
619
|
}
|
|
587
620
|
createMonitoredItems(options, callback) {
|
|
588
|
-
this._defaultRequest(node_opcua_service_subscription_1.CreateMonitoredItemsRequest, node_opcua_service_subscription_1.CreateMonitoredItemsResponse, options, callback);
|
|
621
|
+
return this._defaultRequest(node_opcua_service_subscription_1.CreateMonitoredItemsRequest, node_opcua_service_subscription_1.CreateMonitoredItemsResponse, options, callback);
|
|
589
622
|
}
|
|
590
623
|
modifyMonitoredItems(options, callback) {
|
|
591
|
-
this._defaultRequest(node_opcua_service_subscription_1.ModifyMonitoredItemsRequest, node_opcua_service_subscription_1.ModifyMonitoredItemsResponse, options, callback);
|
|
624
|
+
return this._defaultRequest(node_opcua_service_subscription_1.ModifyMonitoredItemsRequest, node_opcua_service_subscription_1.ModifyMonitoredItemsResponse, options, callback);
|
|
592
625
|
}
|
|
593
626
|
/**
|
|
594
627
|
*
|
|
595
628
|
*/
|
|
596
629
|
modifySubscription(options, callback) {
|
|
597
|
-
this._defaultRequest(node_opcua_service_subscription_1.ModifySubscriptionRequest, node_opcua_service_subscription_1.ModifySubscriptionResponse, options, callback);
|
|
630
|
+
return this._defaultRequest(node_opcua_service_subscription_1.ModifySubscriptionRequest, node_opcua_service_subscription_1.ModifySubscriptionResponse, options, callback);
|
|
598
631
|
}
|
|
599
632
|
setMonitoringMode(options, callback) {
|
|
600
|
-
this._defaultRequest(node_opcua_service_subscription_1.SetMonitoringModeRequest, node_opcua_service_subscription_1.SetMonitoringModeResponse, options, callback);
|
|
633
|
+
return this._defaultRequest(node_opcua_service_subscription_1.SetMonitoringModeRequest, node_opcua_service_subscription_1.SetMonitoringModeResponse, options, callback);
|
|
601
634
|
}
|
|
602
635
|
/**
|
|
603
636
|
*/
|
|
@@ -630,7 +663,7 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
630
663
|
publishingEnabled,
|
|
631
664
|
subscriptionIds
|
|
632
665
|
});
|
|
633
|
-
this._defaultRequest(node_opcua_service_subscription_1.SetPublishingModeRequest, node_opcua_service_subscription_1.SetPublishingModeResponse, options, (err, response) => {
|
|
666
|
+
return this._defaultRequest(node_opcua_service_subscription_1.SetPublishingModeRequest, node_opcua_service_subscription_1.SetPublishingModeResponse, options, (err, response) => {
|
|
634
667
|
/* c8 ignore next */
|
|
635
668
|
if (err) {
|
|
636
669
|
return callback(err);
|
|
@@ -653,7 +686,7 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
653
686
|
const callback = args[1];
|
|
654
687
|
(0, node_opcua_assert_1.assert)(typeof callback === "function");
|
|
655
688
|
const request = new node_opcua_service_translate_browse_path_1.TranslateBrowsePathsToNodeIdsRequest({ browsePaths });
|
|
656
|
-
this.performMessageTransaction(request, (err, response) => {
|
|
689
|
+
return this.performMessageTransaction(request, (err, response) => {
|
|
657
690
|
/* c8 ignore next */
|
|
658
691
|
if (err) {
|
|
659
692
|
return callback(err, response);
|
|
@@ -667,28 +700,36 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
667
700
|
});
|
|
668
701
|
}
|
|
669
702
|
channelId() {
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
: -1;
|
|
703
|
+
const secureChannel = this._client?._secureChannel;
|
|
704
|
+
return secureChannel?.isOpened() ? secureChannel.channelId : -1;
|
|
673
705
|
}
|
|
674
706
|
isChannelValid() {
|
|
675
707
|
/* c8 ignore next */
|
|
676
708
|
if (!this._client) {
|
|
677
|
-
|
|
709
|
+
// c8 ignore next
|
|
710
|
+
doDebug && debugLog(chalk_1.default.red("Warning SessionClient is null ?"));
|
|
678
711
|
}
|
|
679
|
-
return this._client
|
|
712
|
+
return !!this._client?._secureChannel?.isOpened();
|
|
680
713
|
}
|
|
681
714
|
performMessageTransaction(request, callback) {
|
|
682
715
|
if (!this._client) {
|
|
683
716
|
// session may have been closed by user ... but is still in used !!
|
|
684
|
-
|
|
717
|
+
callback(new Error("Session has been closed and should not be used to perform a transaction anymore"));
|
|
718
|
+
return;
|
|
685
719
|
}
|
|
686
720
|
if (request instanceof node_opcua_service_subscription_1.PublishRequest ||
|
|
687
721
|
request instanceof node_opcua_types_1.ActivateSessionRequest ||
|
|
688
722
|
request instanceof node_opcua_types_1.CloseSessionRequest) {
|
|
689
|
-
|
|
723
|
+
this._performMessageTransaction(request, callback);
|
|
724
|
+
return;
|
|
690
725
|
}
|
|
691
|
-
|
|
726
|
+
// Hold the transaction only while the channel is genuinely down and a repair is under
|
|
727
|
+
// way. The repair restores the session *after* the secure channel is back up
|
|
728
|
+
// (_repairConnection: _recreate_secure_channel, then _finalReconnectionStep), so its own
|
|
729
|
+
// traffic - including the plain Read that readOperationLimits issues - always sees a
|
|
730
|
+
// valid channel and passes straight through. Queueing on "reconnecting" alone would
|
|
731
|
+
// park the repair's requests behind the repair that is waiting for them.
|
|
732
|
+
if (!this.isChannelValid() && (this._reconnecting.reconnecting || this._client.isReconnecting)) {
|
|
692
733
|
/* c8 ignore next */
|
|
693
734
|
if (this._reconnecting.pendingTransactions.length > 10) {
|
|
694
735
|
if (!pendingTransactionMessageDisplayed) {
|
|
@@ -698,7 +739,9 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
698
739
|
}
|
|
699
740
|
}
|
|
700
741
|
else if (this._reconnecting.pendingTransactions.length > 3) {
|
|
701
|
-
|
|
742
|
+
// c8 ignore next
|
|
743
|
+
doDebug &&
|
|
744
|
+
debugLog(chalk_1.default.yellow("Warning : your client is sending multiple requests simultaneously to the server", request.constructor.name));
|
|
702
745
|
}
|
|
703
746
|
this._reconnecting.pendingTransactions.push({ request, callback });
|
|
704
747
|
return;
|
|
@@ -709,78 +752,113 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
709
752
|
attemptCount > 0 &&
|
|
710
753
|
warningLog("reprocessRequest => ", request.constructor.name, this._reconnecting.pendingTransactions.length);
|
|
711
754
|
this._performMessageTransaction(request, (err, response) => {
|
|
712
|
-
if (err
|
|
755
|
+
if (err?.message.match(/BadSessionIdInvalid/) && request.constructor.name !== "ActivateSessionRequest") {
|
|
713
756
|
warningLog("Transaction on Invalid Session ", request.constructor.name, err.message, "isReconnecting?=", this.isReconnecting, "q=", this._reconnecting.pendingTransactions.length);
|
|
714
757
|
request.requestHeader.requestHandle = node_opcua_secure_channel_1.requestHandleNotSetValue;
|
|
715
758
|
if (this.isReconnecting) {
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
759
|
+
// Hand it back to the queue rather than parking it on a one-shot
|
|
760
|
+
// session_restored listener: that event is emitted only when a repair
|
|
761
|
+
// succeeds, so a repair that gave up - or a dispose, which drops every
|
|
762
|
+
// listener - left the caller waiting for an answer that could never come.
|
|
763
|
+
// flushPendingTransactions is called on every exit from a repair, so the
|
|
764
|
+
// transaction is always resolved one way or the other.
|
|
765
|
+
// c8 ignore next
|
|
766
|
+
doDebug && debugLog("holding for replay after repair:", request.constructor.name, "attempt", attemptCount);
|
|
767
|
+
this._reconnecting.pendingTransactions.push({ request, callback });
|
|
720
768
|
}
|
|
721
769
|
else {
|
|
722
770
|
this.#_recreate_session_and_reperform_transaction(request, callback);
|
|
723
771
|
}
|
|
724
772
|
return;
|
|
725
773
|
}
|
|
774
|
+
// the queue is owned by flushPendingTransactions, which the repair calls on every
|
|
775
|
+
// exit: draining one entry from here would send it before the session is restored,
|
|
776
|
+
// and would race with that flush.
|
|
726
777
|
callback(err, response);
|
|
727
|
-
const length = this._reconnecting.pendingTransactions.length; // record length before callback is called !
|
|
728
|
-
if (length > 0) {
|
|
729
|
-
debugLog("reprocessRequest => ", this._reconnecting.pendingTransactions.length, " transaction(s) left in queue");
|
|
730
|
-
// tslint:disable-next-line: no-shadowed-variable
|
|
731
|
-
const { request, callback } = this._reconnecting.pendingTransactions.shift();
|
|
732
|
-
this.#reprocessRequest(0, request, callback);
|
|
733
|
-
}
|
|
734
778
|
});
|
|
735
779
|
}
|
|
780
|
+
/**
|
|
781
|
+
* record that the server has answered.
|
|
782
|
+
*
|
|
783
|
+
* A transaction that failed on a timeout or on a broken channel comes back with no response
|
|
784
|
+
* at all and must not refresh lastResponseReceivedTime, or the keep-alive manager would never
|
|
785
|
+
* notice that the server is gone (see #1569). A ServiceFault does count - the round trip
|
|
786
|
+
* completed - but the channel reports it as an Error carrying the decoded fault on
|
|
787
|
+
* err.response, so the response argument alone does not tell the two cases apart.
|
|
788
|
+
*
|
|
789
|
+
* @internal
|
|
790
|
+
*/
|
|
791
|
+
/**
|
|
792
|
+
* resolve every transaction that was held while the connection was down: replay them when the
|
|
793
|
+
* session is usable again, fail them when the repair gave up.
|
|
794
|
+
*
|
|
795
|
+
* Every exit from a repair must call this, otherwise a held caller waits for an answer that
|
|
796
|
+
* can never come - and the session is disposed with a queue that nobody drained.
|
|
797
|
+
*
|
|
798
|
+
* @internal
|
|
799
|
+
*/
|
|
800
|
+
flushPendingTransactions(err) {
|
|
801
|
+
const heldTransactions = this._reconnecting.pendingTransactions.splice(0);
|
|
802
|
+
if (heldTransactions.length === 0) {
|
|
803
|
+
return;
|
|
804
|
+
}
|
|
805
|
+
// c8 ignore next
|
|
806
|
+
doDebug && debugLog("flushPendingTransactions", heldTransactions.length, err ? `failing: ${err.message}` : "replaying");
|
|
807
|
+
pendingTransactionMessageDisplayed = false;
|
|
808
|
+
for (const pending of heldTransactions) {
|
|
809
|
+
if (err) {
|
|
810
|
+
pending.callback(err);
|
|
811
|
+
}
|
|
812
|
+
else {
|
|
813
|
+
this.#reprocessRequest(0, pending.request, pending.callback);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
noteServerAnswer(err, response) {
|
|
818
|
+
if (response || err?.response) {
|
|
819
|
+
this.lastResponseReceivedTime = new Date();
|
|
820
|
+
}
|
|
821
|
+
}
|
|
736
822
|
_performMessageTransaction(request, callback) {
|
|
737
823
|
(0, node_opcua_assert_1.assert)(typeof callback === "function");
|
|
738
824
|
/* c8 ignore next */
|
|
739
825
|
if (!this._client) {
|
|
740
826
|
// session may have been closed by user ... but is still in used !!
|
|
741
|
-
|
|
827
|
+
callback(new Error("Session has been closed and should not be used to perform a transaction anymore"));
|
|
828
|
+
return;
|
|
742
829
|
}
|
|
743
830
|
if (!this.isChannelValid()) {
|
|
744
831
|
// the secure channel is broken, may be the server has crashed or the network cable has been disconnected
|
|
745
832
|
// for a long time
|
|
746
833
|
// we may need to queue this transaction, as a secure token may be being reprocessed
|
|
747
|
-
|
|
748
|
-
|
|
834
|
+
// c8 ignore next
|
|
835
|
+
doDebug && debugLog(chalk_1.default.bgWhite.red("!!! Performing transaction on invalid channel !!! ", request.constructor.name));
|
|
836
|
+
callback(new Error("Invalid Channel BadConnectionClosed"));
|
|
837
|
+
return;
|
|
749
838
|
}
|
|
750
839
|
// is this stuff useful?
|
|
751
840
|
if (request.requestHeader) {
|
|
841
|
+
if (!this.authenticationToken) {
|
|
842
|
+
throw new Error("internal error: authenticationToken should be set on an active session");
|
|
843
|
+
}
|
|
752
844
|
request.requestHeader.authenticationToken = this.authenticationToken;
|
|
753
845
|
}
|
|
754
846
|
this.lastRequestSentTime = new Date();
|
|
755
847
|
this._client.performMessageTransaction(request, (err, response) => {
|
|
756
|
-
this.
|
|
757
|
-
/* c8 ignore next */
|
|
848
|
+
this.noteServerAnswer(err, response);
|
|
758
849
|
if (err) {
|
|
759
|
-
|
|
760
|
-
err.serviceDiagnostics = response.responseHeader.serviceDiagnostics;
|
|
761
|
-
}
|
|
762
|
-
if (response && response.diagnosticInfos) {
|
|
763
|
-
err.diagnosticsInfo = response.diagnosticInfos;
|
|
764
|
-
}
|
|
765
|
-
return callback(err);
|
|
850
|
+
return callback(annotateWithDiagnostics(err, response));
|
|
766
851
|
}
|
|
767
852
|
/* c8 ignore next */
|
|
768
853
|
if (!response) {
|
|
769
854
|
return callback(new Error("internal Error"));
|
|
770
855
|
}
|
|
771
|
-
/* c8 ignore next */
|
|
772
856
|
if (response.responseHeader.serviceResult.isNot(node_opcua_status_code_1.StatusCodes.Good)) {
|
|
773
|
-
|
|
857
|
+
const serviceResultError = new Error(" ServiceResult is " +
|
|
774
858
|
response.responseHeader.serviceResult.toString() +
|
|
775
859
|
" request was " +
|
|
776
860
|
request.constructor.name);
|
|
777
|
-
|
|
778
|
-
err.serviceDiagnostics = response.responseHeader.serviceDiagnostics;
|
|
779
|
-
}
|
|
780
|
-
if (response && response.diagnosticInfos) {
|
|
781
|
-
err.diagnosticsInfo = response.diagnosticInfos;
|
|
782
|
-
}
|
|
783
|
-
return callback(err, response);
|
|
861
|
+
return callback(annotateWithDiagnostics(serviceResultError, response), response);
|
|
784
862
|
}
|
|
785
863
|
return callback(null, response);
|
|
786
864
|
});
|
|
@@ -811,7 +889,12 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
811
889
|
*/
|
|
812
890
|
evaluateRemainingLifetime() {
|
|
813
891
|
const now = Date.now();
|
|
814
|
-
|
|
892
|
+
// anchored on the last answer, not the last send: the server restarts its session
|
|
893
|
+
// watchdog when it *receives* a request, and the only proof the client has that a
|
|
894
|
+
// request arrived is an answer coming back. Anchoring on the send made this return a
|
|
895
|
+
// full lifetime throughout an outage - a client that keeps trying keeps refreshing the
|
|
896
|
+
// send timestamp - which is precisely when the caller needs the truth (see #1569).
|
|
897
|
+
const expiryTime = this.lastResponseReceivedTime.getTime() + this.timeout;
|
|
815
898
|
return Math.max(0, expiryTime - now);
|
|
816
899
|
}
|
|
817
900
|
_terminatePublishEngine() {
|
|
@@ -825,7 +908,7 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
825
908
|
* @param args
|
|
826
909
|
*/
|
|
827
910
|
close(...args) {
|
|
828
|
-
if (
|
|
911
|
+
if (args.length === 1) {
|
|
829
912
|
return this.close(true, args[0]);
|
|
830
913
|
}
|
|
831
914
|
const deleteSubscription = args[0];
|
|
@@ -834,15 +917,18 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
834
917
|
(0, node_opcua_assert_1.assert)(typeof deleteSubscription === "boolean");
|
|
835
918
|
/* c8 ignore next */
|
|
836
919
|
if (!this._client) {
|
|
837
|
-
|
|
920
|
+
// c8 ignore next
|
|
921
|
+
doDebug && debugLog("ClientSession#close : warning, client is already closed");
|
|
838
922
|
return callback(); // already close ?
|
|
839
923
|
}
|
|
840
924
|
(0, node_opcua_assert_1.assert)(this._client);
|
|
841
925
|
this._terminatePublishEngine();
|
|
842
926
|
this._client.closeSession(this, deleteSubscription, (err) => {
|
|
843
|
-
|
|
927
|
+
// c8 ignore next
|
|
928
|
+
doDebug && debugLog("session Close err ", err ? err.message : "null");
|
|
844
929
|
callback();
|
|
845
930
|
});
|
|
931
|
+
return undefined;
|
|
846
932
|
}
|
|
847
933
|
/**
|
|
848
934
|
|
|
@@ -857,7 +943,9 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
857
943
|
*/
|
|
858
944
|
call(...args) {
|
|
859
945
|
const isArray = Array.isArray(args[0]);
|
|
860
|
-
const methodsToCall = isArray
|
|
946
|
+
const methodsToCall = isArray
|
|
947
|
+
? args[0]
|
|
948
|
+
: [args[0]];
|
|
861
949
|
(0, node_opcua_assert_1.assert)(Array.isArray(methodsToCall));
|
|
862
950
|
const callback = args[1];
|
|
863
951
|
// Note : The client has no explicit address space and therefore will struggle to
|
|
@@ -867,7 +955,7 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
867
955
|
// - load a fake address space to have some thing to query on our end
|
|
868
956
|
// const request = this._client.factory.constructObjectId("CallRequest",{ methodsToCall: methodsToCall});
|
|
869
957
|
const request = new node_opcua_service_call_1.CallRequest({ methodsToCall });
|
|
870
|
-
this.performMessageTransaction(request, (err, response) => {
|
|
958
|
+
return this.performMessageTransaction(request, (err, response) => {
|
|
871
959
|
/* c8 ignore next */
|
|
872
960
|
if (err) {
|
|
873
961
|
return callback(err);
|
|
@@ -876,10 +964,11 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
876
964
|
if (!response || !(response instanceof node_opcua_service_call_1.CallResponse)) {
|
|
877
965
|
return callback(new Error("internal error"));
|
|
878
966
|
}
|
|
879
|
-
|
|
880
|
-
|
|
967
|
+
const results = response.results || [];
|
|
968
|
+
response.results = results;
|
|
969
|
+
promoteOpaqueStructureForCall(this, results)
|
|
881
970
|
.then(() => {
|
|
882
|
-
callback(null, isArray ?
|
|
971
|
+
callback(null, isArray ? results : results[0]);
|
|
883
972
|
})
|
|
884
973
|
.catch((err) => {
|
|
885
974
|
callback(err);
|
|
@@ -901,7 +990,7 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
901
990
|
methodId: (0, node_opcua_nodeid_1.coerceNodeId)("ns=0;i=11492"), // MethodIds.Server_GetMonitoredItems;
|
|
902
991
|
objectId: (0, node_opcua_nodeid_1.coerceNodeId)("ns=0;i=2253") // ObjectId.Server
|
|
903
992
|
});
|
|
904
|
-
this.call(methodsToCall, (err, result) => {
|
|
993
|
+
return this.call(methodsToCall, (err, result) => {
|
|
905
994
|
/* c8 ignore next */
|
|
906
995
|
if (err) {
|
|
907
996
|
return callback(err);
|
|
@@ -940,7 +1029,7 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
940
1029
|
(0, node_opcua_assert_1.assert)(typeof callback === "function");
|
|
941
1030
|
return (0, node_opcua_pseudo_session_1.getArgumentDefinitionHelper)(this, methodId)
|
|
942
1031
|
.then((result) => {
|
|
943
|
-
callback(null, result);
|
|
1032
|
+
callback?.(null, result);
|
|
944
1033
|
})
|
|
945
1034
|
.catch((err) => {
|
|
946
1035
|
callback(err);
|
|
@@ -954,7 +1043,7 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
954
1043
|
const request = new node_opcua_service_register_node_1.RegisterNodesRequest({
|
|
955
1044
|
nodesToRegister: nodesToRegister.map((n) => this.resolveNodeId(n))
|
|
956
1045
|
});
|
|
957
|
-
this.performMessageTransaction(request, (err, response) => {
|
|
1046
|
+
return this.performMessageTransaction(request, (err, response) => {
|
|
958
1047
|
/* c8 ignore next */
|
|
959
1048
|
if (err) {
|
|
960
1049
|
return callback(err);
|
|
@@ -975,7 +1064,7 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
975
1064
|
const request = new node_opcua_service_register_node_1.UnregisterNodesRequest({
|
|
976
1065
|
nodesToUnregister: nodesToUnregister.map((n) => this.resolveNodeId(n))
|
|
977
1066
|
});
|
|
978
|
-
this.performMessageTransaction(request, (err, response) => {
|
|
1067
|
+
return this.performMessageTransaction(request, (err, response) => {
|
|
979
1068
|
/* c8 ignore next */
|
|
980
1069
|
if (err) {
|
|
981
1070
|
return callback(err);
|
|
@@ -992,7 +1081,7 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
992
1081
|
const callback = args[1];
|
|
993
1082
|
(0, node_opcua_assert_1.assert)(typeof callback === "function");
|
|
994
1083
|
const request = new node_opcua_service_query_1.QueryFirstRequest(queryFirstRequest);
|
|
995
|
-
this.performMessageTransaction(request, (err, response) => {
|
|
1084
|
+
return this.performMessageTransaction(request, (err, response) => {
|
|
996
1085
|
/* c8 ignore next */
|
|
997
1086
|
if (err) {
|
|
998
1087
|
return callback(err);
|
|
@@ -1038,11 +1127,8 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
1038
1127
|
this.stopKeepAliveManager();
|
|
1039
1128
|
this.removeAllListeners();
|
|
1040
1129
|
//
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
// tslint:disable-next-line: no-console
|
|
1044
|
-
warningLog("dispose when pendingTransactions is not empty ");
|
|
1045
|
-
}
|
|
1130
|
+
// never strand a held caller: the session is going away, so nothing will ever replay them
|
|
1131
|
+
this.flushPendingTransactions(new Error("Session has been disposed while the transaction was waiting for reconnection"));
|
|
1046
1132
|
}
|
|
1047
1133
|
toString() {
|
|
1048
1134
|
const now = Date.now();
|
|
@@ -1050,33 +1136,33 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
1050
1136
|
const lap2 = now - this.lastResponseReceivedTime.getTime();
|
|
1051
1137
|
const timeoutDelay = this.timeout - lap1;
|
|
1052
1138
|
const timeoutInfo = timeoutDelay < 0
|
|
1053
|
-
? chalk_1.default.red(
|
|
1054
|
-
: chalk_1.default.green(
|
|
1139
|
+
? chalk_1.default.red(` expired since ${-timeoutDelay / 1000} seconds`)
|
|
1140
|
+
: chalk_1.default.green(` timeout in ${timeoutDelay / 1000} seconds`);
|
|
1055
1141
|
let str = "";
|
|
1056
|
-
str +=
|
|
1057
|
-
str +=
|
|
1058
|
-
str +=
|
|
1059
|
-
str +=
|
|
1060
|
-
str +=
|
|
1061
|
-
str +=
|
|
1062
|
-
str +=
|
|
1063
|
-
str +=
|
|
1064
|
-
str +=
|
|
1065
|
-
str +=
|
|
1066
|
-
str +=
|
|
1067
|
-
str +=
|
|
1068
|
-
str +=
|
|
1069
|
-
str +=
|
|
1070
|
-
if (this._client
|
|
1142
|
+
str += ` name..................... ${this.name}`;
|
|
1143
|
+
str += `\n sessionId................ ${this.sessionId.toString()}`;
|
|
1144
|
+
str += `\n authenticationToken...... ${this.authenticationToken ? this.authenticationToken?.toString() : ""}`;
|
|
1145
|
+
str += `\n timeout.................. ${this.timeout}ms${timeoutInfo}`;
|
|
1146
|
+
str += `\n serverNonce.............. ${this.serverNonce ? this.serverNonce?.toString("hex") : ""}`;
|
|
1147
|
+
str += `\n serverCertificate........ ${(0, node_opcua_utils_1.buffer_ellipsis)(this.serverCertificate)}`;
|
|
1148
|
+
str += `\n serverSignature.......... ${this.serverSignature}`;
|
|
1149
|
+
str += `\n lastRequestSentTime...... ${new Date(this.lastRequestSentTime).toISOString()} (${lap1})`;
|
|
1150
|
+
str += `\n lastResponseReceivedTime. ${new Date(this.lastResponseReceivedTime).toISOString()} (${lap2})`;
|
|
1151
|
+
str += `\n isReconnecting........... ${this.isReconnecting}`;
|
|
1152
|
+
str += `\n isValidChannel........... ${this.isChannelValid()} has been closed ${this.hasBeenClosed()}`;
|
|
1153
|
+
str += `\n channelId................ ${this.channelId()}`;
|
|
1154
|
+
str += `\n remaining life time...... ${this.evaluateRemainingLifetime()}`;
|
|
1155
|
+
str += `\n subscription count....... ${this.subscriptionCount}`;
|
|
1156
|
+
if (this._client?._secureChannel) {
|
|
1071
1157
|
if (this._client._secureChannel.activeSecurityToken) {
|
|
1072
|
-
str +=
|
|
1158
|
+
str += `\n reviseTokenLifetime...... ${this._client._secureChannel.activeSecurityToken.revisedLifetime}`;
|
|
1073
1159
|
}
|
|
1074
1160
|
}
|
|
1075
|
-
str += "\n keepAlive ................ " + this._keepAliveManager ? true : false;
|
|
1076
1161
|
if (this._keepAliveManager) {
|
|
1077
|
-
str +=
|
|
1078
|
-
str +=
|
|
1079
|
-
str +=
|
|
1162
|
+
str += `\n keepAlive ................ ${this._keepAliveManager}`;
|
|
1163
|
+
str += `\n keepAlive checkInterval.. ${this._keepAliveManager.checkInterval} ms`;
|
|
1164
|
+
str += `\n (defaultTransportTimeout).${node_opcua_secure_channel_1.ClientSecureChannelLayer.defaultTransportTimeout} ms`;
|
|
1165
|
+
str += `\n session timeout ${this.timeout} ms`;
|
|
1080
1166
|
}
|
|
1081
1167
|
return str;
|
|
1082
1168
|
}
|
|
@@ -1094,12 +1180,15 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
1094
1180
|
.catch((err) => {
|
|
1095
1181
|
callback(err);
|
|
1096
1182
|
});
|
|
1183
|
+
return undefined;
|
|
1097
1184
|
}
|
|
1098
1185
|
getNamespaceIndex(namespaceUri) {
|
|
1099
1186
|
(0, node_opcua_assert_1.assert)(this.$$namespaceArray, "please make sure that readNamespaceArray has been called");
|
|
1187
|
+
if (!this.$$namespaceArray) {
|
|
1188
|
+
throw new Error("please make sure that readNamespaceArray has been called");
|
|
1189
|
+
}
|
|
1100
1190
|
return this.$$namespaceArray.indexOf(namespaceUri);
|
|
1101
1191
|
}
|
|
1102
|
-
// tslint:disable:no-empty
|
|
1103
1192
|
// ---------------------------------------- Alarm & condition stub
|
|
1104
1193
|
disableCondition() {
|
|
1105
1194
|
/** empty */
|
|
@@ -1109,19 +1198,19 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
1109
1198
|
}
|
|
1110
1199
|
addCommentCondition(_conditionId, _eventId, _comment, _callback) {
|
|
1111
1200
|
/** empty */
|
|
1201
|
+
return undefined;
|
|
1112
1202
|
}
|
|
1113
1203
|
confirmCondition(_conditionId, _eventId, _comment, _callback) {
|
|
1114
1204
|
/** empty */
|
|
1205
|
+
return undefined;
|
|
1115
1206
|
}
|
|
1116
1207
|
acknowledgeCondition(_conditionId, _eventId, _comment, _callback) {
|
|
1117
1208
|
/** empty */
|
|
1209
|
+
return undefined;
|
|
1118
1210
|
}
|
|
1119
|
-
/**
|
|
1120
|
-
* @deprecated
|
|
1121
|
-
* @private
|
|
1122
|
-
*/
|
|
1123
1211
|
findMethodId(_nodeId, _methodName, _callback) {
|
|
1124
1212
|
/** empty */
|
|
1213
|
+
return undefined;
|
|
1125
1214
|
}
|
|
1126
1215
|
_callMethodCondition(_methodName, _conditionId, _eventId, _comment, _callback) {
|
|
1127
1216
|
/** empty */
|
|
@@ -1143,6 +1232,9 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
1143
1232
|
}
|
|
1144
1233
|
_defaultRequest(requestClass, _responseClass, options, callback) {
|
|
1145
1234
|
(0, node_opcua_assert_1.assert)(typeof callback === "function");
|
|
1235
|
+
if (!callback) {
|
|
1236
|
+
throw new Error("_defaultRequest: expecting a callback function here");
|
|
1237
|
+
}
|
|
1146
1238
|
const request = options instanceof requestClass ? options : new requestClass(options);
|
|
1147
1239
|
/* c8 ignore next */
|
|
1148
1240
|
if (doDebug) {
|
|
@@ -1150,19 +1242,23 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
1150
1242
|
}
|
|
1151
1243
|
/* c8 ignore next */
|
|
1152
1244
|
if (this._closeEventHasBeenEmitted) {
|
|
1153
|
-
|
|
1245
|
+
// c8 ignore next
|
|
1246
|
+
doDebug && debugLog("ClientSession#_defaultRequest => session has been closed !!", request.toString());
|
|
1154
1247
|
setImmediate(() => {
|
|
1155
1248
|
callback(new Error("ClientSession is closed !"));
|
|
1156
1249
|
});
|
|
1157
|
-
return;
|
|
1250
|
+
return undefined;
|
|
1158
1251
|
}
|
|
1159
|
-
this.performMessageTransaction(request, (err, response) => {
|
|
1252
|
+
return this.performMessageTransaction(request, (err, response) => {
|
|
1160
1253
|
if (this._closeEventHasBeenEmitted) {
|
|
1161
|
-
|
|
1254
|
+
// c8 ignore next
|
|
1255
|
+
doDebug &&
|
|
1256
|
+
debugLog("ClientSession#_defaultRequest ... err =", err ? err.message : "null", response ? response.toString() : " null");
|
|
1162
1257
|
}
|
|
1163
1258
|
/* c8 ignore next */
|
|
1164
1259
|
if (err) {
|
|
1165
|
-
|
|
1260
|
+
// c8 ignore next
|
|
1261
|
+
doDebug && debugLog("Client session : performMessageTransaction error = ", err.message);
|
|
1166
1262
|
// let intercept interesting error message
|
|
1167
1263
|
if (err.message.match(/BadSessionClosed/)) {
|
|
1168
1264
|
// the session has been closed by Server
|
|
@@ -1179,6 +1275,7 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
1179
1275
|
}
|
|
1180
1276
|
// DO NOT TERMINATE SESSION, as we will need a publishEngine when we
|
|
1181
1277
|
// reconnect this._terminatePublishEngine();
|
|
1278
|
+
// biome-ignore lint/correctness/noConstantCondition: deliberate debug on/off toggle, not dead code
|
|
1182
1279
|
if (false) {
|
|
1183
1280
|
// ER 10.2019
|
|
1184
1281
|
/**
|
|
@@ -1196,10 +1293,12 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
1196
1293
|
#_recreate_session_and_reperform_transaction(request, callback) {
|
|
1197
1294
|
warningLog("attempt to recreate session to reperform a transaction ", request.constructor.name);
|
|
1198
1295
|
if (this.recursive_repair_detector >= 1) {
|
|
1199
|
-
// tslint:disable-next-line: no-console
|
|
1200
1296
|
warningLog("recreate_session_and_reperform_transaction => Already in Progress");
|
|
1201
1297
|
return callback(new Error("Cannot recreate session"));
|
|
1202
1298
|
}
|
|
1299
|
+
if (!this._client) {
|
|
1300
|
+
return callback(new Error("Cannot recreate session: session has no client"));
|
|
1301
|
+
}
|
|
1203
1302
|
this.recursive_repair_detector += 1;
|
|
1204
1303
|
warningLog(chalk_1.default.red("----------------> Repairing Client Session as Server believes it is invalid now "));
|
|
1205
1304
|
(0, reconnection_1.repair_client_session)(this._client, this, (err) => {
|
|
@@ -1215,7 +1314,7 @@ class ClientSessionImpl extends events_1.EventEmitter {
|
|
|
1215
1314
|
}
|
|
1216
1315
|
exports.ClientSessionImpl = ClientSessionImpl;
|
|
1217
1316
|
async function promoteOpaqueStructureForCallMethodResult(session, callMethodResult) {
|
|
1218
|
-
if (!callMethodResult
|
|
1317
|
+
if (!callMethodResult?.outputArguments || callMethodResult.outputArguments.length === 0) {
|
|
1219
1318
|
return;
|
|
1220
1319
|
}
|
|
1221
1320
|
await (0, node_opcua_client_dynamic_extension_object_1.promoteOpaqueStructure)(session, callMethodResult.outputArguments.map((a) => ({ value: a })));
|
|
@@ -1242,8 +1341,6 @@ async function promoteOpaqueStructureForCall(session, callMethodResults) {
|
|
|
1242
1341
|
const promises = callMethodResults.map(async (x) => promoteOpaqueStructureForCallMethodResult(session, x));
|
|
1243
1342
|
await Promise.all(promises);
|
|
1244
1343
|
}
|
|
1245
|
-
// tslint:disable:no-var-requires
|
|
1246
|
-
// tslint:disable:max-line-length
|
|
1247
1344
|
const thenify_ex_1 = require("thenify-ex");
|
|
1248
1345
|
const opts = { multiArgs: false };
|
|
1249
1346
|
ClientSessionImpl.prototype.browse = (0, thenify_ex_1.withCallback)(ClientSessionImpl.prototype.browse, opts);
|