node-opcua-client 2.63.1 → 2.64.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist/alarms_and_conditions/client_alarm.d.ts +42 -42
  2. package/dist/alarms_and_conditions/client_alarm.js +84 -84
  3. package/dist/alarms_and_conditions/client_alarm_list.d.ts +21 -21
  4. package/dist/alarms_and_conditions/client_alarm_list.js +97 -97
  5. package/dist/alarms_and_conditions/client_alarm_tools.d.ts +4 -4
  6. package/dist/alarms_and_conditions/client_alarm_tools.js +139 -139
  7. package/dist/alarms_and_conditions/client_alarm_tools_acknowledge_all_conditions.d.ts +18 -18
  8. package/dist/alarms_and_conditions/client_alarm_tools_acknowledge_all_conditions.js +190 -190
  9. package/dist/alarms_and_conditions/client_alarm_tools_dump_event.d.ts +9 -9
  10. package/dist/alarms_and_conditions/client_alarm_tools_dump_event.js +73 -73
  11. package/dist/alarms_and_conditions/client_alarm_tools_extractConditionFields.d.ts +8 -8
  12. package/dist/alarms_and_conditions/client_alarm_tools_extractConditionFields.js +120 -120
  13. package/dist/alarms_and_conditions/client_tools.d.ts +7 -7
  14. package/dist/alarms_and_conditions/client_tools.js +179 -179
  15. package/dist/client_base.d.ts +270 -270
  16. package/dist/client_base.js +13 -13
  17. package/dist/client_monitored_item.d.ts +21 -21
  18. package/dist/client_monitored_item.js +11 -11
  19. package/dist/client_monitored_item_base.d.ts +39 -39
  20. package/dist/client_monitored_item_base.js +2 -2
  21. package/dist/client_monitored_item_group.d.ts +18 -18
  22. package/dist/client_monitored_item_group.js +13 -13
  23. package/dist/client_monitored_item_toolbox.d.ts +15 -15
  24. package/dist/client_monitored_item_toolbox.js +117 -117
  25. package/dist/client_session.d.ts +483 -483
  26. package/dist/client_session.js +10 -10
  27. package/dist/client_session_keepalive_manager.d.ts +34 -34
  28. package/dist/client_session_keepalive_manager.js +150 -150
  29. package/dist/client_session_keepalive_manager.js.map +1 -1
  30. package/dist/client_subscription.d.ts +241 -241
  31. package/dist/client_subscription.js +14 -14
  32. package/dist/client_utils.d.ts +22 -22
  33. package/dist/client_utils.js +88 -88
  34. package/dist/common.d.ts +17 -17
  35. package/dist/common.js +5 -5
  36. package/dist/index.d.ts +55 -55
  37. package/dist/index.js +89 -89
  38. package/dist/opcua_client.d.ts +132 -132
  39. package/dist/opcua_client.js +33 -33
  40. package/dist/private/client_base_impl.d.ts +169 -169
  41. package/dist/private/client_base_impl.js +1315 -1318
  42. package/dist/private/client_base_impl.js.map +1 -1
  43. package/dist/private/client_monitored_item_base_impl.d.ts +3 -3
  44. package/dist/private/client_monitored_item_base_impl.js +4 -4
  45. package/dist/private/client_monitored_item_group_impl.d.ts +53 -53
  46. package/dist/private/client_monitored_item_group_impl.js +159 -159
  47. package/dist/private/client_monitored_item_impl.d.ts +93 -93
  48. package/dist/private/client_monitored_item_impl.js +304 -304
  49. package/dist/private/client_publish_engine.d.ts +62 -62
  50. package/dist/private/client_publish_engine.js +408 -408
  51. package/dist/private/client_session_impl.d.ts +620 -620
  52. package/dist/private/client_session_impl.js +1298 -1298
  53. package/dist/private/client_subscription_impl.d.ts +93 -93
  54. package/dist/private/client_subscription_impl.js +779 -779
  55. package/dist/private/i_private_client.d.ts +18 -18
  56. package/dist/private/i_private_client.js +2 -2
  57. package/dist/private/opcua_client_impl.d.ts +169 -169
  58. package/dist/private/opcua_client_impl.js +978 -975
  59. package/dist/private/opcua_client_impl.js.map +1 -1
  60. package/dist/reconnection.d.ts +9 -9
  61. package/dist/reconnection.js +362 -362
  62. package/dist/tools/findservers.d.ts +20 -20
  63. package/dist/tools/findservers.js +61 -61
  64. package/dist/tools/read_history_server_capabilities.d.ts +6 -6
  65. package/dist/tools/read_history_server_capabilities.js +99 -99
  66. package/dist/verify.d.ts +5 -5
  67. package/dist/verify.js +134 -134
  68. package/package.json +46 -46
  69. package/source/client_session_keepalive_manager.ts +1 -1
  70. package/source/private/client_base_impl.ts +0 -3
  71. package/source/private/opcua_client_impl.ts +4 -1
@@ -1,1319 +1,1316 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.ClientBaseImpl = void 0;
13
- /**
14
- * @module node-opcua-client-private
15
- */
16
- // tslint:disable:no-unused-expression
17
- const fs = require("fs");
18
- const path = require("path");
19
- const async = require("async");
20
- const chalk = require("chalk");
21
- const global_mutex_1 = require("@ster5/global-mutex");
22
- const node_opcua_assert_1 = require("node-opcua-assert");
23
- const node_opcua_common_1 = require("node-opcua-common");
24
- const node_opcua_crypto_1 = require("node-opcua-crypto");
25
- const node_opcua_date_time_1 = require("node-opcua-date-time");
26
- const node_opcua_debug_1 = require("node-opcua-debug");
27
- const node_opcua_common_2 = require("node-opcua-common");
28
- const node_opcua_hostname_1 = require("node-opcua-hostname");
29
- const node_opcua_secure_channel_1 = require("node-opcua-secure-channel");
30
- const node_opcua_service_discovery_1 = require("node-opcua-service-discovery");
31
- const node_opcua_service_endpoints_1 = require("node-opcua-service-endpoints");
32
- const node_opcua_service_secure_channel_1 = require("node-opcua-service-secure-channel");
33
- const node_opcua_status_code_1 = require("node-opcua-status-code");
34
- const node_opcua_utils_1 = require("node-opcua-utils");
35
- const node_opcua_certificate_manager_1 = require("node-opcua-certificate-manager");
36
- const node_opcua_service_session_1 = require("node-opcua-service-session");
37
- const client_base_1 = require("../client_base");
38
- const verify_1 = require("../verify");
39
- // tslint:disable-next-line:no-var-requires
40
- const once = require("once");
41
- const debugLog = (0, node_opcua_debug_1.make_debugLog)(__filename);
42
- const doDebug = (0, node_opcua_debug_1.checkDebugFlag)(__filename);
43
- const errorLog = (0, node_opcua_debug_1.make_errorLog)(__filename);
44
- const warningLog = (0, node_opcua_debug_1.make_warningLog)(__filename);
45
- const defaultConnectionStrategy = {
46
- initialDelay: 1000,
47
- maxDelay: 20 * 1000,
48
- maxRetry: -1,
49
- randomisationFactor: 0.1
50
- };
51
- function __findEndpoint(endpointUrl, params, _callback) {
52
- const masterClient = this;
53
- debugLog("findEndpoint : endpointUrl = ", endpointUrl);
54
- debugLog(" params ", params);
55
- (0, node_opcua_assert_1.assert)(!masterClient._tmpClient);
56
- const callback = (err, result) => {
57
- masterClient._tmpClient = undefined;
58
- _callback(err, result);
59
- };
60
- const securityMode = params.securityMode;
61
- const securityPolicy = params.securityPolicy;
62
- const connectionStrategy = params.connectionStrategy;
63
- const options = {
64
- applicationName: params.applicationName,
65
- applicationUri: params.applicationUri,
66
- certificateFile: params.certificateFile,
67
- clientCertificateManager: params.clientCertificateManager,
68
- clientName: "EndpointFetcher",
69
- connectionStrategy: {
70
- maxRetry: 0 /* no- retry */,
71
- maxDelay: 2000
72
- },
73
- privateKeyFile: params.privateKeyFile
74
- };
75
- const client = new TmpClient(options);
76
- masterClient._tmpClient = client;
77
- let selectedEndpoint;
78
- const allEndpoints = [];
79
- const tasks = [
80
- (innerCallback) => {
81
- // rebind backoff handler
82
- masterClient.listeners("backoff").forEach((handler) => client.on("backoff", handler));
83
- if (doDebug) {
84
- client.on("backoff", (retryCount, delay) => {
85
- debugLog("finding Endpoint => reconnecting ", " retry count", retryCount, " next attempt in ", delay / 1000, "seconds");
86
- });
87
- }
88
- client.connect(endpointUrl, (err) => {
89
- if (err) {
90
- // let's improve the error message with meaningful info
91
- err.message =
92
- "Fail to connect to server at " +
93
- endpointUrl +
94
- " to collect server's certificate (in findEndpoint) \n" +
95
- " (err =" +
96
- err.message +
97
- ")";
98
- debugLog(err.message);
99
- }
100
- return innerCallback(err);
101
- });
102
- },
103
- (innerCallback) => {
104
- client.getEndpoints((err, endpoints) => {
105
- if (err) {
106
- err.message = "error in getEndpoints \n" + err.message;
107
- return innerCallback(err);
108
- }
109
- // istanbul ignore next
110
- if (!endpoints) {
111
- return innerCallback(new Error("Internal Error"));
112
- }
113
- for (const endpoint of endpoints) {
114
- if (endpoint.securityMode === securityMode && endpoint.securityPolicyUri === securityPolicy) {
115
- if (selectedEndpoint) {
116
- errorLog("Warning more than one endpoint matching !", endpoint.endpointUrl, selectedEndpoint.endpointUrl);
117
- }
118
- selectedEndpoint = endpoint; // found it
119
- }
120
- }
121
- innerCallback();
122
- });
123
- },
124
- (innerCallback) => {
125
- client.disconnect(innerCallback);
126
- }
127
- ];
128
- async.series(tasks, (err) => {
129
- if (err) {
130
- client.disconnect(() => {
131
- callback(err);
132
- });
133
- return;
134
- }
135
- if (!selectedEndpoint) {
136
- return callback(new Error("Cannot find an Endpoint matching " +
137
- " security mode: " +
138
- securityMode.toString() +
139
- " policy: " +
140
- securityPolicy.toString()));
141
- }
142
- // istanbul ignore next
143
- if (doDebug) {
144
- debugLog(chalk.bgWhite.red("xxxxxxxxxxxxxxxxxxxxx => selected EndPoint = "), selectedEndpoint.toString());
145
- }
146
- const result = {
147
- endpoints: allEndpoints,
148
- selectedEndpoint
149
- };
150
- callback(null, result);
151
- });
152
- }
153
- /**
154
- * check if certificate is trusted or untrusted
155
- */
156
- function _verify_serverCertificate(certificateManager, serverCertificate, callback) {
157
- certificateManager.checkCertificate(serverCertificate, (err, status) => {
158
- if (err) {
159
- return callback(err);
160
- }
161
- if (status !== node_opcua_status_code_1.StatusCodes.Good) {
162
- // do it again for debug purposes
163
- if (doDebug) {
164
- certificateManager.verifyCertificate(serverCertificate, (err1, status1) => {
165
- debugLog(status1);
166
- });
167
- }
168
- warningLog("serverCertificate = ", (0, node_opcua_crypto_1.makeSHA1Thumbprint)(serverCertificate).toString("hex"));
169
- warningLog("serverCertificate = ", serverCertificate.toString("base64"));
170
- return callback(new Error("server Certificate verification failed with err " + (status === null || status === void 0 ? void 0 : status.toString())));
171
- }
172
- callback();
173
- });
174
- }
175
- const forceEndpointDiscoveryOnConnect = !!parseInt(process.env.NODEOPCUA_CLIENT_FORCE_ENDPOINT_DISCOVERY || "0", 10);
176
- debugLog("forceEndpointDiscoveryOnConnect = ", forceEndpointDiscoveryOnConnect);
177
- class ClockAdjustment {
178
- constructor() {
179
- debugLog("installPeriodicClockAdjustment ", node_opcua_date_time_1.periodicClockAdjustment.timerInstallationCount);
180
- (0, node_opcua_date_time_1.installPeriodicClockAdjustment)();
181
- }
182
- dispose() {
183
- (0, node_opcua_date_time_1.uninstallPeriodicClockAdjustment)();
184
- debugLog("uninstallPeriodicClockAdjustment ", node_opcua_date_time_1.periodicClockAdjustment.timerInstallationCount);
185
- }
186
- }
187
- /*
188
- * "disconnected" ---[connect]----------------------> "connecting"
189
- *
190
- * "connecting" ---[(connection successful)]------> "connected"
191
- *
192
- * "connecting" ---[(connection failure)]---------> "disconnected"
193
- *
194
- * "connecting" ---[disconnect]-------------------> "disconnecting" --> "disconnected"
195
- *
196
- * "connecting" ---[lost of connection]-----------> "reconnecting" ->[reconnection]
197
- *
198
- * "reconnecting" ---[reconnection successful]------> "connected"
199
- *
200
- * "reconnecting" ---[reconnection failure]---------> [reconnection] ---> "reconnecting"
201
- *
202
- * "reconnecting" ---[disconnect]-------------------> "disconnecting" --> "disconnected"
203
- */
204
- let g_ClientCounter = 0;
205
- /**
206
- * @internal
207
- */
208
- // tslint:disable-next-line: max-classes-per-file
209
- class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
210
- constructor(options) {
211
- options = options || {};
212
- if (!options.clientCertificateManager) {
213
- options.clientCertificateManager = (0, node_opcua_certificate_manager_1.getDefaultCertificateManager)("PKI");
214
- }
215
- options.privateKeyFile = options.privateKeyFile || options.clientCertificateManager.privateKey;
216
- options.certificateFile =
217
- options.certificateFile || path.join(options.clientCertificateManager.rootDir, "own/certs/client_certificate.pem");
218
- super(options);
219
- this._instanceNumber = g_ClientCounter++;
220
- this._internalState = "uninitialized";
221
- this.applicationName = options.applicationName || "NodeOPCUA-Client";
222
- (0, node_opcua_assert_1.assert)(!this.applicationName.match(/^locale=/), "applicationName badly converted from LocalizedText");
223
- (0, node_opcua_assert_1.assert)(!this.applicationName.match(/urn:/), "applicationName should not be a URI");
224
- // we need to delay _applicationUri initialization
225
- this._applicationUri = options.applicationUri || this._getBuiltApplicationUri();
226
- this.disconnecting = false;
227
- this.clientCertificateManager = options.clientCertificateManager;
228
- this._secureChannel = null;
229
- this.reconnectionIsCanceled = false;
230
- this.endpointUrl = "";
231
- this.clientName = options.clientName || "ClientSession";
232
- // must be ZERO with Spec 1.0.2
233
- this.protocolVersion = 0;
234
- this._sessions = [];
235
- this._serverEndpoints = [];
236
- this.defaultSecureTokenLifetime = options.defaultSecureTokenLifetime || 600000;
237
- this.tokenRenewalInterval = options.tokenRenewalInterval || 0;
238
- (0, node_opcua_assert_1.assert)(isFinite(this.tokenRenewalInterval) && this.tokenRenewalInterval >= 0);
239
- this.securityMode = (0, node_opcua_service_secure_channel_1.coerceMessageSecurityMode)(options.securityMode);
240
- this.securityPolicy = (0, node_opcua_secure_channel_1.coerceSecurityPolicy)(options.securityPolicy);
241
- this.serverCertificate = options.serverCertificate;
242
- this.keepSessionAlive = typeof options.keepSessionAlive === "boolean" ? options.keepSessionAlive : false;
243
- // statistics...
244
- this._byteRead = 0;
245
- this._byteWritten = 0;
246
- this._transactionsPerformed = 0;
247
- this._timedOutRequestCount = 0;
248
- this.connectionStrategy = (0, node_opcua_secure_channel_1.coerceConnectionStrategy)(options.connectionStrategy || defaultConnectionStrategy);
249
- /***
250
- * @property keepPendingSessionsOnDisconnect²
251
- * @type {boolean}
252
- */
253
- this.keepPendingSessionsOnDisconnect = options.keepPendingSessionsOnDisconnect || false;
254
- this.discoveryUrl = options.discoveryUrl || "";
255
- this._setInternalState("disconnected");
256
- }
257
- /**
258
- * total number of requests that been canceled due to timeout
259
- * @property timedOutRequestCount
260
- * @type {Number}
261
- */
262
- get timedOutRequestCount() {
263
- return this._timedOutRequestCount + (this._secureChannel ? this._secureChannel.timedOutRequestCount : 0);
264
- }
265
- /**
266
- * total number of transactions performed by the client
267
- * @property transactionsPerformed
268
- * @type {Number}
269
- */
270
- get transactionsPerformed() {
271
- return this._transactionsPerformed + (this._secureChannel ? this._secureChannel.transactionsPerformed : 0);
272
- }
273
- /**
274
- * is true when the client has already requested the server end points.
275
- * @property knowsServerEndpoint
276
- * @type boolean
277
- */
278
- get knowsServerEndpoint() {
279
- return this._serverEndpoints && this._serverEndpoints.length > 0;
280
- }
281
- /**
282
- * true if the client is trying to reconnect to the server after a connection break.
283
- * @property isReconnecting
284
- * @type {Boolean}
285
- */
286
- get isReconnecting() {
287
- return !!(this._secureChannel && this._secureChannel.isConnecting) || this._internalState !== "connected";
288
- }
289
- /**
290
- * true if the connection strategy is set to automatically try to reconnect in case of failure
291
- * @property reconnectOnFailure
292
- * @type {Boolean}
293
- */
294
- get reconnectOnFailure() {
295
- return this.connectionStrategy.maxRetry > 0 || this.connectionStrategy.maxRetry === -1;
296
- }
297
- /**
298
- * total number of bytes read by the client
299
- * @property bytesRead
300
- * @type {Number}
301
- */
302
- get bytesRead() {
303
- return this._byteRead + (this._secureChannel ? this._secureChannel.bytesRead : 0);
304
- }
305
- /**
306
- * total number of bytes written by the client
307
- * @property bytesWritten
308
- * @type {Number}
309
- */
310
- get bytesWritten() {
311
- return this._byteWritten + (this._secureChannel ? this._secureChannel.bytesWritten : 0);
312
- }
313
- _setInternalState(internalState) {
314
- const previousState = this._internalState;
315
- if (doDebug) {
316
- debugLog(chalk.cyan(` Client ${this._instanceNumber} ${this.clientName} from `), chalk.yellow(previousState), "to", chalk.yellow(internalState));
317
- }
318
- this._internalState = internalState;
319
- }
320
- emit(eventName, ...others) {
321
- if (doDebug) {
322
- debugLog(chalk.cyan(` Client ${this._instanceNumber} ${this.clientName} emitting `), chalk.magentaBright(eventName));
323
- }
324
- return super.emit(eventName, ...others);
325
- }
326
- _cancel_reconnection(callback) {
327
- // _cancel_reconnection is invoked during disconnection
328
- // when we detect that a reconnection is in progress..
329
- (0, node_opcua_assert_1.assert)(this.isReconnecting);
330
- this.reconnectionIsCanceled = true;
331
- // istanbul ignore next
332
- if (!this._secureChannel) {
333
- debugLog("_cancel_reconnection: Nothing to do !");
334
- return callback(); // nothing to do
335
- }
336
- this._secureChannel.abortConnection(( /*err?: Error*/) => {
337
- this._secureChannel = null;
338
- callback();
339
- });
340
- this.once("reconnection_canceled", () => {
341
- /* empty */
342
- });
343
- }
344
- _recreate_secure_channel(callback) {
345
- debugLog("_recreate_secure_channel...", this._internalState);
346
- if (!this.knowsServerEndpoint) {
347
- debugLog("Cannot reconnect , server endpoint is unknown");
348
- return callback(new Error("Cannot reconnect, server endpoint is unknown"));
349
- }
350
- (0, node_opcua_assert_1.assert)(this.knowsServerEndpoint);
351
- // xx ??? assert(!this.isReconnecting);
352
- /**
353
- * notifies the observer that the OPCUA is now trying to reestablish the connection
354
- * after having received a connection break...
355
- * @event start_reconnection
356
- *
357
- */
358
- this._setInternalState("reconnecting");
359
- this.emit("start_reconnection"); // send after callback
360
- this._destroy_secure_channel();
361
- (0, node_opcua_assert_1.assert)(!this._secureChannel);
362
- const infiniteConnectionRetry = {
363
- initialDelay: this.connectionStrategy.initialDelay,
364
- maxDelay: this.connectionStrategy.maxDelay,
365
- maxRetry: -1
366
- };
367
- const failAndRetry = (err, message) => {
368
- debugLog("failAndRetry; ", message);
369
- if (this.reconnectionIsCanceled) {
370
- this.emit("reconnection_canceled");
371
- return callback(new Error("Reconnection has been canceled - " + this.clientName));
372
- }
373
- warningLog("client = ", this.clientName, message, err.message);
374
- // else
375
- // let retry a little bit later
376
- this.emit("reconnection_attempt_has_failed", err, message); // send after callback
377
- setTimeout(_attempt_to_recreate_secure_channel, 100);
378
- };
379
- const _attempt_to_recreate_secure_channel = () => {
380
- if (this.reconnectionIsCanceled) {
381
- this.emit("reconnection_canceled");
382
- return callback(new Error("Reconnection has been canceled - " + this.clientName));
383
- }
384
- this._internal_create_secure_channel(infiniteConnectionRetry, (err) => {
385
- if (err) {
386
- if (err.message.match(/ECONNREFUSED|ECONNABORTED/)) {
387
- return callback(err);
388
- }
389
- if (err.message.match("Backoff aborted.")) {
390
- return failAndRetry(err, "cannot create secure channel (backoff aborted)");
391
- }
392
- if (err.message.match("BadCertificateInvalid") ||
393
- err.message.match(/_socket has been disconnected by third party/)) {
394
- warningLog("the server certificate has changed, we need to retrieve server certificate again: ", err.message);
395
- warningLog("old server certificate ", this.serverCertificate ? (0, node_opcua_crypto_1.makeSHA1Thumbprint)(this.serverCertificate).toString("hex") : "undefined");
396
- // the server may have shut down the channel because its certificate
397
- // has changed ....
398
- // let request the server certificate again ....
399
- debugLog(chalk.bgWhite.red("ClientBaseImpl: Server Certificate has changed." + " we need to retrieve server certificate again"));
400
- return this.fetchServerCertificate(this.endpointUrl, (err1) => {
401
- if (err1) {
402
- errorLog("Failing to fetch new server certificate: ", err1.message);
403
- return failAndRetry(err1, "trying to fetch new server certificate");
404
- }
405
- warningLog("new server certificate ", (0, node_opcua_crypto_1.makeSHA1Thumbprint)(this.serverCertificate).toString("hex"));
406
- this._internal_create_secure_channel(infiniteConnectionRetry, (err3) => {
407
- if (err3) {
408
- return failAndRetry(err3, "trying to create new channel with new certificate");
409
- }
410
- this._setInternalState("connected");
411
- this.emit("connected");
412
- callback();
413
- });
414
- });
415
- }
416
- debugLog(chalk.bgWhite.red("ClientBaseImpl: cannot reconnect .."));
417
- failAndRetry(err, "cannot create secure channel");
418
- }
419
- else {
420
- /**
421
- * notify the observers that the reconnection process has been completed
422
- * @event after_reconnection
423
- * @param err
424
- */
425
- this.emit("after_reconnection", err); // send after callback
426
- (0, node_opcua_assert_1.assert)(this._secureChannel, "expecting a secureChannel here ");
427
- // a new channel has be created and a new connection is established
428
- debugLog(chalk.bgWhite.red("ClientBaseImpl: RECONNECTED !!!"));
429
- this._setInternalState("connected");
430
- return callback();
431
- }
432
- });
433
- };
434
- // create a secure channel
435
- // a new secure channel must be established
436
- setImmediate(() => {
437
- _attempt_to_recreate_secure_channel();
438
- });
439
- }
440
- _internal_create_secure_channel(connectionStrategy, callback) {
441
- (0, node_opcua_assert_1.assert)(this._secureChannel === null);
442
- (0, node_opcua_assert_1.assert)(typeof this.endpointUrl === "string");
443
- debugLog("_internal_create_secure_channel creating new ClientSecureChannelLayer");
444
- const secureChannel = new node_opcua_secure_channel_1.ClientSecureChannelLayer({
445
- connectionStrategy,
446
- defaultSecureTokenLifetime: this.defaultSecureTokenLifetime,
447
- parent: this,
448
- securityMode: this.securityMode,
449
- securityPolicy: this.securityPolicy,
450
- serverCertificate: this.serverCertificate,
451
- tokenRenewalInterval: this.tokenRenewalInterval
452
- });
453
- secureChannel.protocolVersion = this.protocolVersion;
454
- this._secureChannel = secureChannel;
455
- async.series([
456
- // ------------------------------------------------- STEP 2 : OpenSecureChannel
457
- (_innerCallback) => {
458
- debugLog("_internal_create_secure_channel before secureChannel.create");
459
- secureChannel.create(this.endpointUrl, (err) => {
460
- debugLog("_internal_create_secure_channel after secureChannel.create");
461
- if (!this._secureChannel) {
462
- debugLog("_secureChannel has been closed during the transaction !");
463
- return _innerCallback(new Error("Secure Channel Closed"));
464
- }
465
- if (err) {
466
- debugLog(chalk.yellow("Cannot create secureChannel"), err.message ? chalk.cyan(err.message) : "");
467
- this._destroy_secure_channel();
468
- }
469
- else {
470
- (0, node_opcua_assert_1.assert)(this._secureChannel !== null);
471
- this._install_secure_channel_event_handlers(secureChannel);
472
- }
473
- _innerCallback(err);
474
- });
475
- secureChannel.on("backoff", (count, delay) => {
476
- this.emit("backoff", count, delay);
477
- });
478
- secureChannel.on("abort", () => {
479
- this.emit("abort");
480
- });
481
- },
482
- // ------------------------------------------------- STEP 3 : GetEndpointsRequest
483
- (innerCallback) => {
484
- (0, node_opcua_assert_1.assert)(this._secureChannel !== null);
485
- if (!this.knowsServerEndpoint) {
486
- this.getEndpoints((err /*, endpoints?: EndpointDescription[]*/) => {
487
- if (this._secureChannel === null) {
488
- (0, node_opcua_assert_1.assert)(this.disconnecting);
489
- innerCallback(new Error("disconnecting"));
490
- }
491
- innerCallback(err ? err : undefined);
492
- });
493
- }
494
- else {
495
- // end points are already known
496
- innerCallback();
497
- }
498
- }
499
- ], (err) => {
500
- if (err) {
501
- debugLog("Inner create secure channel has failed", err.message);
502
- this._secureChannel = null;
503
- callback(err);
504
- }
505
- else {
506
- (0, node_opcua_assert_1.assert)(this._secureChannel !== null);
507
- callback(null, secureChannel);
508
- }
509
- });
510
- }
511
- static createCertificate(clientCertificateManager, certificateFile, applicationName, applicationUri) {
512
- return __awaiter(this, void 0, void 0, function* () {
513
- if (!fs.existsSync(certificateFile)) {
514
- const hostname = (0, node_opcua_hostname_1.getHostname)();
515
- // this.serverInfo.applicationUri!;
516
- yield clientCertificateManager.createSelfSignedCertificate({
517
- applicationUri,
518
- dns: [hostname],
519
- // ip: await getIpAddresses(),
520
- outputFile: certificateFile,
521
- subject: (0, node_opcua_certificate_manager_1.makeSubject)(applicationName, hostname),
522
- startDate: new Date(),
523
- validity: 365 * 10 // 10 years
524
- });
525
- }
526
- // istanbul ignore next
527
- if (!fs.existsSync(certificateFile)) {
528
- throw new Error(" cannot locate certificate file " + certificateFile);
529
- }
530
- });
531
- }
532
- createDefaultCertificate() {
533
- return __awaiter(this, void 0, void 0, function* () {
534
- // istanbul ignore next
535
- if (this._inCreateDefaultCertificate) {
536
- errorLog("Internal error : re-entrancy in createDefaultCertificate!");
537
- }
538
- this._inCreateDefaultCertificate = true;
539
- if (!fs.existsSync(this.certificateFile)) {
540
- const lockfile = path.join(this.certificateFile + ".lock");
541
- yield (0, global_mutex_1.withLock)({ lockfile: lockfile, maxStaleDuration: 60 * 1000, retryInterval: 100 }, () => __awaiter(this, void 0, void 0, function* () {
542
- if (this.disconnecting)
543
- return;
544
- yield ClientBaseImpl.createCertificate(this.clientCertificateManager, this.certificateFile, this.applicationName, this._getBuiltApplicationUri());
545
- debugLog("privateKey = ", this.privateKeyFile);
546
- debugLog(" = ", this.clientCertificateManager.privateKey);
547
- debugLog("certificateFile = ", this.certificateFile);
548
- const certificate = this.getCertificate();
549
- const privateKey = this.getPrivateKey();
550
- }));
551
- }
552
- this._inCreateDefaultCertificate = false;
553
- });
554
- }
555
- _getBuiltApplicationUri() {
556
- if (!this._applicationUri) {
557
- this._applicationUri = (0, node_opcua_common_2.makeApplicationUrn)((0, node_opcua_hostname_1.getHostname)(), this.applicationName);
558
- }
559
- return this._applicationUri;
560
- }
561
- initializeCM() {
562
- return __awaiter(this, void 0, void 0, function* () {
563
- if (!this.clientCertificateManager) {
564
- return;
565
- }
566
- yield this.clientCertificateManager.initialize();
567
- yield this.createDefaultCertificate();
568
- // istanbul ignore next
569
- if (!fs.existsSync(this.privateKeyFile)) {
570
- throw new Error(" cannot locate private key file " + this.privateKeyFile);
571
- }
572
- if (this.disconnecting)
573
- return;
574
- const lockfile = path.join(this.certificateFile + ".lock");
575
- yield (0, global_mutex_1.withLock)({ lockfile: lockfile, maxStaleDuration: 60 * 1000, retryInterval: 100 }, () => __awaiter(this, void 0, void 0, function* () {
576
- if (this.disconnecting)
577
- return;
578
- yield verify_1.performCertificateSanityCheck.call(this, "client", this.clientCertificateManager, this._getBuiltApplicationUri());
579
- }));
580
- });
581
- }
582
- _handleUnrecoverableConnectionFailure(err, callback) {
583
- debugLog(err.message);
584
- this.emit("connection_failed");
585
- this._setInternalState("disconnected");
586
- return callback(err);
587
- }
588
- _handleDisconnectionWhileConnecting(err, callback) {
589
- debugLog(err.message);
590
- this.emit("connection_failed");
591
- this._setInternalState("disconnected");
592
- return callback(err);
593
- }
594
- _handleSuccessfulConnection(callback) {
595
- debugLog(" Connected successfully to ", this.endpointUrl);
596
- this.emit("connected");
597
- this._setInternalState("connected");
598
- callback();
599
- }
600
- connect(...args) {
601
- const endpointUrl = args[0];
602
- const callback = args[1];
603
- (0, node_opcua_assert_1.assert)(typeof callback === "function", "expecting a callback");
604
- if (typeof endpointUrl !== "string" || endpointUrl.length <= 0) {
605
- errorLog("[NODE-OPCUA-E03] OPCUAClient#connect expects a valid endpoint : " + endpointUrl);
606
- callback(new Error("Invalid endpoint"));
607
- return;
608
- }
609
- (0, node_opcua_assert_1.assert)(typeof endpointUrl === "string" && endpointUrl.length > 0);
610
- // istanbul ignore next
611
- if (this._internalState !== "disconnected") {
612
- callback(new Error("invalid internal state = " + this._internalState));
613
- return;
614
- }
615
- // prevent illegal call to connect
616
- if (this._secureChannel !== null) {
617
- setImmediate(() => callback(new Error("connect already called")));
618
- return;
619
- }
620
- this._setInternalState("connecting");
621
- this.disconnecting = false;
622
- this.initializeCM()
623
- .then(() => {
624
- debugLog("ClientBaseImpl#connect ", endpointUrl);
625
- if (this.disconnecting) {
626
- return this._handleDisconnectionWhileConnecting(new Error("premature disconnection 1"), callback);
627
- }
628
- if (!this.serverCertificate &&
629
- (forceEndpointDiscoveryOnConnect || this.securityMode !== node_opcua_service_secure_channel_1.MessageSecurityMode.None)) {
630
- debugLog("Fetching certificates from endpoints");
631
- this.fetchServerCertificate(endpointUrl, (err, adjustedEndpointUrl) => {
632
- if (err) {
633
- return this._handleUnrecoverableConnectionFailure(err, callback);
634
- }
635
- if (this.disconnecting) {
636
- return this._handleDisconnectionWhileConnecting(new Error("premature disconnection 2"), callback);
637
- }
638
- if (forceEndpointDiscoveryOnConnect) {
639
- debugLog("connecting with adjusted endpoint : ", adjustedEndpointUrl, " was =", endpointUrl);
640
- this._connectStep2(adjustedEndpointUrl, callback);
641
- }
642
- else {
643
- debugLog("connecting with endpoint : ", endpointUrl);
644
- this._connectStep2(endpointUrl, callback);
645
- }
646
- });
647
- }
648
- else {
649
- this._connectStep2(endpointUrl, callback);
650
- }
651
- })
652
- .catch((err) => {
653
- return this._handleUnrecoverableConnectionFailure(err, callback);
654
- });
655
- }
656
- /**
657
- * @private
658
- */
659
- _connectStep2(endpointUrl, callback) {
660
- // prevent illegal call to connect
661
- (0, node_opcua_assert_1.assert)(this._secureChannel === null);
662
- this.endpointUrl = endpointUrl;
663
- this._clockAdjuster = this._clockAdjuster || new ClockAdjustment();
664
- client_base_1.OPCUAClientBase.registry.register(this);
665
- debugLog("__connectStep2");
666
- this._internal_create_secure_channel(this.connectionStrategy, (err) => {
667
- if (!err) {
668
- this._handleSuccessfulConnection(callback);
669
- }
670
- else {
671
- client_base_1.OPCUAClientBase.registry.unregister(this);
672
- if (this._clockAdjuster) {
673
- this._clockAdjuster.dispose();
674
- this._clockAdjuster = undefined;
675
- }
676
- debugLog(chalk.red("SecureChannel creation has failed with error :", err.message));
677
- if (err.message.match(/ECONNABORTED/)) {
678
- debugLog(chalk.yellow("- The client cannot to :" + endpointUrl + ". Connection has been aborted."));
679
- err = new Error("The connection has been aborted");
680
- this._handleUnrecoverableConnectionFailure(err, callback);
681
- }
682
- else if (err.message.match(/ECONNREF/)) {
683
- debugLog(chalk.yellow("- The client cannot to :" + endpointUrl + ". Server is not reachable."));
684
- err = new Error("The connection cannot be established with server " +
685
- endpointUrl +
686
- " .\n" +
687
- "Please check that the server is up and running or your network configuration.\n" +
688
- "Err = (" +
689
- err.message +
690
- ")");
691
- this._handleUnrecoverableConnectionFailure(err, callback);
692
- }
693
- else if (err.message.match(/disconnecting/)) {
694
- /* */
695
- this._handleDisconnectionWhileConnecting(err, callback);
696
- }
697
- else {
698
- err = new Error("The connection may have been rejected by server,\n" + "Err = (" + err.message + ")");
699
- this._handleUnrecoverableConnectionFailure(err, callback);
700
- }
701
- }
702
- });
703
- }
704
- getClientNonce() {
705
- return this._secureChannel ? this._secureChannel.getClientNonce() : null;
706
- }
707
- performMessageTransaction(request, callback) {
708
- if (!this._secureChannel) {
709
- // this may happen if the Server has closed the connection abruptly for some unknown reason
710
- // or if the tcp connection has been broken.
711
- return callback(new Error("No SecureChannel , connection may have been canceled abruptly by server"));
712
- }
713
- if (this._internalState !== "connected" && this._internalState !== "connecting") {
714
- return callback(new Error("Invalid client state " + this._internalState));
715
- }
716
- (0, node_opcua_assert_1.assert)(this._secureChannel);
717
- (0, node_opcua_assert_1.assert)(request);
718
- (0, node_opcua_assert_1.assert)(request.requestHeader);
719
- (0, node_opcua_assert_1.assert)(typeof callback === "function");
720
- this._secureChannel.performMessageTransaction(request, callback);
721
- }
722
- /**
723
- *
724
- * return the endpoint information matching security mode and security policy.
725
- * @method findEndpoint
726
- */
727
- findEndpointForSecurity(securityMode, securityPolicy) {
728
- securityMode = (0, node_opcua_service_secure_channel_1.coerceMessageSecurityMode)(securityMode);
729
- securityPolicy = (0, node_opcua_secure_channel_1.coerceSecurityPolicy)(securityPolicy);
730
- (0, node_opcua_assert_1.assert)(this.knowsServerEndpoint, "Server end point are not known yet");
731
- return this._serverEndpoints.find((endpoint) => {
732
- return endpoint.securityMode === securityMode && endpoint.securityPolicyUri === securityPolicy;
733
- });
734
- }
735
- /**
736
- *
737
- * return the endpoint information matching the specified url , security mode and security policy.
738
- * @method findEndpoint
739
- */
740
- findEndpoint(endpointUrl, securityMode, securityPolicy) {
741
- (0, node_opcua_assert_1.assert)(this.knowsServerEndpoint, "Server end point are not known yet");
742
- if (!this._serverEndpoints || this._serverEndpoints.length === 0) {
743
- return undefined;
744
- }
745
- return this._serverEndpoints.find((endpoint) => {
746
- return ((0, node_opcua_utils_1.matchUri)(endpoint.endpointUrl, endpointUrl) &&
747
- endpoint.securityMode === securityMode &&
748
- endpoint.securityPolicyUri === securityPolicy);
749
- });
750
- }
751
- getEndpoints(...args) {
752
- if (args.length === 1) {
753
- return this.getEndpoints({}, args[0]);
754
- }
755
- const options = args[0];
756
- const callback = args[1];
757
- (0, node_opcua_assert_1.assert)(typeof callback === "function");
758
- options.localeIds = options.localeIds || [];
759
- options.profileUris = options.profileUris || [];
760
- const request = new node_opcua_service_endpoints_1.GetEndpointsRequest({
761
- endpointUrl: options.endpointUrl || this.endpointUrl,
762
- localeIds: options.localeIds,
763
- profileUris: options.profileUris,
764
- requestHeader: {
765
- auditEntryId: null
766
- }
767
- });
768
- this.performMessageTransaction(request, (err, response) => {
769
- this._serverEndpoints = [];
770
- if (err) {
771
- return callback(err);
772
- }
773
- // istanbul ignore next
774
- if (!response || !(response instanceof node_opcua_service_endpoints_1.GetEndpointsResponse)) {
775
- return callback(new Error("Internal Error"));
776
- }
777
- if (response && response.endpoints) {
778
- this._serverEndpoints = response.endpoints;
779
- }
780
- callback(null, this._serverEndpoints);
781
- });
782
- }
783
- /**
784
- * @deprecated
785
- */
786
- getEndpointsRequest(options, callback) {
787
- warningLog("note: ClientBaseImpl#getEndpointsRequest is deprecated, use ClientBaseImpl#getEndpoints instead");
788
- return this.getEndpoints(options, callback);
789
- }
790
- findServers(...args) {
791
- if (!this._secureChannel) {
792
- setImmediate(() => {
793
- callback(new Error("Invalid Secure Channel"));
794
- });
795
- return;
796
- }
797
- if (args.length === 1) {
798
- return this.findServers({}, args[0]);
799
- }
800
- const options = args[0];
801
- const callback = args[1];
802
- const request = new node_opcua_service_discovery_1.FindServersRequest({
803
- endpointUrl: options.endpointUrl || this.endpointUrl,
804
- localeIds: options.localeIds || [],
805
- serverUris: options.serverUris || []
806
- });
807
- this.performMessageTransaction(request, (err, response) => {
808
- if (err) {
809
- return callback(err);
810
- }
811
- /* istanbul ignore next */
812
- if (!response || !(response instanceof node_opcua_service_discovery_1.FindServersResponse)) {
813
- return callback(new Error("Internal Error"));
814
- }
815
- response.servers = response.servers || [];
816
- callback(null, response.servers);
817
- });
818
- }
819
- findServersOnNetwork(...args) {
820
- if (args.length === 1) {
821
- return this.findServersOnNetwork({}, args[0]);
822
- }
823
- const options = args[0];
824
- const callback = args[1];
825
- if (!this._secureChannel) {
826
- setImmediate(() => {
827
- callback(new Error("Invalid Secure Channel"));
828
- });
829
- return;
830
- }
831
- const request = new node_opcua_service_discovery_1.FindServersOnNetworkRequest(options);
832
- this.performMessageTransaction(request, (err, response) => {
833
- if (err) {
834
- return callback(err);
835
- }
836
- /* istanbul ignore next */
837
- if (!response || !(response instanceof node_opcua_service_discovery_1.FindServersOnNetworkResponse)) {
838
- return new Error("Internal Error");
839
- }
840
- response.servers = response.servers || [];
841
- callback(null, response.servers);
842
- });
843
- }
844
- _removeSession(session) {
845
- const index = this._sessions.indexOf(session);
846
- if (index >= 0) {
847
- const s = this._sessions.splice(index, 1)[0];
848
- (0, node_opcua_assert_1.assert)(s === session);
849
- (0, node_opcua_assert_1.assert)(session._client === this);
850
- session._client = null;
851
- }
852
- (0, node_opcua_assert_1.assert)(this._sessions.indexOf(session) === -1);
853
- }
854
- _closeSession(session, deleteSubscriptions, callback) {
855
- (0, node_opcua_assert_1.assert)(typeof callback === "function");
856
- (0, node_opcua_assert_1.assert)(typeof deleteSubscriptions === "boolean");
857
- // istanbul ignore next
858
- if (!this._secureChannel) {
859
- return callback(null); // new Error("no channel"));
860
- }
861
- (0, node_opcua_assert_1.assert)(this._secureChannel);
862
- if (!this._secureChannel.isValid()) {
863
- return callback(null);
864
- }
865
- debugLog(chalk.bgWhite.green("_closeSession ") + this._secureChannel.channelId);
866
- if (this.isReconnecting) {
867
- errorLog("OPCUAClientImpl#_closeSession called while reconnection in progress ! What shall we do");
868
- return callback(null);
869
- }
870
- const request = new node_opcua_service_session_1.CloseSessionRequest({
871
- deleteSubscriptions
872
- });
873
- session.performMessageTransaction(request, (err, response) => {
874
- if (err) {
875
- callback(err);
876
- }
877
- else {
878
- callback(err, response);
879
- }
880
- });
881
- }
882
- closeSession(...args) {
883
- const session = args[0];
884
- const deleteSubscriptions = args[1];
885
- const callback = args[2];
886
- (0, node_opcua_assert_1.assert)(typeof deleteSubscriptions === "boolean");
887
- (0, node_opcua_assert_1.assert)(typeof callback === "function");
888
- (0, node_opcua_assert_1.assert)(session);
889
- (0, node_opcua_assert_1.assert)(session._client === this, "session must be attached to this");
890
- session._closed = true;
891
- // todo : send close session on secure channel
892
- this._closeSession(session, deleteSubscriptions, (err, response) => {
893
- session.emitCloseEvent(node_opcua_status_code_1.StatusCodes.Good);
894
- this._removeSession(session);
895
- session.dispose();
896
- (0, node_opcua_assert_1.assert)(this._sessions.indexOf(session) === -1);
897
- (0, node_opcua_assert_1.assert)(session._closed, "session must indicate it is closed");
898
- callback(err ? err : undefined);
899
- });
900
- }
901
- // eslint-disable-next-line max-statements
902
- disconnect(...args) {
903
- const callback = args[0];
904
- (0, node_opcua_assert_1.assert)(typeof callback === "function", "expecting a callback function here");
905
- this.reconnectionIsCanceled = true;
906
- this.disconnecting = true;
907
- if (this._tmpClient) {
908
- this._tmpClient.disconnect((err) => {
909
- this._tmpClient = undefined;
910
- (0, node_opcua_assert_1.assert)(!this._tmpClient);
911
- // retry disconnect on main client
912
- this.disconnect(callback);
913
- });
914
- return;
915
- }
916
- debugLog("ClientBaseImpl#disconnect", this.endpointUrl);
917
- if (this.isReconnecting && !this.reconnectionIsCanceled) {
918
- debugLog("ClientBaseImpl#disconnect called while reconnection is in progress");
919
- // let's abort the reconnection process
920
- this._cancel_reconnection((err) => {
921
- debugLog("ClientBaseImpl#disconnect reconnection has been canceled", this.applicationName);
922
- (0, node_opcua_assert_1.assert)(!err, " why would this fail ?");
923
- // sessions cannot be cancelled properly and must be discarded.
924
- this.disconnect(callback);
925
- });
926
- return;
927
- }
928
- if (this._sessions.length && !this.keepPendingSessionsOnDisconnect) {
929
- debugLog("warning : disconnection : closing pending sessions");
930
- // disconnect has been called whereas living session exists
931
- // we need to close them first .... (unless keepPendingSessionsOnDisconnect)
932
- this._close_pending_sessions(( /*err*/) => {
933
- this.disconnect(callback);
934
- });
935
- return;
936
- }
937
- if (this.clientCertificateManager) {
938
- const tmp = this.clientCertificateManager;
939
- this.clientCertificateManager = null;
940
- tmp.dispose();
941
- }
942
- if (this._internalState === "disconnected" || this._internalState === "disconnecting") {
943
- return callback();
944
- }
945
- debugLog("Disconnecting !");
946
- this._setInternalState("disconnecting");
947
- if (this._sessions.length) {
948
- // transfer active session to orphan and detach them from channel
949
- const tmp = [...this._sessions];
950
- for (const session of tmp) {
951
- this._removeSession(session);
952
- }
953
- this._sessions = [];
954
- }
955
- (0, node_opcua_assert_1.assert)(this._sessions.length === 0, " attempt to disconnect a client with live sessions ");
956
- client_base_1.OPCUAClientBase.registry.unregister(this);
957
- if (this._clockAdjuster) {
958
- this._clockAdjuster.dispose();
959
- this._clockAdjuster = undefined;
960
- }
961
- if (this._secureChannel) {
962
- let tmpChannel = this._secureChannel;
963
- this._secureChannel = null;
964
- debugLog("Closing channel");
965
- tmpChannel.close(() => {
966
- this._secureChannel = tmpChannel;
967
- tmpChannel = null;
968
- this._destroy_secure_channel();
969
- this._setInternalState("disconnected");
970
- setImmediate(callback);
971
- });
972
- }
973
- else {
974
- this.emit("close", null);
975
- this._setInternalState("disconnected");
976
- setImmediate(callback);
977
- }
978
- }
979
- // override me !
980
- _on_connection_reestablished(callback) {
981
- callback();
982
- }
983
- toString() {
984
- let str = "\n";
985
- str += " defaultSecureTokenLifetime.... " + this.defaultSecureTokenLifetime + "\n";
986
- str += " securityMode.................. " + node_opcua_service_secure_channel_1.MessageSecurityMode[this.securityMode] + "\n";
987
- str += " securityPolicy................ " + this.securityPolicy.toString() + "\n";
988
- str += " certificate fingerprint....... " + (0, node_opcua_crypto_1.makeSHA1Thumbprint)(this.getCertificate()).toString("hex") + "\n";
989
- str +=
990
- " server certificate fingerprint " +
991
- (this.serverCertificate ? (0, node_opcua_crypto_1.makeSHA1Thumbprint)(this.serverCertificate).toString("hex") : "") +
992
- "\n";
993
- // this.serverCertificate = options.serverCertificate || null + "\n";
994
- str += " keepSessionAlive.............. " + this.keepSessionAlive + "\n";
995
- str += " bytesRead..................... " + this.bytesRead + "\n";
996
- str += " bytesWritten.................. " + this.bytesWritten + "\n";
997
- str += " transactionsPerformed......... " + this.transactionsPerformed + "\n";
998
- str += " timedOutRequestCount.......... " + this.timedOutRequestCount + "\n";
999
- str += " connectionStrategy." + "\n";
1000
- str += " .maxRetry............... " + this.connectionStrategy.maxRetry + "\n";
1001
- str += " .initialDelay........... " + this.connectionStrategy.initialDelay + "\n";
1002
- str += " .maxDelay............... " + this.connectionStrategy.maxDelay + "\n";
1003
- str += " .randomisationFactor.... " + this.connectionStrategy.randomisationFactor + "\n";
1004
- str += " keepSessionAlive.............. " + this.keepSessionAlive + "\n";
1005
- str += " applicationName............... " + this.applicationName + "\n";
1006
- str += " applicationUri................ " + this._getBuiltApplicationUri() + "\n";
1007
- str += " clientName.................... " + this.clientName + "\n";
1008
- if (this._secureChannel) {
1009
- str += "secureChannel:\n" + this._secureChannel.toString();
1010
- }
1011
- return str;
1012
- }
1013
- getSessions() {
1014
- return this._sessions;
1015
- }
1016
- _addSession(session) {
1017
- (0, node_opcua_assert_1.assert)(!session._client || session._client === this);
1018
- (0, node_opcua_assert_1.assert)(this._sessions.indexOf(session) === -1, "session already added");
1019
- session._client = this;
1020
- this._sessions.push(session);
1021
- if (this.keepSessionAlive) {
1022
- session.startKeepAliveManager();
1023
- }
1024
- }
1025
- fetchServerCertificate(endpointUrl, callback) {
1026
- const discoveryUrl = this.discoveryUrl.length > 0 ? this.discoveryUrl : endpointUrl;
1027
- debugLog("OPCUAClientImpl : getting serverCertificate");
1028
- // we have not been given the serverCertificate but this certificate
1029
- // is required as the connection is to be secured.
1030
- //
1031
- // Let's explore the server endpoint that matches our security settings
1032
- // This will give us the missing Certificate as well from the server.
1033
- // todo :
1034
- // Once we have the certificate, we cannot trust it straight away
1035
- // we have to verify that the certificate is valid and not outdated and not revoked.
1036
- // if the certificate is self-signed the certificate must appear in the trust certificate
1037
- // list.
1038
- // if the certificate has been certified by an Certificate Authority we have to
1039
- // verify that the certificates in the chain are valid and not revoked.
1040
- //
1041
- const certificateFile = this.certificateFile;
1042
- const privateKeyFile = this.privateKeyFile;
1043
- const applicationName = this.applicationName;
1044
- const applicationUri = this._applicationUri;
1045
- const params = {
1046
- connectionStrategy: this.connectionStrategy,
1047
- endpointMustExist: false,
1048
- securityMode: this.securityMode,
1049
- securityPolicy: this.securityPolicy,
1050
- applicationName,
1051
- applicationUri,
1052
- certificateFile,
1053
- privateKeyFile,
1054
- clientCertificateManager: this.clientCertificateManager
1055
- };
1056
- return __findEndpoint.call(this, discoveryUrl, params, (err, result) => {
1057
- if (err) {
1058
- return callback(err);
1059
- }
1060
- // istanbul ignore next
1061
- if (!result) {
1062
- const err1 = new Error("internal error");
1063
- return callback(err1);
1064
- }
1065
- const endpoint = result.selectedEndpoint;
1066
- if (!endpoint) {
1067
- // no matching end point can be found ...
1068
- const err1 = new Error("cannot find endpoint for securityMode=" +
1069
- node_opcua_service_secure_channel_1.MessageSecurityMode[this.securityMode] +
1070
- " policy = " +
1071
- this.securityPolicy);
1072
- return callback(err1);
1073
- }
1074
- (0, node_opcua_assert_1.assert)(endpoint);
1075
- _verify_serverCertificate(this.clientCertificateManager, endpoint.serverCertificate, (err1) => {
1076
- if (err1) {
1077
- warningLog("[NODE-OPCUA-W25] client's server certificate verification has failed ", err1.message);
1078
- warningLog(" ", this.clientCertificateManager.rootDir);
1079
- warningLog(" ", endpoint.serverCertificate.toString("base64").replace(/(.{80})/g, "$1\n "));
1080
- warningLog(" verify that server certificate is trusted or that server certificate issuer's certificate is present in the issuer folder");
1081
- return callback(err1);
1082
- }
1083
- this.serverCertificate = endpoint.serverCertificate;
1084
- callback(null, endpoint.endpointUrl);
1085
- });
1086
- });
1087
- }
1088
- _accumulate_statistics() {
1089
- if (this._secureChannel) {
1090
- // keep accumulated statistics
1091
- this._byteWritten += this._secureChannel.bytesWritten;
1092
- this._byteRead += this._secureChannel.bytesRead;
1093
- this._transactionsPerformed += this._secureChannel.transactionsPerformed;
1094
- this._timedOutRequestCount += this._secureChannel.timedOutRequestCount;
1095
- if (doDebug) {
1096
- debugLog(chalk.cyan(` Client ${this._instanceNumber} ${this.clientName} byteWritten = `), this._byteWritten);
1097
- debugLog(chalk.cyan(` Client ${this._instanceNumber} ${this.clientName} byteRead = `), this._byteRead);
1098
- debugLog(chalk.cyan(` Client ${this._instanceNumber} ${this.clientName} transactions = `), this._transactionsPerformed);
1099
- debugLog(chalk.cyan(` Client ${this._instanceNumber} ${this.clientName} timedOutRequestCount = `), this._timedOutRequestCount);
1100
- }
1101
- }
1102
- }
1103
- _destroy_secure_channel() {
1104
- if (this._secureChannel) {
1105
- if (doDebug) {
1106
- debugLog(" DESTROYING SECURE CHANNEL (isTransactionInProgress ?", this._secureChannel.isTransactionInProgress(), ")");
1107
- }
1108
- this._accumulate_statistics();
1109
- this._secureChannel.dispose();
1110
- this._secureChannel.removeAllListeners();
1111
- this._secureChannel = null;
1112
- }
1113
- }
1114
- _close_pending_sessions(callback) {
1115
- const sessions = [...this._sessions];
1116
- async.map(sessions, (session, next) => {
1117
- (0, node_opcua_assert_1.assert)(session._client === this);
1118
- // note: to prevent next to be call twice
1119
- let _next_already_call = false;
1120
- session.close((err) => {
1121
- if (_next_already_call) {
1122
- return;
1123
- }
1124
- _next_already_call = true;
1125
- // We should not bother if we have an error here
1126
- // Session may fail to close , if they haven't been activate and forcefully closed by server
1127
- // in a attempt to preserve resources in the case of a DDOS attack for instance.
1128
- if (err) {
1129
- const msg = session.authenticationToken ? session.authenticationToken.toString() : "";
1130
- debugLog(" failing to close session " + msg);
1131
- }
1132
- next();
1133
- });
1134
- }, (err) => {
1135
- // istanbul ignore next
1136
- if (this._sessions.length > 0) {
1137
- debugLog(this._sessions
1138
- .map((s) => (s.authenticationToken ? s.authenticationToken.toString() : ""))
1139
- .join(" "));
1140
- }
1141
- (0, node_opcua_assert_1.assert)(this._sessions.length === 0, " failed to disconnect exiting sessions ");
1142
- callback(err);
1143
- });
1144
- }
1145
- _install_secure_channel_event_handlers(secureChannel) {
1146
- (0, node_opcua_assert_1.assert)(this instanceof ClientBaseImpl);
1147
- secureChannel.on("send_chunk", (chunk) => {
1148
- /**
1149
- * notify the observer that a message_chunk has been sent
1150
- * @event send_chunk
1151
- * @param message_chunk
1152
- */
1153
- this.emit("send_chunk", chunk);
1154
- });
1155
- secureChannel.on("receive_chunk", (chunk) => {
1156
- /**
1157
- * notify the observer that a message_chunk has been received
1158
- * @event receive_chunk
1159
- * @param message_chunk
1160
- */
1161
- this.emit("receive_chunk", chunk);
1162
- });
1163
- secureChannel.on("send_request", (message) => {
1164
- /**
1165
- * notify the observer that a request has been sent to the server.
1166
- * @event send_request
1167
- * @param message
1168
- */
1169
- this.emit("send_request", message);
1170
- });
1171
- secureChannel.on("receive_response", (message) => {
1172
- /**
1173
- * notify the observer that a response has been received from the server.
1174
- * @event receive_response
1175
- * @param message
1176
- */
1177
- this.emit("receive_response", message);
1178
- });
1179
- secureChannel.on("lifetime_75", (token) => {
1180
- // secureChannel requests a new token
1181
- debugLog("SecureChannel Security Token ", token.tokenId, "live time was =", token.revisedLifetime, " is about to expired , it's time to request a new token");
1182
- // forward message to upper level
1183
- this.emit("lifetime_75", token, secureChannel);
1184
- });
1185
- secureChannel.on("security_token_renewed", () => {
1186
- // forward message to upper level
1187
- this.emit("security_token_renewed", secureChannel);
1188
- });
1189
- secureChannel.on("close", (err) => {
1190
- debugLog(chalk.yellow.bold(" ClientBaseImpl emitting close"), err === null || err === void 0 ? void 0 : err.message);
1191
- if (!err || !this.reconnectOnFailure) {
1192
- // this is a normal close operation initiated by us
1193
- /**
1194
- * @event close
1195
- * @param error
1196
- */
1197
- this.emit("close", err);
1198
- setImmediate(() => this._destroy_secure_channel());
1199
- }
1200
- else {
1201
- /**
1202
- * @event connection_lost
1203
- */
1204
- this.emit("connection_lost", err === null || err === void 0 ? void 0 : err.message); // instead of "close"
1205
- this._repairConnection();
1206
- }
1207
- });
1208
- secureChannel.on("timed_out_request", (request) => {
1209
- /**
1210
- * send when a request has timed out without receiving a response
1211
- * @event timed_out_request
1212
- * @param request
1213
- */
1214
- this.emit("timed_out_request", request);
1215
- });
1216
- }
1217
- _repairConnection() {
1218
- setImmediate(() => {
1219
- debugLog("recreating new secure channel ");
1220
- this._recreate_secure_channel((err1) => {
1221
- debugLog("secureChannel#on(close) => _recreate_secure_channel returns ", err1 ? err1.message : "OK");
1222
- if (err1) {
1223
- // xx assert(!this._secureChannel);
1224
- debugLog("_recreate_secure_channel has failed");
1225
- this.emit("close", err1);
1226
- this._setInternalState("disconnected");
1227
- return;
1228
- }
1229
- else {
1230
- this._finalReconnectionStep((err2) => {
1231
- if (err2) {
1232
- // istanbul ignore next
1233
- if (doDebug) {
1234
- debugLog("connection_reestablished has failed");
1235
- debugLog("err= ", err2);
1236
- }
1237
- this.disconnect(() => {
1238
- // we still need to retry connecting here !!!
1239
- warningLog("Disconnected following reconnection failure", err2.message);
1240
- warningLog("I will retry OPCUA client reconnection in 5 seconds");
1241
- setTimeout(() => this._repairConnection(), 5000);
1242
- });
1243
- return;
1244
- }
1245
- else {
1246
- /**
1247
- * @event connection_reestablished
1248
- * send when the connection is reestablished after a connection break
1249
- */
1250
- this.emit("connection_reestablished");
1251
- this._setInternalState("connected");
1252
- }
1253
- });
1254
- }
1255
- });
1256
- });
1257
- }
1258
- _finalReconnectionStep(callback) {
1259
- // now delegate to upper class the
1260
- if (this._on_connection_reestablished) {
1261
- (0, node_opcua_assert_1.assert)(typeof this._on_connection_reestablished === "function");
1262
- this._on_connection_reestablished((err2) => {
1263
- callback(err2);
1264
- });
1265
- }
1266
- else {
1267
- callback();
1268
- }
1269
- }
1270
- /**
1271
- *
1272
- * @internal
1273
- * @private
1274
- */
1275
- __createSession_step2(session, callback) {
1276
- throw new Error("Please override");
1277
- }
1278
- _activateSession(session, callback) {
1279
- throw new Error("Please override");
1280
- }
1281
- }
1282
- exports.ClientBaseImpl = ClientBaseImpl;
1283
- // tslint:disable-next-line: max-classes-per-file
1284
- class TmpClient extends ClientBaseImpl {
1285
- constructor(options) {
1286
- options.clientName = (options.clientName || "") + "_TmpClient";
1287
- super(options);
1288
- }
1289
- connect(endpoint, callback) {
1290
- debugLog("connecting to TmpClient");
1291
- // istanbul ignore next
1292
- if (this._internalState !== "disconnected") {
1293
- callback(new Error("TmpClient#connect: invalid internal state " + this._internalState));
1294
- return;
1295
- }
1296
- if (this.disconnecting) {
1297
- return this._handleUnrecoverableConnectionFailure(new Error("premature disconnection 3"), callback);
1298
- }
1299
- this._setInternalState("connecting");
1300
- this._connectStep2(endpoint, (err) => {
1301
- if (this.disconnecting) {
1302
- return this._handleUnrecoverableConnectionFailure(new Error("premature disconnection 4"), callback);
1303
- }
1304
- callback(err);
1305
- });
1306
- }
1307
- }
1308
- // tslint:disable:no-var-requires
1309
- // tslint:disable:max-line-length
1310
- const thenify = require("thenify");
1311
- ClientBaseImpl.prototype.connect = thenify.withCallback(ClientBaseImpl.prototype.connect);
1312
- ClientBaseImpl.prototype.disconnect = thenify.withCallback(ClientBaseImpl.prototype.disconnect);
1313
- ClientBaseImpl.prototype.getEndpoints = thenify.withCallback(ClientBaseImpl.prototype.getEndpoints);
1314
- ClientBaseImpl.prototype.findServers = thenify.withCallback(ClientBaseImpl.prototype.findServers);
1315
- ClientBaseImpl.prototype.findServersOnNetwork = thenify.withCallback(ClientBaseImpl.prototype.findServersOnNetwork);
1316
- client_base_1.OPCUAClientBase.create = (options) => {
1317
- return new ClientBaseImpl(options);
1318
- };
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.ClientBaseImpl = void 0;
13
+ /**
14
+ * @module node-opcua-client-private
15
+ */
16
+ // tslint:disable:no-unused-expression
17
+ const fs = require("fs");
18
+ const path = require("path");
19
+ const async = require("async");
20
+ const chalk = require("chalk");
21
+ const global_mutex_1 = require("@ster5/global-mutex");
22
+ const node_opcua_assert_1 = require("node-opcua-assert");
23
+ const node_opcua_common_1 = require("node-opcua-common");
24
+ const node_opcua_crypto_1 = require("node-opcua-crypto");
25
+ const node_opcua_date_time_1 = require("node-opcua-date-time");
26
+ const node_opcua_debug_1 = require("node-opcua-debug");
27
+ const node_opcua_common_2 = require("node-opcua-common");
28
+ const node_opcua_hostname_1 = require("node-opcua-hostname");
29
+ const node_opcua_secure_channel_1 = require("node-opcua-secure-channel");
30
+ const node_opcua_service_discovery_1 = require("node-opcua-service-discovery");
31
+ const node_opcua_service_endpoints_1 = require("node-opcua-service-endpoints");
32
+ const node_opcua_service_secure_channel_1 = require("node-opcua-service-secure-channel");
33
+ const node_opcua_status_code_1 = require("node-opcua-status-code");
34
+ const node_opcua_utils_1 = require("node-opcua-utils");
35
+ const node_opcua_certificate_manager_1 = require("node-opcua-certificate-manager");
36
+ const node_opcua_service_session_1 = require("node-opcua-service-session");
37
+ const client_base_1 = require("../client_base");
38
+ const verify_1 = require("../verify");
39
+ // tslint:disable-next-line:no-var-requires
40
+ const once = require("once");
41
+ const debugLog = (0, node_opcua_debug_1.make_debugLog)(__filename);
42
+ const doDebug = (0, node_opcua_debug_1.checkDebugFlag)(__filename);
43
+ const errorLog = (0, node_opcua_debug_1.make_errorLog)(__filename);
44
+ const warningLog = (0, node_opcua_debug_1.make_warningLog)(__filename);
45
+ const defaultConnectionStrategy = {
46
+ initialDelay: 1000,
47
+ maxDelay: 20 * 1000,
48
+ maxRetry: -1,
49
+ randomisationFactor: 0.1
50
+ };
51
+ function __findEndpoint(endpointUrl, params, _callback) {
52
+ const masterClient = this;
53
+ debugLog("findEndpoint : endpointUrl = ", endpointUrl);
54
+ debugLog(" params ", params);
55
+ (0, node_opcua_assert_1.assert)(!masterClient._tmpClient);
56
+ const callback = (err, result) => {
57
+ masterClient._tmpClient = undefined;
58
+ _callback(err, result);
59
+ };
60
+ const securityMode = params.securityMode;
61
+ const securityPolicy = params.securityPolicy;
62
+ const connectionStrategy = params.connectionStrategy;
63
+ const options = {
64
+ applicationName: params.applicationName,
65
+ applicationUri: params.applicationUri,
66
+ certificateFile: params.certificateFile,
67
+ clientCertificateManager: params.clientCertificateManager,
68
+ clientName: "EndpointFetcher",
69
+ connectionStrategy: {
70
+ maxRetry: 0 /* no- retry */,
71
+ maxDelay: 2000
72
+ },
73
+ privateKeyFile: params.privateKeyFile
74
+ };
75
+ const client = new TmpClient(options);
76
+ masterClient._tmpClient = client;
77
+ let selectedEndpoint;
78
+ const allEndpoints = [];
79
+ const tasks = [
80
+ (innerCallback) => {
81
+ // rebind backoff handler
82
+ masterClient.listeners("backoff").forEach((handler) => client.on("backoff", handler));
83
+ if (doDebug) {
84
+ client.on("backoff", (retryCount, delay) => {
85
+ debugLog("finding Endpoint => reconnecting ", " retry count", retryCount, " next attempt in ", delay / 1000, "seconds");
86
+ });
87
+ }
88
+ client.connect(endpointUrl, (err) => {
89
+ if (err) {
90
+ // let's improve the error message with meaningful info
91
+ err.message =
92
+ "Fail to connect to server at " +
93
+ endpointUrl +
94
+ " to collect server's certificate (in findEndpoint) \n" +
95
+ " (err =" +
96
+ err.message +
97
+ ")";
98
+ debugLog(err.message);
99
+ }
100
+ return innerCallback(err);
101
+ });
102
+ },
103
+ (innerCallback) => {
104
+ client.getEndpoints((err, endpoints) => {
105
+ if (err) {
106
+ err.message = "error in getEndpoints \n" + err.message;
107
+ return innerCallback(err);
108
+ }
109
+ // istanbul ignore next
110
+ if (!endpoints) {
111
+ return innerCallback(new Error("Internal Error"));
112
+ }
113
+ for (const endpoint of endpoints) {
114
+ if (endpoint.securityMode === securityMode && endpoint.securityPolicyUri === securityPolicy) {
115
+ if (selectedEndpoint) {
116
+ errorLog("Warning more than one endpoint matching !", endpoint.endpointUrl, selectedEndpoint.endpointUrl);
117
+ }
118
+ selectedEndpoint = endpoint; // found it
119
+ }
120
+ }
121
+ innerCallback();
122
+ });
123
+ },
124
+ (innerCallback) => {
125
+ client.disconnect(innerCallback);
126
+ }
127
+ ];
128
+ async.series(tasks, (err) => {
129
+ if (err) {
130
+ client.disconnect(() => {
131
+ callback(err);
132
+ });
133
+ return;
134
+ }
135
+ if (!selectedEndpoint) {
136
+ return callback(new Error("Cannot find an Endpoint matching " +
137
+ " security mode: " +
138
+ securityMode.toString() +
139
+ " policy: " +
140
+ securityPolicy.toString()));
141
+ }
142
+ // istanbul ignore next
143
+ if (doDebug) {
144
+ debugLog(chalk.bgWhite.red("xxxxxxxxxxxxxxxxxxxxx => selected EndPoint = "), selectedEndpoint.toString());
145
+ }
146
+ const result = {
147
+ endpoints: allEndpoints,
148
+ selectedEndpoint
149
+ };
150
+ callback(null, result);
151
+ });
152
+ }
153
+ /**
154
+ * check if certificate is trusted or untrusted
155
+ */
156
+ function _verify_serverCertificate(certificateManager, serverCertificate, callback) {
157
+ certificateManager.checkCertificate(serverCertificate, (err, status) => {
158
+ if (err) {
159
+ return callback(err);
160
+ }
161
+ if (status !== node_opcua_status_code_1.StatusCodes.Good) {
162
+ // do it again for debug purposes
163
+ if (doDebug) {
164
+ certificateManager.verifyCertificate(serverCertificate, (err1, status1) => {
165
+ debugLog(status1);
166
+ });
167
+ }
168
+ warningLog("serverCertificate = ", (0, node_opcua_crypto_1.makeSHA1Thumbprint)(serverCertificate).toString("hex"));
169
+ warningLog("serverCertificate = ", serverCertificate.toString("base64"));
170
+ return callback(new Error("server Certificate verification failed with err " + (status === null || status === void 0 ? void 0 : status.toString())));
171
+ }
172
+ callback();
173
+ });
174
+ }
175
+ const forceEndpointDiscoveryOnConnect = !!parseInt(process.env.NODEOPCUA_CLIENT_FORCE_ENDPOINT_DISCOVERY || "0", 10);
176
+ debugLog("forceEndpointDiscoveryOnConnect = ", forceEndpointDiscoveryOnConnect);
177
+ class ClockAdjustment {
178
+ constructor() {
179
+ debugLog("installPeriodicClockAdjustment ", node_opcua_date_time_1.periodicClockAdjustment.timerInstallationCount);
180
+ (0, node_opcua_date_time_1.installPeriodicClockAdjustment)();
181
+ }
182
+ dispose() {
183
+ (0, node_opcua_date_time_1.uninstallPeriodicClockAdjustment)();
184
+ debugLog("uninstallPeriodicClockAdjustment ", node_opcua_date_time_1.periodicClockAdjustment.timerInstallationCount);
185
+ }
186
+ }
187
+ /*
188
+ * "disconnected" ---[connect]----------------------> "connecting"
189
+ *
190
+ * "connecting" ---[(connection successful)]------> "connected"
191
+ *
192
+ * "connecting" ---[(connection failure)]---------> "disconnected"
193
+ *
194
+ * "connecting" ---[disconnect]-------------------> "disconnecting" --> "disconnected"
195
+ *
196
+ * "connecting" ---[lost of connection]-----------> "reconnecting" ->[reconnection]
197
+ *
198
+ * "reconnecting" ---[reconnection successful]------> "connected"
199
+ *
200
+ * "reconnecting" ---[reconnection failure]---------> [reconnection] ---> "reconnecting"
201
+ *
202
+ * "reconnecting" ---[disconnect]-------------------> "disconnecting" --> "disconnected"
203
+ */
204
+ let g_ClientCounter = 0;
205
+ /**
206
+ * @internal
207
+ */
208
+ // tslint:disable-next-line: max-classes-per-file
209
+ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
210
+ constructor(options) {
211
+ options = options || {};
212
+ if (!options.clientCertificateManager) {
213
+ options.clientCertificateManager = (0, node_opcua_certificate_manager_1.getDefaultCertificateManager)("PKI");
214
+ }
215
+ options.privateKeyFile = options.privateKeyFile || options.clientCertificateManager.privateKey;
216
+ options.certificateFile =
217
+ options.certificateFile || path.join(options.clientCertificateManager.rootDir, "own/certs/client_certificate.pem");
218
+ super(options);
219
+ this._instanceNumber = g_ClientCounter++;
220
+ this._internalState = "uninitialized";
221
+ this.applicationName = options.applicationName || "NodeOPCUA-Client";
222
+ (0, node_opcua_assert_1.assert)(!this.applicationName.match(/^locale=/), "applicationName badly converted from LocalizedText");
223
+ (0, node_opcua_assert_1.assert)(!this.applicationName.match(/urn:/), "applicationName should not be a URI");
224
+ // we need to delay _applicationUri initialization
225
+ this._applicationUri = options.applicationUri || this._getBuiltApplicationUri();
226
+ this.disconnecting = false;
227
+ this.clientCertificateManager = options.clientCertificateManager;
228
+ this._secureChannel = null;
229
+ this.reconnectionIsCanceled = false;
230
+ this.endpointUrl = "";
231
+ this.clientName = options.clientName || "ClientSession";
232
+ // must be ZERO with Spec 1.0.2
233
+ this.protocolVersion = 0;
234
+ this._sessions = [];
235
+ this._serverEndpoints = [];
236
+ this.defaultSecureTokenLifetime = options.defaultSecureTokenLifetime || 600000;
237
+ this.tokenRenewalInterval = options.tokenRenewalInterval || 0;
238
+ (0, node_opcua_assert_1.assert)(isFinite(this.tokenRenewalInterval) && this.tokenRenewalInterval >= 0);
239
+ this.securityMode = (0, node_opcua_service_secure_channel_1.coerceMessageSecurityMode)(options.securityMode);
240
+ this.securityPolicy = (0, node_opcua_secure_channel_1.coerceSecurityPolicy)(options.securityPolicy);
241
+ this.serverCertificate = options.serverCertificate;
242
+ this.keepSessionAlive = typeof options.keepSessionAlive === "boolean" ? options.keepSessionAlive : false;
243
+ // statistics...
244
+ this._byteRead = 0;
245
+ this._byteWritten = 0;
246
+ this._transactionsPerformed = 0;
247
+ this._timedOutRequestCount = 0;
248
+ this.connectionStrategy = (0, node_opcua_secure_channel_1.coerceConnectionStrategy)(options.connectionStrategy || defaultConnectionStrategy);
249
+ /***
250
+ * @property keepPendingSessionsOnDisconnect²
251
+ * @type {boolean}
252
+ */
253
+ this.keepPendingSessionsOnDisconnect = options.keepPendingSessionsOnDisconnect || false;
254
+ this.discoveryUrl = options.discoveryUrl || "";
255
+ this._setInternalState("disconnected");
256
+ }
257
+ /**
258
+ * total number of requests that been canceled due to timeout
259
+ * @property timedOutRequestCount
260
+ * @type {Number}
261
+ */
262
+ get timedOutRequestCount() {
263
+ return this._timedOutRequestCount + (this._secureChannel ? this._secureChannel.timedOutRequestCount : 0);
264
+ }
265
+ /**
266
+ * total number of transactions performed by the client
267
+ * @property transactionsPerformed
268
+ * @type {Number}
269
+ */
270
+ get transactionsPerformed() {
271
+ return this._transactionsPerformed + (this._secureChannel ? this._secureChannel.transactionsPerformed : 0);
272
+ }
273
+ /**
274
+ * is true when the client has already requested the server end points.
275
+ * @property knowsServerEndpoint
276
+ * @type boolean
277
+ */
278
+ get knowsServerEndpoint() {
279
+ return this._serverEndpoints && this._serverEndpoints.length > 0;
280
+ }
281
+ /**
282
+ * true if the client is trying to reconnect to the server after a connection break.
283
+ * @property isReconnecting
284
+ * @type {Boolean}
285
+ */
286
+ get isReconnecting() {
287
+ return !!(this._secureChannel && this._secureChannel.isConnecting) || this._internalState !== "connected";
288
+ }
289
+ /**
290
+ * true if the connection strategy is set to automatically try to reconnect in case of failure
291
+ * @property reconnectOnFailure
292
+ * @type {Boolean}
293
+ */
294
+ get reconnectOnFailure() {
295
+ return this.connectionStrategy.maxRetry > 0 || this.connectionStrategy.maxRetry === -1;
296
+ }
297
+ /**
298
+ * total number of bytes read by the client
299
+ * @property bytesRead
300
+ * @type {Number}
301
+ */
302
+ get bytesRead() {
303
+ return this._byteRead + (this._secureChannel ? this._secureChannel.bytesRead : 0);
304
+ }
305
+ /**
306
+ * total number of bytes written by the client
307
+ * @property bytesWritten
308
+ * @type {Number}
309
+ */
310
+ get bytesWritten() {
311
+ return this._byteWritten + (this._secureChannel ? this._secureChannel.bytesWritten : 0);
312
+ }
313
+ _setInternalState(internalState) {
314
+ const previousState = this._internalState;
315
+ if (doDebug) {
316
+ debugLog(chalk.cyan(` Client ${this._instanceNumber} ${this.clientName} from `), chalk.yellow(previousState), "to", chalk.yellow(internalState));
317
+ }
318
+ this._internalState = internalState;
319
+ }
320
+ emit(eventName, ...others) {
321
+ if (doDebug) {
322
+ debugLog(chalk.cyan(` Client ${this._instanceNumber} ${this.clientName} emitting `), chalk.magentaBright(eventName));
323
+ }
324
+ return super.emit(eventName, ...others);
325
+ }
326
+ _cancel_reconnection(callback) {
327
+ // _cancel_reconnection is invoked during disconnection
328
+ // when we detect that a reconnection is in progress..
329
+ (0, node_opcua_assert_1.assert)(this.isReconnecting);
330
+ this.reconnectionIsCanceled = true;
331
+ // istanbul ignore next
332
+ if (!this._secureChannel) {
333
+ debugLog("_cancel_reconnection: Nothing to do !");
334
+ return callback(); // nothing to do
335
+ }
336
+ this._secureChannel.abortConnection(( /*err?: Error*/) => {
337
+ this._secureChannel = null;
338
+ callback();
339
+ });
340
+ this.once("reconnection_canceled", () => {
341
+ /* empty */
342
+ });
343
+ }
344
+ _recreate_secure_channel(callback) {
345
+ debugLog("_recreate_secure_channel...", this._internalState);
346
+ if (!this.knowsServerEndpoint) {
347
+ debugLog("Cannot reconnect , server endpoint is unknown");
348
+ return callback(new Error("Cannot reconnect, server endpoint is unknown"));
349
+ }
350
+ (0, node_opcua_assert_1.assert)(this.knowsServerEndpoint);
351
+ // xx ??? assert(!this.isReconnecting);
352
+ /**
353
+ * notifies the observer that the OPCUA is now trying to reestablish the connection
354
+ * after having received a connection break...
355
+ * @event start_reconnection
356
+ *
357
+ */
358
+ this._setInternalState("reconnecting");
359
+ this.emit("start_reconnection"); // send after callback
360
+ this._destroy_secure_channel();
361
+ (0, node_opcua_assert_1.assert)(!this._secureChannel);
362
+ const infiniteConnectionRetry = {
363
+ initialDelay: this.connectionStrategy.initialDelay,
364
+ maxDelay: this.connectionStrategy.maxDelay,
365
+ maxRetry: -1
366
+ };
367
+ const failAndRetry = (err, message) => {
368
+ debugLog("failAndRetry; ", message);
369
+ if (this.reconnectionIsCanceled) {
370
+ this.emit("reconnection_canceled");
371
+ return callback(new Error("Reconnection has been canceled - " + this.clientName));
372
+ }
373
+ warningLog("client = ", this.clientName, message, err.message);
374
+ // else
375
+ // let retry a little bit later
376
+ this.emit("reconnection_attempt_has_failed", err, message); // send after callback
377
+ setTimeout(_attempt_to_recreate_secure_channel, 100);
378
+ };
379
+ const _attempt_to_recreate_secure_channel = () => {
380
+ if (this.reconnectionIsCanceled) {
381
+ this.emit("reconnection_canceled");
382
+ return callback(new Error("Reconnection has been canceled - " + this.clientName));
383
+ }
384
+ this._internal_create_secure_channel(infiniteConnectionRetry, (err) => {
385
+ if (err) {
386
+ if (err.message.match(/ECONNREFUSED|ECONNABORTED/)) {
387
+ return callback(err);
388
+ }
389
+ if (err.message.match("Backoff aborted.")) {
390
+ return failAndRetry(err, "cannot create secure channel (backoff aborted)");
391
+ }
392
+ if (err.message.match("BadCertificateInvalid") ||
393
+ err.message.match(/_socket has been disconnected by third party/)) {
394
+ warningLog("the server certificate has changed, we need to retrieve server certificate again: ", err.message);
395
+ warningLog("old server certificate ", this.serverCertificate ? (0, node_opcua_crypto_1.makeSHA1Thumbprint)(this.serverCertificate).toString("hex") : "undefined");
396
+ // the server may have shut down the channel because its certificate
397
+ // has changed ....
398
+ // let request the server certificate again ....
399
+ debugLog(chalk.bgWhite.red("ClientBaseImpl: Server Certificate has changed." + " we need to retrieve server certificate again"));
400
+ return this.fetchServerCertificate(this.endpointUrl, (err1) => {
401
+ if (err1) {
402
+ errorLog("Failing to fetch new server certificate: ", err1.message);
403
+ return failAndRetry(err1, "trying to fetch new server certificate");
404
+ }
405
+ warningLog("new server certificate ", (0, node_opcua_crypto_1.makeSHA1Thumbprint)(this.serverCertificate).toString("hex"));
406
+ this._internal_create_secure_channel(infiniteConnectionRetry, (err3) => {
407
+ if (err3) {
408
+ return failAndRetry(err3, "trying to create new channel with new certificate");
409
+ }
410
+ this._setInternalState("connected");
411
+ this.emit("connected");
412
+ callback();
413
+ });
414
+ });
415
+ }
416
+ debugLog(chalk.bgWhite.red("ClientBaseImpl: cannot reconnect .."));
417
+ failAndRetry(err, "cannot create secure channel");
418
+ }
419
+ else {
420
+ /**
421
+ * notify the observers that the reconnection process has been completed
422
+ * @event after_reconnection
423
+ * @param err
424
+ */
425
+ this.emit("after_reconnection", err); // send after callback
426
+ (0, node_opcua_assert_1.assert)(this._secureChannel, "expecting a secureChannel here ");
427
+ // a new channel has be created and a new connection is established
428
+ debugLog(chalk.bgWhite.red("ClientBaseImpl: RECONNECTED !!!"));
429
+ this._setInternalState("connected");
430
+ return callback();
431
+ }
432
+ });
433
+ };
434
+ // create a secure channel
435
+ // a new secure channel must be established
436
+ setImmediate(() => {
437
+ _attempt_to_recreate_secure_channel();
438
+ });
439
+ }
440
+ _internal_create_secure_channel(connectionStrategy, callback) {
441
+ (0, node_opcua_assert_1.assert)(this._secureChannel === null);
442
+ (0, node_opcua_assert_1.assert)(typeof this.endpointUrl === "string");
443
+ debugLog("_internal_create_secure_channel creating new ClientSecureChannelLayer");
444
+ const secureChannel = new node_opcua_secure_channel_1.ClientSecureChannelLayer({
445
+ connectionStrategy,
446
+ defaultSecureTokenLifetime: this.defaultSecureTokenLifetime,
447
+ parent: this,
448
+ securityMode: this.securityMode,
449
+ securityPolicy: this.securityPolicy,
450
+ serverCertificate: this.serverCertificate,
451
+ tokenRenewalInterval: this.tokenRenewalInterval
452
+ });
453
+ secureChannel.protocolVersion = this.protocolVersion;
454
+ this._secureChannel = secureChannel;
455
+ async.series([
456
+ // ------------------------------------------------- STEP 2 : OpenSecureChannel
457
+ (_innerCallback) => {
458
+ debugLog("_internal_create_secure_channel before secureChannel.create");
459
+ secureChannel.create(this.endpointUrl, (err) => {
460
+ debugLog("_internal_create_secure_channel after secureChannel.create");
461
+ if (!this._secureChannel) {
462
+ debugLog("_secureChannel has been closed during the transaction !");
463
+ return _innerCallback(new Error("Secure Channel Closed"));
464
+ }
465
+ if (err) {
466
+ debugLog(chalk.yellow("Cannot create secureChannel"), err.message ? chalk.cyan(err.message) : "");
467
+ this._destroy_secure_channel();
468
+ }
469
+ else {
470
+ (0, node_opcua_assert_1.assert)(this._secureChannel !== null);
471
+ this._install_secure_channel_event_handlers(secureChannel);
472
+ }
473
+ _innerCallback(err);
474
+ });
475
+ secureChannel.on("backoff", (count, delay) => {
476
+ this.emit("backoff", count, delay);
477
+ });
478
+ secureChannel.on("abort", () => {
479
+ this.emit("abort");
480
+ });
481
+ },
482
+ // ------------------------------------------------- STEP 3 : GetEndpointsRequest
483
+ (innerCallback) => {
484
+ (0, node_opcua_assert_1.assert)(this._secureChannel !== null);
485
+ if (!this.knowsServerEndpoint) {
486
+ this.getEndpoints((err /*, endpoints?: EndpointDescription[]*/) => {
487
+ if (this._secureChannel === null) {
488
+ (0, node_opcua_assert_1.assert)(this.disconnecting);
489
+ innerCallback(new Error("disconnecting"));
490
+ }
491
+ innerCallback(err ? err : undefined);
492
+ });
493
+ }
494
+ else {
495
+ // end points are already known
496
+ innerCallback();
497
+ }
498
+ }
499
+ ], (err) => {
500
+ if (err) {
501
+ debugLog("Inner create secure channel has failed", err.message);
502
+ this._secureChannel = null;
503
+ callback(err);
504
+ }
505
+ else {
506
+ (0, node_opcua_assert_1.assert)(this._secureChannel !== null);
507
+ callback(null, secureChannel);
508
+ }
509
+ });
510
+ }
511
+ static createCertificate(clientCertificateManager, certificateFile, applicationName, applicationUri) {
512
+ return __awaiter(this, void 0, void 0, function* () {
513
+ if (!fs.existsSync(certificateFile)) {
514
+ const hostname = (0, node_opcua_hostname_1.getHostname)();
515
+ // this.serverInfo.applicationUri!;
516
+ yield clientCertificateManager.createSelfSignedCertificate({
517
+ applicationUri,
518
+ dns: [hostname],
519
+ // ip: await getIpAddresses(),
520
+ outputFile: certificateFile,
521
+ subject: (0, node_opcua_certificate_manager_1.makeSubject)(applicationName, hostname),
522
+ startDate: new Date(),
523
+ validity: 365 * 10 // 10 years
524
+ });
525
+ }
526
+ // istanbul ignore next
527
+ if (!fs.existsSync(certificateFile)) {
528
+ throw new Error(" cannot locate certificate file " + certificateFile);
529
+ }
530
+ });
531
+ }
532
+ createDefaultCertificate() {
533
+ return __awaiter(this, void 0, void 0, function* () {
534
+ // istanbul ignore next
535
+ if (this._inCreateDefaultCertificate) {
536
+ errorLog("Internal error : re-entrancy in createDefaultCertificate!");
537
+ }
538
+ this._inCreateDefaultCertificate = true;
539
+ if (!fs.existsSync(this.certificateFile)) {
540
+ const lockfile = path.join(this.certificateFile + ".lock");
541
+ yield (0, global_mutex_1.withLock)({ lockfile: lockfile, maxStaleDuration: 60 * 1000, retryInterval: 100 }, () => __awaiter(this, void 0, void 0, function* () {
542
+ if (this.disconnecting)
543
+ return;
544
+ yield ClientBaseImpl.createCertificate(this.clientCertificateManager, this.certificateFile, this.applicationName, this._getBuiltApplicationUri());
545
+ debugLog("privateKey = ", this.privateKeyFile);
546
+ debugLog(" = ", this.clientCertificateManager.privateKey);
547
+ debugLog("certificateFile = ", this.certificateFile);
548
+ const certificate = this.getCertificate();
549
+ const privateKey = this.getPrivateKey();
550
+ }));
551
+ }
552
+ this._inCreateDefaultCertificate = false;
553
+ });
554
+ }
555
+ _getBuiltApplicationUri() {
556
+ if (!this._applicationUri) {
557
+ this._applicationUri = (0, node_opcua_common_2.makeApplicationUrn)((0, node_opcua_hostname_1.getHostname)(), this.applicationName);
558
+ }
559
+ return this._applicationUri;
560
+ }
561
+ initializeCM() {
562
+ return __awaiter(this, void 0, void 0, function* () {
563
+ if (!this.clientCertificateManager) {
564
+ return;
565
+ }
566
+ yield this.clientCertificateManager.initialize();
567
+ yield this.createDefaultCertificate();
568
+ // istanbul ignore next
569
+ if (!fs.existsSync(this.privateKeyFile)) {
570
+ throw new Error(" cannot locate private key file " + this.privateKeyFile);
571
+ }
572
+ if (this.disconnecting)
573
+ return;
574
+ const lockfile = path.join(this.certificateFile + ".lock");
575
+ yield (0, global_mutex_1.withLock)({ lockfile: lockfile, maxStaleDuration: 60 * 1000, retryInterval: 100 }, () => __awaiter(this, void 0, void 0, function* () {
576
+ if (this.disconnecting)
577
+ return;
578
+ yield verify_1.performCertificateSanityCheck.call(this, "client", this.clientCertificateManager, this._getBuiltApplicationUri());
579
+ }));
580
+ });
581
+ }
582
+ _handleUnrecoverableConnectionFailure(err, callback) {
583
+ debugLog(err.message);
584
+ this.emit("connection_failed");
585
+ this._setInternalState("disconnected");
586
+ return callback(err);
587
+ }
588
+ _handleDisconnectionWhileConnecting(err, callback) {
589
+ debugLog(err.message);
590
+ this.emit("connection_failed");
591
+ this._setInternalState("disconnected");
592
+ return callback(err);
593
+ }
594
+ _handleSuccessfulConnection(callback) {
595
+ debugLog(" Connected successfully to ", this.endpointUrl);
596
+ this.emit("connected");
597
+ this._setInternalState("connected");
598
+ callback();
599
+ }
600
+ connect(...args) {
601
+ const endpointUrl = args[0];
602
+ const callback = args[1];
603
+ (0, node_opcua_assert_1.assert)(typeof callback === "function", "expecting a callback");
604
+ if (typeof endpointUrl !== "string" || endpointUrl.length <= 0) {
605
+ errorLog("[NODE-OPCUA-E03] OPCUAClient#connect expects a valid endpoint : " + endpointUrl);
606
+ callback(new Error("Invalid endpoint"));
607
+ return;
608
+ }
609
+ (0, node_opcua_assert_1.assert)(typeof endpointUrl === "string" && endpointUrl.length > 0);
610
+ // istanbul ignore next
611
+ if (this._internalState !== "disconnected") {
612
+ callback(new Error("invalid internal state = " + this._internalState));
613
+ return;
614
+ }
615
+ // prevent illegal call to connect
616
+ if (this._secureChannel !== null) {
617
+ setImmediate(() => callback(new Error("connect already called")));
618
+ return;
619
+ }
620
+ this._setInternalState("connecting");
621
+ this.disconnecting = false;
622
+ this.initializeCM()
623
+ .then(() => {
624
+ debugLog("ClientBaseImpl#connect ", endpointUrl);
625
+ if (this.disconnecting) {
626
+ return this._handleDisconnectionWhileConnecting(new Error("premature disconnection 1"), callback);
627
+ }
628
+ if (!this.serverCertificate &&
629
+ (forceEndpointDiscoveryOnConnect || this.securityMode !== node_opcua_service_secure_channel_1.MessageSecurityMode.None)) {
630
+ debugLog("Fetching certificates from endpoints");
631
+ this.fetchServerCertificate(endpointUrl, (err, adjustedEndpointUrl) => {
632
+ if (err) {
633
+ return this._handleUnrecoverableConnectionFailure(err, callback);
634
+ }
635
+ if (this.disconnecting) {
636
+ return this._handleDisconnectionWhileConnecting(new Error("premature disconnection 2"), callback);
637
+ }
638
+ if (forceEndpointDiscoveryOnConnect) {
639
+ debugLog("connecting with adjusted endpoint : ", adjustedEndpointUrl, " was =", endpointUrl);
640
+ this._connectStep2(adjustedEndpointUrl, callback);
641
+ }
642
+ else {
643
+ debugLog("connecting with endpoint : ", endpointUrl);
644
+ this._connectStep2(endpointUrl, callback);
645
+ }
646
+ });
647
+ }
648
+ else {
649
+ this._connectStep2(endpointUrl, callback);
650
+ }
651
+ })
652
+ .catch((err) => {
653
+ return this._handleUnrecoverableConnectionFailure(err, callback);
654
+ });
655
+ }
656
+ /**
657
+ * @private
658
+ */
659
+ _connectStep2(endpointUrl, callback) {
660
+ // prevent illegal call to connect
661
+ (0, node_opcua_assert_1.assert)(this._secureChannel === null);
662
+ this.endpointUrl = endpointUrl;
663
+ this._clockAdjuster = this._clockAdjuster || new ClockAdjustment();
664
+ client_base_1.OPCUAClientBase.registry.register(this);
665
+ debugLog("__connectStep2");
666
+ this._internal_create_secure_channel(this.connectionStrategy, (err) => {
667
+ if (!err) {
668
+ this._handleSuccessfulConnection(callback);
669
+ }
670
+ else {
671
+ client_base_1.OPCUAClientBase.registry.unregister(this);
672
+ if (this._clockAdjuster) {
673
+ this._clockAdjuster.dispose();
674
+ this._clockAdjuster = undefined;
675
+ }
676
+ debugLog(chalk.red("SecureChannel creation has failed with error :", err.message));
677
+ if (err.message.match(/ECONNABORTED/)) {
678
+ debugLog(chalk.yellow("- The client cannot to :" + endpointUrl + ". Connection has been aborted."));
679
+ err = new Error("The connection has been aborted");
680
+ this._handleUnrecoverableConnectionFailure(err, callback);
681
+ }
682
+ else if (err.message.match(/ECONNREF/)) {
683
+ debugLog(chalk.yellow("- The client cannot to :" + endpointUrl + ". Server is not reachable."));
684
+ err = new Error("The connection cannot be established with server " +
685
+ endpointUrl +
686
+ " .\n" +
687
+ "Please check that the server is up and running or your network configuration.\n" +
688
+ "Err = (" +
689
+ err.message +
690
+ ")");
691
+ this._handleUnrecoverableConnectionFailure(err, callback);
692
+ }
693
+ else if (err.message.match(/disconnecting/)) {
694
+ /* */
695
+ this._handleDisconnectionWhileConnecting(err, callback);
696
+ }
697
+ else {
698
+ err = new Error("The connection may have been rejected by server,\n" + "Err = (" + err.message + ")");
699
+ this._handleUnrecoverableConnectionFailure(err, callback);
700
+ }
701
+ }
702
+ });
703
+ }
704
+ getClientNonce() {
705
+ return this._secureChannel ? this._secureChannel.getClientNonce() : null;
706
+ }
707
+ performMessageTransaction(request, callback) {
708
+ if (!this._secureChannel) {
709
+ // this may happen if the Server has closed the connection abruptly for some unknown reason
710
+ // or if the tcp connection has been broken.
711
+ return callback(new Error("No SecureChannel , connection may have been canceled abruptly by server"));
712
+ }
713
+ if (this._internalState !== "connected" && this._internalState !== "connecting") {
714
+ return callback(new Error("Invalid client state " + this._internalState));
715
+ }
716
+ (0, node_opcua_assert_1.assert)(this._secureChannel);
717
+ (0, node_opcua_assert_1.assert)(request);
718
+ (0, node_opcua_assert_1.assert)(request.requestHeader);
719
+ (0, node_opcua_assert_1.assert)(typeof callback === "function");
720
+ this._secureChannel.performMessageTransaction(request, callback);
721
+ }
722
+ /**
723
+ *
724
+ * return the endpoint information matching security mode and security policy.
725
+ * @method findEndpoint
726
+ */
727
+ findEndpointForSecurity(securityMode, securityPolicy) {
728
+ securityMode = (0, node_opcua_service_secure_channel_1.coerceMessageSecurityMode)(securityMode);
729
+ securityPolicy = (0, node_opcua_secure_channel_1.coerceSecurityPolicy)(securityPolicy);
730
+ (0, node_opcua_assert_1.assert)(this.knowsServerEndpoint, "Server end point are not known yet");
731
+ return this._serverEndpoints.find((endpoint) => {
732
+ return endpoint.securityMode === securityMode && endpoint.securityPolicyUri === securityPolicy;
733
+ });
734
+ }
735
+ /**
736
+ *
737
+ * return the endpoint information matching the specified url , security mode and security policy.
738
+ * @method findEndpoint
739
+ */
740
+ findEndpoint(endpointUrl, securityMode, securityPolicy) {
741
+ (0, node_opcua_assert_1.assert)(this.knowsServerEndpoint, "Server end point are not known yet");
742
+ if (!this._serverEndpoints || this._serverEndpoints.length === 0) {
743
+ return undefined;
744
+ }
745
+ return this._serverEndpoints.find((endpoint) => {
746
+ return ((0, node_opcua_utils_1.matchUri)(endpoint.endpointUrl, endpointUrl) &&
747
+ endpoint.securityMode === securityMode &&
748
+ endpoint.securityPolicyUri === securityPolicy);
749
+ });
750
+ }
751
+ getEndpoints(...args) {
752
+ if (args.length === 1) {
753
+ return this.getEndpoints({}, args[0]);
754
+ }
755
+ const options = args[0];
756
+ const callback = args[1];
757
+ (0, node_opcua_assert_1.assert)(typeof callback === "function");
758
+ options.localeIds = options.localeIds || [];
759
+ options.profileUris = options.profileUris || [];
760
+ const request = new node_opcua_service_endpoints_1.GetEndpointsRequest({
761
+ endpointUrl: options.endpointUrl || this.endpointUrl,
762
+ localeIds: options.localeIds,
763
+ profileUris: options.profileUris,
764
+ requestHeader: {
765
+ auditEntryId: null
766
+ }
767
+ });
768
+ this.performMessageTransaction(request, (err, response) => {
769
+ this._serverEndpoints = [];
770
+ if (err) {
771
+ return callback(err);
772
+ }
773
+ // istanbul ignore next
774
+ if (!response || !(response instanceof node_opcua_service_endpoints_1.GetEndpointsResponse)) {
775
+ return callback(new Error("Internal Error"));
776
+ }
777
+ if (response && response.endpoints) {
778
+ this._serverEndpoints = response.endpoints;
779
+ }
780
+ callback(null, this._serverEndpoints);
781
+ });
782
+ }
783
+ /**
784
+ * @deprecated
785
+ */
786
+ getEndpointsRequest(options, callback) {
787
+ warningLog("note: ClientBaseImpl#getEndpointsRequest is deprecated, use ClientBaseImpl#getEndpoints instead");
788
+ return this.getEndpoints(options, callback);
789
+ }
790
+ findServers(...args) {
791
+ if (!this._secureChannel) {
792
+ setImmediate(() => {
793
+ callback(new Error("Invalid Secure Channel"));
794
+ });
795
+ return;
796
+ }
797
+ if (args.length === 1) {
798
+ return this.findServers({}, args[0]);
799
+ }
800
+ const options = args[0];
801
+ const callback = args[1];
802
+ const request = new node_opcua_service_discovery_1.FindServersRequest({
803
+ endpointUrl: options.endpointUrl || this.endpointUrl,
804
+ localeIds: options.localeIds || [],
805
+ serverUris: options.serverUris || []
806
+ });
807
+ this.performMessageTransaction(request, (err, response) => {
808
+ if (err) {
809
+ return callback(err);
810
+ }
811
+ /* istanbul ignore next */
812
+ if (!response || !(response instanceof node_opcua_service_discovery_1.FindServersResponse)) {
813
+ return callback(new Error("Internal Error"));
814
+ }
815
+ response.servers = response.servers || [];
816
+ callback(null, response.servers);
817
+ });
818
+ }
819
+ findServersOnNetwork(...args) {
820
+ if (args.length === 1) {
821
+ return this.findServersOnNetwork({}, args[0]);
822
+ }
823
+ const options = args[0];
824
+ const callback = args[1];
825
+ if (!this._secureChannel) {
826
+ setImmediate(() => {
827
+ callback(new Error("Invalid Secure Channel"));
828
+ });
829
+ return;
830
+ }
831
+ const request = new node_opcua_service_discovery_1.FindServersOnNetworkRequest(options);
832
+ this.performMessageTransaction(request, (err, response) => {
833
+ if (err) {
834
+ return callback(err);
835
+ }
836
+ /* istanbul ignore next */
837
+ if (!response || !(response instanceof node_opcua_service_discovery_1.FindServersOnNetworkResponse)) {
838
+ return new Error("Internal Error");
839
+ }
840
+ response.servers = response.servers || [];
841
+ callback(null, response.servers);
842
+ });
843
+ }
844
+ _removeSession(session) {
845
+ const index = this._sessions.indexOf(session);
846
+ if (index >= 0) {
847
+ const s = this._sessions.splice(index, 1)[0];
848
+ (0, node_opcua_assert_1.assert)(s === session);
849
+ (0, node_opcua_assert_1.assert)(session._client === this);
850
+ session._client = null;
851
+ }
852
+ (0, node_opcua_assert_1.assert)(this._sessions.indexOf(session) === -1);
853
+ }
854
+ _closeSession(session, deleteSubscriptions, callback) {
855
+ (0, node_opcua_assert_1.assert)(typeof callback === "function");
856
+ (0, node_opcua_assert_1.assert)(typeof deleteSubscriptions === "boolean");
857
+ // istanbul ignore next
858
+ if (!this._secureChannel) {
859
+ return callback(null); // new Error("no channel"));
860
+ }
861
+ (0, node_opcua_assert_1.assert)(this._secureChannel);
862
+ if (!this._secureChannel.isValid()) {
863
+ return callback(null);
864
+ }
865
+ debugLog(chalk.bgWhite.green("_closeSession ") + this._secureChannel.channelId);
866
+ if (this.isReconnecting) {
867
+ errorLog("OPCUAClientImpl#_closeSession called while reconnection in progress ! What shall we do");
868
+ return callback(null);
869
+ }
870
+ const request = new node_opcua_service_session_1.CloseSessionRequest({
871
+ deleteSubscriptions
872
+ });
873
+ session.performMessageTransaction(request, (err, response) => {
874
+ if (err) {
875
+ callback(err);
876
+ }
877
+ else {
878
+ callback(err, response);
879
+ }
880
+ });
881
+ }
882
+ closeSession(...args) {
883
+ const session = args[0];
884
+ const deleteSubscriptions = args[1];
885
+ const callback = args[2];
886
+ (0, node_opcua_assert_1.assert)(typeof deleteSubscriptions === "boolean");
887
+ (0, node_opcua_assert_1.assert)(typeof callback === "function");
888
+ (0, node_opcua_assert_1.assert)(session);
889
+ (0, node_opcua_assert_1.assert)(session._client === this, "session must be attached to this");
890
+ session._closed = true;
891
+ // todo : send close session on secure channel
892
+ this._closeSession(session, deleteSubscriptions, (err, response) => {
893
+ session.emitCloseEvent(node_opcua_status_code_1.StatusCodes.Good);
894
+ this._removeSession(session);
895
+ session.dispose();
896
+ (0, node_opcua_assert_1.assert)(this._sessions.indexOf(session) === -1);
897
+ (0, node_opcua_assert_1.assert)(session._closed, "session must indicate it is closed");
898
+ callback(err ? err : undefined);
899
+ });
900
+ }
901
+ // eslint-disable-next-line max-statements
902
+ disconnect(...args) {
903
+ const callback = args[0];
904
+ (0, node_opcua_assert_1.assert)(typeof callback === "function", "expecting a callback function here");
905
+ this.reconnectionIsCanceled = true;
906
+ this.disconnecting = true;
907
+ if (this._tmpClient) {
908
+ this._tmpClient.disconnect((err) => {
909
+ this._tmpClient = undefined;
910
+ (0, node_opcua_assert_1.assert)(!this._tmpClient);
911
+ // retry disconnect on main client
912
+ this.disconnect(callback);
913
+ });
914
+ return;
915
+ }
916
+ debugLog("ClientBaseImpl#disconnect", this.endpointUrl);
917
+ if (this.isReconnecting && !this.reconnectionIsCanceled) {
918
+ debugLog("ClientBaseImpl#disconnect called while reconnection is in progress");
919
+ // let's abort the reconnection process
920
+ this._cancel_reconnection((err) => {
921
+ debugLog("ClientBaseImpl#disconnect reconnection has been canceled", this.applicationName);
922
+ (0, node_opcua_assert_1.assert)(!err, " why would this fail ?");
923
+ // sessions cannot be cancelled properly and must be discarded.
924
+ this.disconnect(callback);
925
+ });
926
+ return;
927
+ }
928
+ if (this._sessions.length && !this.keepPendingSessionsOnDisconnect) {
929
+ debugLog("warning : disconnection : closing pending sessions");
930
+ // disconnect has been called whereas living session exists
931
+ // we need to close them first .... (unless keepPendingSessionsOnDisconnect)
932
+ this._close_pending_sessions(( /*err*/) => {
933
+ this.disconnect(callback);
934
+ });
935
+ return;
936
+ }
937
+ if (this.clientCertificateManager) {
938
+ const tmp = this.clientCertificateManager;
939
+ this.clientCertificateManager = null;
940
+ tmp.dispose();
941
+ }
942
+ if (this._internalState === "disconnected" || this._internalState === "disconnecting") {
943
+ return callback();
944
+ }
945
+ debugLog("Disconnecting !");
946
+ this._setInternalState("disconnecting");
947
+ if (this._sessions.length) {
948
+ // transfer active session to orphan and detach them from channel
949
+ const tmp = [...this._sessions];
950
+ for (const session of tmp) {
951
+ this._removeSession(session);
952
+ }
953
+ this._sessions = [];
954
+ }
955
+ (0, node_opcua_assert_1.assert)(this._sessions.length === 0, " attempt to disconnect a client with live sessions ");
956
+ client_base_1.OPCUAClientBase.registry.unregister(this);
957
+ if (this._clockAdjuster) {
958
+ this._clockAdjuster.dispose();
959
+ this._clockAdjuster = undefined;
960
+ }
961
+ if (this._secureChannel) {
962
+ let tmpChannel = this._secureChannel;
963
+ this._secureChannel = null;
964
+ debugLog("Closing channel");
965
+ tmpChannel.close(() => {
966
+ this._secureChannel = tmpChannel;
967
+ tmpChannel = null;
968
+ this._destroy_secure_channel();
969
+ this._setInternalState("disconnected");
970
+ setImmediate(callback);
971
+ });
972
+ }
973
+ else {
974
+ this.emit("close", null);
975
+ this._setInternalState("disconnected");
976
+ setImmediate(callback);
977
+ }
978
+ }
979
+ // override me !
980
+ _on_connection_reestablished(callback) {
981
+ callback();
982
+ }
983
+ toString() {
984
+ let str = "\n";
985
+ str += " defaultSecureTokenLifetime.... " + this.defaultSecureTokenLifetime + "\n";
986
+ str += " securityMode.................. " + node_opcua_service_secure_channel_1.MessageSecurityMode[this.securityMode] + "\n";
987
+ str += " securityPolicy................ " + this.securityPolicy.toString() + "\n";
988
+ str += " certificate fingerprint....... " + (0, node_opcua_crypto_1.makeSHA1Thumbprint)(this.getCertificate()).toString("hex") + "\n";
989
+ str +=
990
+ " server certificate fingerprint " +
991
+ (this.serverCertificate ? (0, node_opcua_crypto_1.makeSHA1Thumbprint)(this.serverCertificate).toString("hex") : "") +
992
+ "\n";
993
+ // this.serverCertificate = options.serverCertificate || null + "\n";
994
+ str += " keepSessionAlive.............. " + this.keepSessionAlive + "\n";
995
+ str += " bytesRead..................... " + this.bytesRead + "\n";
996
+ str += " bytesWritten.................. " + this.bytesWritten + "\n";
997
+ str += " transactionsPerformed......... " + this.transactionsPerformed + "\n";
998
+ str += " timedOutRequestCount.......... " + this.timedOutRequestCount + "\n";
999
+ str += " connectionStrategy." + "\n";
1000
+ str += " .maxRetry............... " + this.connectionStrategy.maxRetry + "\n";
1001
+ str += " .initialDelay........... " + this.connectionStrategy.initialDelay + "\n";
1002
+ str += " .maxDelay............... " + this.connectionStrategy.maxDelay + "\n";
1003
+ str += " .randomisationFactor.... " + this.connectionStrategy.randomisationFactor + "\n";
1004
+ str += " keepSessionAlive.............. " + this.keepSessionAlive + "\n";
1005
+ str += " applicationName............... " + this.applicationName + "\n";
1006
+ str += " applicationUri................ " + this._getBuiltApplicationUri() + "\n";
1007
+ str += " clientName.................... " + this.clientName + "\n";
1008
+ if (this._secureChannel) {
1009
+ str += "secureChannel:\n" + this._secureChannel.toString();
1010
+ }
1011
+ return str;
1012
+ }
1013
+ getSessions() {
1014
+ return this._sessions;
1015
+ }
1016
+ _addSession(session) {
1017
+ (0, node_opcua_assert_1.assert)(!session._client || session._client === this);
1018
+ (0, node_opcua_assert_1.assert)(this._sessions.indexOf(session) === -1, "session already added");
1019
+ session._client = this;
1020
+ this._sessions.push(session);
1021
+ }
1022
+ fetchServerCertificate(endpointUrl, callback) {
1023
+ const discoveryUrl = this.discoveryUrl.length > 0 ? this.discoveryUrl : endpointUrl;
1024
+ debugLog("OPCUAClientImpl : getting serverCertificate");
1025
+ // we have not been given the serverCertificate but this certificate
1026
+ // is required as the connection is to be secured.
1027
+ //
1028
+ // Let's explore the server endpoint that matches our security settings
1029
+ // This will give us the missing Certificate as well from the server.
1030
+ // todo :
1031
+ // Once we have the certificate, we cannot trust it straight away
1032
+ // we have to verify that the certificate is valid and not outdated and not revoked.
1033
+ // if the certificate is self-signed the certificate must appear in the trust certificate
1034
+ // list.
1035
+ // if the certificate has been certified by an Certificate Authority we have to
1036
+ // verify that the certificates in the chain are valid and not revoked.
1037
+ //
1038
+ const certificateFile = this.certificateFile;
1039
+ const privateKeyFile = this.privateKeyFile;
1040
+ const applicationName = this.applicationName;
1041
+ const applicationUri = this._applicationUri;
1042
+ const params = {
1043
+ connectionStrategy: this.connectionStrategy,
1044
+ endpointMustExist: false,
1045
+ securityMode: this.securityMode,
1046
+ securityPolicy: this.securityPolicy,
1047
+ applicationName,
1048
+ applicationUri,
1049
+ certificateFile,
1050
+ privateKeyFile,
1051
+ clientCertificateManager: this.clientCertificateManager
1052
+ };
1053
+ return __findEndpoint.call(this, discoveryUrl, params, (err, result) => {
1054
+ if (err) {
1055
+ return callback(err);
1056
+ }
1057
+ // istanbul ignore next
1058
+ if (!result) {
1059
+ const err1 = new Error("internal error");
1060
+ return callback(err1);
1061
+ }
1062
+ const endpoint = result.selectedEndpoint;
1063
+ if (!endpoint) {
1064
+ // no matching end point can be found ...
1065
+ const err1 = new Error("cannot find endpoint for securityMode=" +
1066
+ node_opcua_service_secure_channel_1.MessageSecurityMode[this.securityMode] +
1067
+ " policy = " +
1068
+ this.securityPolicy);
1069
+ return callback(err1);
1070
+ }
1071
+ (0, node_opcua_assert_1.assert)(endpoint);
1072
+ _verify_serverCertificate(this.clientCertificateManager, endpoint.serverCertificate, (err1) => {
1073
+ if (err1) {
1074
+ warningLog("[NODE-OPCUA-W25] client's server certificate verification has failed ", err1.message);
1075
+ warningLog(" ", this.clientCertificateManager.rootDir);
1076
+ warningLog(" ", endpoint.serverCertificate.toString("base64").replace(/(.{80})/g, "$1\n "));
1077
+ warningLog(" verify that server certificate is trusted or that server certificate issuer's certificate is present in the issuer folder");
1078
+ return callback(err1);
1079
+ }
1080
+ this.serverCertificate = endpoint.serverCertificate;
1081
+ callback(null, endpoint.endpointUrl);
1082
+ });
1083
+ });
1084
+ }
1085
+ _accumulate_statistics() {
1086
+ if (this._secureChannel) {
1087
+ // keep accumulated statistics
1088
+ this._byteWritten += this._secureChannel.bytesWritten;
1089
+ this._byteRead += this._secureChannel.bytesRead;
1090
+ this._transactionsPerformed += this._secureChannel.transactionsPerformed;
1091
+ this._timedOutRequestCount += this._secureChannel.timedOutRequestCount;
1092
+ if (doDebug) {
1093
+ debugLog(chalk.cyan(` Client ${this._instanceNumber} ${this.clientName} byteWritten = `), this._byteWritten);
1094
+ debugLog(chalk.cyan(` Client ${this._instanceNumber} ${this.clientName} byteRead = `), this._byteRead);
1095
+ debugLog(chalk.cyan(` Client ${this._instanceNumber} ${this.clientName} transactions = `), this._transactionsPerformed);
1096
+ debugLog(chalk.cyan(` Client ${this._instanceNumber} ${this.clientName} timedOutRequestCount = `), this._timedOutRequestCount);
1097
+ }
1098
+ }
1099
+ }
1100
+ _destroy_secure_channel() {
1101
+ if (this._secureChannel) {
1102
+ if (doDebug) {
1103
+ debugLog(" DESTROYING SECURE CHANNEL (isTransactionInProgress ?", this._secureChannel.isTransactionInProgress(), ")");
1104
+ }
1105
+ this._accumulate_statistics();
1106
+ this._secureChannel.dispose();
1107
+ this._secureChannel.removeAllListeners();
1108
+ this._secureChannel = null;
1109
+ }
1110
+ }
1111
+ _close_pending_sessions(callback) {
1112
+ const sessions = [...this._sessions];
1113
+ async.map(sessions, (session, next) => {
1114
+ (0, node_opcua_assert_1.assert)(session._client === this);
1115
+ // note: to prevent next to be call twice
1116
+ let _next_already_call = false;
1117
+ session.close((err) => {
1118
+ if (_next_already_call) {
1119
+ return;
1120
+ }
1121
+ _next_already_call = true;
1122
+ // We should not bother if we have an error here
1123
+ // Session may fail to close , if they haven't been activate and forcefully closed by server
1124
+ // in a attempt to preserve resources in the case of a DDOS attack for instance.
1125
+ if (err) {
1126
+ const msg = session.authenticationToken ? session.authenticationToken.toString() : "";
1127
+ debugLog(" failing to close session " + msg);
1128
+ }
1129
+ next();
1130
+ });
1131
+ }, (err) => {
1132
+ // istanbul ignore next
1133
+ if (this._sessions.length > 0) {
1134
+ debugLog(this._sessions
1135
+ .map((s) => (s.authenticationToken ? s.authenticationToken.toString() : ""))
1136
+ .join(" "));
1137
+ }
1138
+ (0, node_opcua_assert_1.assert)(this._sessions.length === 0, " failed to disconnect exiting sessions ");
1139
+ callback(err);
1140
+ });
1141
+ }
1142
+ _install_secure_channel_event_handlers(secureChannel) {
1143
+ (0, node_opcua_assert_1.assert)(this instanceof ClientBaseImpl);
1144
+ secureChannel.on("send_chunk", (chunk) => {
1145
+ /**
1146
+ * notify the observer that a message_chunk has been sent
1147
+ * @event send_chunk
1148
+ * @param message_chunk
1149
+ */
1150
+ this.emit("send_chunk", chunk);
1151
+ });
1152
+ secureChannel.on("receive_chunk", (chunk) => {
1153
+ /**
1154
+ * notify the observer that a message_chunk has been received
1155
+ * @event receive_chunk
1156
+ * @param message_chunk
1157
+ */
1158
+ this.emit("receive_chunk", chunk);
1159
+ });
1160
+ secureChannel.on("send_request", (message) => {
1161
+ /**
1162
+ * notify the observer that a request has been sent to the server.
1163
+ * @event send_request
1164
+ * @param message
1165
+ */
1166
+ this.emit("send_request", message);
1167
+ });
1168
+ secureChannel.on("receive_response", (message) => {
1169
+ /**
1170
+ * notify the observer that a response has been received from the server.
1171
+ * @event receive_response
1172
+ * @param message
1173
+ */
1174
+ this.emit("receive_response", message);
1175
+ });
1176
+ secureChannel.on("lifetime_75", (token) => {
1177
+ // secureChannel requests a new token
1178
+ debugLog("SecureChannel Security Token ", token.tokenId, "live time was =", token.revisedLifetime, " is about to expired , it's time to request a new token");
1179
+ // forward message to upper level
1180
+ this.emit("lifetime_75", token, secureChannel);
1181
+ });
1182
+ secureChannel.on("security_token_renewed", () => {
1183
+ // forward message to upper level
1184
+ this.emit("security_token_renewed", secureChannel);
1185
+ });
1186
+ secureChannel.on("close", (err) => {
1187
+ debugLog(chalk.yellow.bold(" ClientBaseImpl emitting close"), err === null || err === void 0 ? void 0 : err.message);
1188
+ if (!err || !this.reconnectOnFailure) {
1189
+ // this is a normal close operation initiated by us
1190
+ /**
1191
+ * @event close
1192
+ * @param error
1193
+ */
1194
+ this.emit("close", err);
1195
+ setImmediate(() => this._destroy_secure_channel());
1196
+ }
1197
+ else {
1198
+ /**
1199
+ * @event connection_lost
1200
+ */
1201
+ this.emit("connection_lost", err === null || err === void 0 ? void 0 : err.message); // instead of "close"
1202
+ this._repairConnection();
1203
+ }
1204
+ });
1205
+ secureChannel.on("timed_out_request", (request) => {
1206
+ /**
1207
+ * send when a request has timed out without receiving a response
1208
+ * @event timed_out_request
1209
+ * @param request
1210
+ */
1211
+ this.emit("timed_out_request", request);
1212
+ });
1213
+ }
1214
+ _repairConnection() {
1215
+ setImmediate(() => {
1216
+ debugLog("recreating new secure channel ");
1217
+ this._recreate_secure_channel((err1) => {
1218
+ debugLog("secureChannel#on(close) => _recreate_secure_channel returns ", err1 ? err1.message : "OK");
1219
+ if (err1) {
1220
+ // xx assert(!this._secureChannel);
1221
+ debugLog("_recreate_secure_channel has failed");
1222
+ this.emit("close", err1);
1223
+ this._setInternalState("disconnected");
1224
+ return;
1225
+ }
1226
+ else {
1227
+ this._finalReconnectionStep((err2) => {
1228
+ if (err2) {
1229
+ // istanbul ignore next
1230
+ if (doDebug) {
1231
+ debugLog("connection_reestablished has failed");
1232
+ debugLog("err= ", err2);
1233
+ }
1234
+ this.disconnect(() => {
1235
+ // we still need to retry connecting here !!!
1236
+ warningLog("Disconnected following reconnection failure", err2.message);
1237
+ warningLog("I will retry OPCUA client reconnection in 5 seconds");
1238
+ setTimeout(() => this._repairConnection(), 5000);
1239
+ });
1240
+ return;
1241
+ }
1242
+ else {
1243
+ /**
1244
+ * @event connection_reestablished
1245
+ * send when the connection is reestablished after a connection break
1246
+ */
1247
+ this.emit("connection_reestablished");
1248
+ this._setInternalState("connected");
1249
+ }
1250
+ });
1251
+ }
1252
+ });
1253
+ });
1254
+ }
1255
+ _finalReconnectionStep(callback) {
1256
+ // now delegate to upper class the
1257
+ if (this._on_connection_reestablished) {
1258
+ (0, node_opcua_assert_1.assert)(typeof this._on_connection_reestablished === "function");
1259
+ this._on_connection_reestablished((err2) => {
1260
+ callback(err2);
1261
+ });
1262
+ }
1263
+ else {
1264
+ callback();
1265
+ }
1266
+ }
1267
+ /**
1268
+ *
1269
+ * @internal
1270
+ * @private
1271
+ */
1272
+ __createSession_step2(session, callback) {
1273
+ throw new Error("Please override");
1274
+ }
1275
+ _activateSession(session, callback) {
1276
+ throw new Error("Please override");
1277
+ }
1278
+ }
1279
+ exports.ClientBaseImpl = ClientBaseImpl;
1280
+ // tslint:disable-next-line: max-classes-per-file
1281
+ class TmpClient extends ClientBaseImpl {
1282
+ constructor(options) {
1283
+ options.clientName = (options.clientName || "") + "_TmpClient";
1284
+ super(options);
1285
+ }
1286
+ connect(endpoint, callback) {
1287
+ debugLog("connecting to TmpClient");
1288
+ // istanbul ignore next
1289
+ if (this._internalState !== "disconnected") {
1290
+ callback(new Error("TmpClient#connect: invalid internal state " + this._internalState));
1291
+ return;
1292
+ }
1293
+ if (this.disconnecting) {
1294
+ return this._handleUnrecoverableConnectionFailure(new Error("premature disconnection 3"), callback);
1295
+ }
1296
+ this._setInternalState("connecting");
1297
+ this._connectStep2(endpoint, (err) => {
1298
+ if (this.disconnecting) {
1299
+ return this._handleUnrecoverableConnectionFailure(new Error("premature disconnection 4"), callback);
1300
+ }
1301
+ callback(err);
1302
+ });
1303
+ }
1304
+ }
1305
+ // tslint:disable:no-var-requires
1306
+ // tslint:disable:max-line-length
1307
+ const thenify = require("thenify");
1308
+ ClientBaseImpl.prototype.connect = thenify.withCallback(ClientBaseImpl.prototype.connect);
1309
+ ClientBaseImpl.prototype.disconnect = thenify.withCallback(ClientBaseImpl.prototype.disconnect);
1310
+ ClientBaseImpl.prototype.getEndpoints = thenify.withCallback(ClientBaseImpl.prototype.getEndpoints);
1311
+ ClientBaseImpl.prototype.findServers = thenify.withCallback(ClientBaseImpl.prototype.findServers);
1312
+ ClientBaseImpl.prototype.findServersOnNetwork = thenify.withCallback(ClientBaseImpl.prototype.findServersOnNetwork);
1313
+ client_base_1.OPCUAClientBase.create = (options) => {
1314
+ return new ClientBaseImpl(options);
1315
+ };
1319
1316
  //# sourceMappingURL=client_base_impl.js.map