node-opcua-client 2.71.0 → 2.72.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/dist/alarms_and_conditions/client_alarm.d.ts +45 -43
  2. package/dist/alarms_and_conditions/client_alarm.js +101 -84
  3. package/dist/alarms_and_conditions/client_alarm.js.map +1 -1
  4. package/dist/alarms_and_conditions/client_alarm_list.d.ts +25 -21
  5. package/dist/alarms_and_conditions/client_alarm_list.js +97 -97
  6. package/dist/alarms_and_conditions/client_alarm_list.js.map +1 -1
  7. package/dist/alarms_and_conditions/client_alarm_tools.d.ts +4 -4
  8. package/dist/alarms_and_conditions/client_alarm_tools.js +152 -139
  9. package/dist/alarms_and_conditions/client_alarm_tools.js.map +1 -1
  10. package/dist/alarms_and_conditions/client_alarm_tools_acknowledge_all_conditions.d.ts +18 -18
  11. package/dist/alarms_and_conditions/client_alarm_tools_acknowledge_all_conditions.js +190 -190
  12. package/dist/alarms_and_conditions/client_alarm_tools_dump_event.d.ts +9 -9
  13. package/dist/alarms_and_conditions/client_alarm_tools_dump_event.js +73 -73
  14. package/dist/alarms_and_conditions/client_alarm_tools_extractConditionFields.d.ts +8 -8
  15. package/dist/alarms_and_conditions/client_alarm_tools_extractConditionFields.js +120 -120
  16. package/dist/alarms_and_conditions/client_tools.d.ts +7 -7
  17. package/dist/alarms_and_conditions/client_tools.js +180 -180
  18. package/dist/alarms_and_conditions/client_tools.js.map +1 -1
  19. package/dist/client_base.d.ts +294 -290
  20. package/dist/client_base.js +13 -13
  21. package/dist/client_base.js.map +1 -1
  22. package/dist/client_monitored_item.d.ts +21 -21
  23. package/dist/client_monitored_item.js +11 -11
  24. package/dist/client_monitored_item_base.d.ts +39 -39
  25. package/dist/client_monitored_item_base.js +2 -2
  26. package/dist/client_monitored_item_group.d.ts +18 -18
  27. package/dist/client_monitored_item_group.js +13 -13
  28. package/dist/client_monitored_item_toolbox.d.ts +15 -15
  29. package/dist/client_monitored_item_toolbox.js +117 -117
  30. package/dist/client_session.d.ts +484 -484
  31. package/dist/client_session.js +10 -10
  32. package/dist/client_session_keepalive_manager.d.ts +34 -34
  33. package/dist/client_session_keepalive_manager.js +150 -150
  34. package/dist/client_subscription.d.ts +241 -241
  35. package/dist/client_subscription.js +14 -14
  36. package/dist/client_utils.d.ts +22 -22
  37. package/dist/client_utils.js +88 -88
  38. package/dist/common.d.ts +17 -17
  39. package/dist/common.js +5 -5
  40. package/dist/index.d.ts +55 -55
  41. package/dist/index.js +93 -93
  42. package/dist/opcua_client.d.ts +132 -132
  43. package/dist/opcua_client.js +33 -33
  44. package/dist/opcua_client.js.map +1 -1
  45. package/dist/private/client_base_impl.d.ts +169 -169
  46. package/dist/private/client_base_impl.js +1324 -1316
  47. package/dist/private/client_base_impl.js.map +1 -1
  48. package/dist/private/client_monitored_item_base_impl.d.ts +3 -3
  49. package/dist/private/client_monitored_item_base_impl.js +4 -4
  50. package/dist/private/client_monitored_item_group_impl.d.ts +53 -53
  51. package/dist/private/client_monitored_item_group_impl.js +159 -159
  52. package/dist/private/client_monitored_item_impl.d.ts +93 -93
  53. package/dist/private/client_monitored_item_impl.js +304 -304
  54. package/dist/private/client_publish_engine.d.ts +62 -62
  55. package/dist/private/client_publish_engine.js +408 -408
  56. package/dist/private/client_session_impl.d.ts +621 -621
  57. package/dist/private/client_session_impl.js +1301 -1301
  58. package/dist/private/client_subscription_impl.d.ts +93 -93
  59. package/dist/private/client_subscription_impl.js +743 -734
  60. package/dist/private/client_subscription_impl.js.map +1 -1
  61. package/dist/private/i_private_client.d.ts +18 -18
  62. package/dist/private/i_private_client.js +2 -2
  63. package/dist/private/opcua_client_impl.d.ts +169 -169
  64. package/dist/private/opcua_client_impl.js +978 -978
  65. package/dist/reconnection.d.ts +9 -9
  66. package/dist/reconnection.js +362 -362
  67. package/dist/tools/findservers.d.ts +20 -20
  68. package/dist/tools/findservers.js +61 -61
  69. package/dist/tools/read_history_server_capabilities.d.ts +6 -6
  70. package/dist/tools/read_history_server_capabilities.js +99 -99
  71. package/dist/verify.d.ts +5 -5
  72. package/dist/verify.js +134 -134
  73. package/package.json +30 -30
  74. package/source/alarms_and_conditions/client_alarm.ts +21 -1
  75. package/source/alarms_and_conditions/client_alarm_list.ts +6 -2
  76. package/source/alarms_and_conditions/client_alarm_tools.ts +32 -15
  77. package/source/alarms_and_conditions/client_tools.ts +4 -4
  78. package/source/client_base.ts +6 -3
  79. package/source/opcua_client.ts +0 -2
  80. package/source/private/client_base_impl.ts +22 -13
  81. package/source/private/client_subscription_impl.ts +8 -0
@@ -1,1317 +1,1325 @@
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
- // transportTimeout:
453
- });
454
- secureChannel.protocolVersion = this.protocolVersion;
455
- this._secureChannel = secureChannel;
456
- async.series([
457
- // ------------------------------------------------- STEP 2 : OpenSecureChannel
458
- (_innerCallback) => {
459
- debugLog("_internal_create_secure_channel before secureChannel.create");
460
- secureChannel.create(this.endpointUrl, (err) => {
461
- debugLog("_internal_create_secure_channel after secureChannel.create");
462
- if (!this._secureChannel) {
463
- debugLog("_secureChannel has been closed during the transaction !");
464
- return _innerCallback(new Error("Secure Channel Closed"));
465
- }
466
- if (err) {
467
- debugLog(chalk.yellow("Cannot create secureChannel"), err.message ? chalk.cyan(err.message) : "");
468
- this._destroy_secure_channel();
469
- }
470
- else {
471
- (0, node_opcua_assert_1.assert)(this._secureChannel !== null);
472
- this._install_secure_channel_event_handlers(secureChannel);
473
- }
474
- _innerCallback(err);
475
- });
476
- secureChannel.on("backoff", (count, delay) => {
477
- this.emit("backoff", count, delay);
478
- });
479
- secureChannel.on("abort", () => {
480
- this.emit("abort");
481
- });
482
- },
483
- // ------------------------------------------------- STEP 3 : GetEndpointsRequest
484
- (innerCallback) => {
485
- (0, node_opcua_assert_1.assert)(this._secureChannel !== null);
486
- if (!this.knowsServerEndpoint) {
487
- this.getEndpoints((err /*, endpoints?: EndpointDescription[]*/) => {
488
- if (this._secureChannel === null) {
489
- (0, node_opcua_assert_1.assert)(this.disconnecting);
490
- innerCallback(new Error("disconnecting"));
491
- }
492
- innerCallback(err ? err : undefined);
493
- });
494
- }
495
- else {
496
- // end points are already known
497
- innerCallback();
498
- }
499
- }
500
- ], (err) => {
501
- if (err) {
502
- debugLog("Inner create secure channel has failed", err.message);
503
- this._secureChannel = null;
504
- callback(err);
505
- }
506
- else {
507
- (0, node_opcua_assert_1.assert)(this._secureChannel !== null);
508
- callback(null, secureChannel);
509
- }
510
- });
511
- }
512
- static createCertificate(clientCertificateManager, certificateFile, applicationName, applicationUri) {
513
- return __awaiter(this, void 0, void 0, function* () {
514
- if (!fs.existsSync(certificateFile)) {
515
- const hostname = (0, node_opcua_hostname_1.getHostname)();
516
- // this.serverInfo.applicationUri!;
517
- yield clientCertificateManager.createSelfSignedCertificate({
518
- applicationUri,
519
- dns: [hostname],
520
- // ip: await getIpAddresses(),
521
- outputFile: certificateFile,
522
- subject: (0, node_opcua_certificate_manager_1.makeSubject)(applicationName, hostname),
523
- startDate: new Date(),
524
- validity: 365 * 10 // 10 years
525
- });
526
- }
527
- // istanbul ignore next
528
- if (!fs.existsSync(certificateFile)) {
529
- throw new Error(" cannot locate certificate file " + certificateFile);
530
- }
531
- });
532
- }
533
- createDefaultCertificate() {
534
- return __awaiter(this, void 0, void 0, function* () {
535
- // istanbul ignore next
536
- if (this._inCreateDefaultCertificate) {
537
- errorLog("Internal error : re-entrancy in createDefaultCertificate!");
538
- }
539
- this._inCreateDefaultCertificate = true;
540
- if (!fs.existsSync(this.certificateFile)) {
541
- const lockfile = path.join(this.certificateFile + ".lock");
542
- yield (0, global_mutex_1.withLock)({ lockfile: lockfile, maxStaleDuration: 60 * 1000, retryInterval: 100 }, () => __awaiter(this, void 0, void 0, function* () {
543
- if (this.disconnecting)
544
- return;
545
- yield ClientBaseImpl.createCertificate(this.clientCertificateManager, this.certificateFile, this.applicationName, this._getBuiltApplicationUri());
546
- debugLog("privateKey = ", this.privateKeyFile);
547
- debugLog(" = ", this.clientCertificateManager.privateKey);
548
- debugLog("certificateFile = ", this.certificateFile);
549
- const certificate = this.getCertificate();
550
- const privateKey = this.getPrivateKey();
551
- }));
552
- }
553
- this._inCreateDefaultCertificate = false;
554
- });
555
- }
556
- _getBuiltApplicationUri() {
557
- if (!this._applicationUri) {
558
- this._applicationUri = (0, node_opcua_common_2.makeApplicationUrn)((0, node_opcua_hostname_1.getHostname)(), this.applicationName);
559
- }
560
- return this._applicationUri;
561
- }
562
- initializeCM() {
563
- return __awaiter(this, void 0, void 0, function* () {
564
- if (!this.clientCertificateManager) {
565
- return;
566
- }
567
- yield this.clientCertificateManager.initialize();
568
- yield this.createDefaultCertificate();
569
- // istanbul ignore next
570
- if (!fs.existsSync(this.privateKeyFile)) {
571
- throw new Error(" cannot locate private key file " + this.privateKeyFile);
572
- }
573
- if (this.disconnecting)
574
- return;
575
- const lockfile = path.join(this.certificateFile + ".lock");
576
- yield (0, global_mutex_1.withLock)({ lockfile: lockfile, maxStaleDuration: 60 * 1000, retryInterval: 100 }, () => __awaiter(this, void 0, void 0, function* () {
577
- if (this.disconnecting)
578
- return;
579
- yield verify_1.performCertificateSanityCheck.call(this, "client", this.clientCertificateManager, this._getBuiltApplicationUri());
580
- }));
581
- });
582
- }
583
- _handleUnrecoverableConnectionFailure(err, callback) {
584
- debugLog(err.message);
585
- this.emit("connection_failed");
586
- this._setInternalState("disconnected");
587
- return callback(err);
588
- }
589
- _handleDisconnectionWhileConnecting(err, callback) {
590
- debugLog(err.message);
591
- this.emit("connection_failed");
592
- this._setInternalState("disconnected");
593
- return callback(err);
594
- }
595
- _handleSuccessfulConnection(callback) {
596
- debugLog(" Connected successfully to ", this.endpointUrl);
597
- this.emit("connected");
598
- this._setInternalState("connected");
599
- callback();
600
- }
601
- connect(...args) {
602
- const endpointUrl = args[0];
603
- const callback = args[1];
604
- (0, node_opcua_assert_1.assert)(typeof callback === "function", "expecting a callback");
605
- if (typeof endpointUrl !== "string" || endpointUrl.length <= 0) {
606
- errorLog("[NODE-OPCUA-E03] OPCUAClient#connect expects a valid endpoint : " + endpointUrl);
607
- callback(new Error("Invalid endpoint"));
608
- return;
609
- }
610
- (0, node_opcua_assert_1.assert)(typeof endpointUrl === "string" && endpointUrl.length > 0);
611
- // istanbul ignore next
612
- if (this._internalState !== "disconnected") {
613
- callback(new Error("invalid internal state = " + this._internalState));
614
- return;
615
- }
616
- // prevent illegal call to connect
617
- if (this._secureChannel !== null) {
618
- setImmediate(() => callback(new Error("connect already called")));
619
- return;
620
- }
621
- this._setInternalState("connecting");
622
- this.disconnecting = false;
623
- this.initializeCM()
624
- .then(() => {
625
- debugLog("ClientBaseImpl#connect ", endpointUrl);
626
- if (this.disconnecting) {
627
- return this._handleDisconnectionWhileConnecting(new Error("premature disconnection 1"), callback);
628
- }
629
- if (!this.serverCertificate &&
630
- (forceEndpointDiscoveryOnConnect || this.securityMode !== node_opcua_service_secure_channel_1.MessageSecurityMode.None)) {
631
- debugLog("Fetching certificates from endpoints");
632
- this.fetchServerCertificate(endpointUrl, (err, adjustedEndpointUrl) => {
633
- if (err) {
634
- return this._handleUnrecoverableConnectionFailure(err, callback);
635
- }
636
- if (this.disconnecting) {
637
- return this._handleDisconnectionWhileConnecting(new Error("premature disconnection 2"), callback);
638
- }
639
- if (forceEndpointDiscoveryOnConnect) {
640
- debugLog("connecting with adjusted endpoint : ", adjustedEndpointUrl, " was =", endpointUrl);
641
- this._connectStep2(adjustedEndpointUrl, callback);
642
- }
643
- else {
644
- debugLog("connecting with endpoint : ", endpointUrl);
645
- this._connectStep2(endpointUrl, callback);
646
- }
647
- });
648
- }
649
- else {
650
- this._connectStep2(endpointUrl, callback);
651
- }
652
- })
653
- .catch((err) => {
654
- return this._handleUnrecoverableConnectionFailure(err, callback);
655
- });
656
- }
657
- /**
658
- * @private
659
- */
660
- _connectStep2(endpointUrl, callback) {
661
- // prevent illegal call to connect
662
- (0, node_opcua_assert_1.assert)(this._secureChannel === null);
663
- this.endpointUrl = endpointUrl;
664
- this._clockAdjuster = this._clockAdjuster || new ClockAdjustment();
665
- client_base_1.OPCUAClientBase.registry.register(this);
666
- debugLog("__connectStep2");
667
- this._internal_create_secure_channel(this.connectionStrategy, (err) => {
668
- if (!err) {
669
- this._handleSuccessfulConnection(callback);
670
- }
671
- else {
672
- client_base_1.OPCUAClientBase.registry.unregister(this);
673
- if (this._clockAdjuster) {
674
- this._clockAdjuster.dispose();
675
- this._clockAdjuster = undefined;
676
- }
677
- debugLog(chalk.red("SecureChannel creation has failed with error :", err.message));
678
- if (err.message.match(/ECONNABORTED/)) {
679
- debugLog(chalk.yellow("- The client cannot to :" + endpointUrl + ". Connection has been aborted."));
680
- err = new Error("The connection has been aborted");
681
- this._handleUnrecoverableConnectionFailure(err, callback);
682
- }
683
- else if (err.message.match(/ECONNREF/)) {
684
- debugLog(chalk.yellow("- The client cannot to :" + endpointUrl + ". Server is not reachable."));
685
- err = new Error("The connection cannot be established with server " +
686
- endpointUrl +
687
- " .\n" +
688
- "Please check that the server is up and running or your network configuration.\n" +
689
- "Err = (" +
690
- err.message +
691
- ")");
692
- this._handleUnrecoverableConnectionFailure(err, callback);
693
- }
694
- else if (err.message.match(/disconnecting/)) {
695
- /* */
696
- this._handleDisconnectionWhileConnecting(err, callback);
697
- }
698
- else {
699
- err = new Error("The connection may have been rejected by server,\n" + "Err = (" + err.message + ")");
700
- this._handleUnrecoverableConnectionFailure(err, callback);
701
- }
702
- }
703
- });
704
- }
705
- getClientNonce() {
706
- return this._secureChannel ? this._secureChannel.getClientNonce() : null;
707
- }
708
- performMessageTransaction(request, callback) {
709
- if (!this._secureChannel) {
710
- // this may happen if the Server has closed the connection abruptly for some unknown reason
711
- // or if the tcp connection has been broken.
712
- return callback(new Error("No SecureChannel , connection may have been canceled abruptly by server"));
713
- }
714
- if (this._internalState !== "connected" && this._internalState !== "connecting") {
715
- return callback(new Error("Invalid client state " + this._internalState));
716
- }
717
- (0, node_opcua_assert_1.assert)(this._secureChannel);
718
- (0, node_opcua_assert_1.assert)(request);
719
- (0, node_opcua_assert_1.assert)(request.requestHeader);
720
- (0, node_opcua_assert_1.assert)(typeof callback === "function");
721
- this._secureChannel.performMessageTransaction(request, callback);
722
- }
723
- /**
724
- *
725
- * return the endpoint information matching security mode and security policy.
726
- * @method findEndpoint
727
- */
728
- findEndpointForSecurity(securityMode, securityPolicy) {
729
- securityMode = (0, node_opcua_service_secure_channel_1.coerceMessageSecurityMode)(securityMode);
730
- securityPolicy = (0, node_opcua_secure_channel_1.coerceSecurityPolicy)(securityPolicy);
731
- (0, node_opcua_assert_1.assert)(this.knowsServerEndpoint, "Server end point are not known yet");
732
- return this._serverEndpoints.find((endpoint) => {
733
- return endpoint.securityMode === securityMode && endpoint.securityPolicyUri === securityPolicy;
734
- });
735
- }
736
- /**
737
- *
738
- * return the endpoint information matching the specified url , security mode and security policy.
739
- * @method findEndpoint
740
- */
741
- findEndpoint(endpointUrl, securityMode, securityPolicy) {
742
- (0, node_opcua_assert_1.assert)(this.knowsServerEndpoint, "Server end point are not known yet");
743
- if (!this._serverEndpoints || this._serverEndpoints.length === 0) {
744
- return undefined;
745
- }
746
- return this._serverEndpoints.find((endpoint) => {
747
- return ((0, node_opcua_utils_1.matchUri)(endpoint.endpointUrl, endpointUrl) &&
748
- endpoint.securityMode === securityMode &&
749
- endpoint.securityPolicyUri === securityPolicy);
750
- });
751
- }
752
- getEndpoints(...args) {
753
- if (args.length === 1) {
754
- return this.getEndpoints({}, args[0]);
755
- }
756
- const options = args[0];
757
- const callback = args[1];
758
- (0, node_opcua_assert_1.assert)(typeof callback === "function");
759
- options.localeIds = options.localeIds || [];
760
- options.profileUris = options.profileUris || [];
761
- const request = new node_opcua_service_endpoints_1.GetEndpointsRequest({
762
- endpointUrl: options.endpointUrl || this.endpointUrl,
763
- localeIds: options.localeIds,
764
- profileUris: options.profileUris,
765
- requestHeader: {
766
- auditEntryId: null
767
- }
768
- });
769
- this.performMessageTransaction(request, (err, response) => {
770
- this._serverEndpoints = [];
771
- if (err) {
772
- return callback(err);
773
- }
774
- // istanbul ignore next
775
- if (!response || !(response instanceof node_opcua_service_endpoints_1.GetEndpointsResponse)) {
776
- return callback(new Error("Internal Error"));
777
- }
778
- if (response && response.endpoints) {
779
- this._serverEndpoints = response.endpoints;
780
- }
781
- callback(null, this._serverEndpoints);
782
- });
783
- }
784
- /**
785
- * @deprecated
786
- */
787
- getEndpointsRequest(options, callback) {
788
- warningLog("note: ClientBaseImpl#getEndpointsRequest is deprecated, use ClientBaseImpl#getEndpoints instead");
789
- return this.getEndpoints(options, callback);
790
- }
791
- findServers(...args) {
792
- if (!this._secureChannel) {
793
- setImmediate(() => {
794
- callback(new Error("Invalid Secure Channel"));
795
- });
796
- return;
797
- }
798
- if (args.length === 1) {
799
- return this.findServers({}, args[0]);
800
- }
801
- const options = args[0];
802
- const callback = args[1];
803
- const request = new node_opcua_service_discovery_1.FindServersRequest({
804
- endpointUrl: options.endpointUrl || this.endpointUrl,
805
- localeIds: options.localeIds || [],
806
- serverUris: options.serverUris || []
807
- });
808
- this.performMessageTransaction(request, (err, response) => {
809
- if (err) {
810
- return callback(err);
811
- }
812
- /* istanbul ignore next */
813
- if (!response || !(response instanceof node_opcua_service_discovery_1.FindServersResponse)) {
814
- return callback(new Error("Internal Error"));
815
- }
816
- response.servers = response.servers || [];
817
- callback(null, response.servers);
818
- });
819
- }
820
- findServersOnNetwork(...args) {
821
- if (args.length === 1) {
822
- return this.findServersOnNetwork({}, args[0]);
823
- }
824
- const options = args[0];
825
- const callback = args[1];
826
- if (!this._secureChannel) {
827
- setImmediate(() => {
828
- callback(new Error("Invalid Secure Channel"));
829
- });
830
- return;
831
- }
832
- const request = new node_opcua_service_discovery_1.FindServersOnNetworkRequest(options);
833
- this.performMessageTransaction(request, (err, response) => {
834
- if (err) {
835
- return callback(err);
836
- }
837
- /* istanbul ignore next */
838
- if (!response || !(response instanceof node_opcua_service_discovery_1.FindServersOnNetworkResponse)) {
839
- return new Error("Internal Error");
840
- }
841
- response.servers = response.servers || [];
842
- callback(null, response.servers);
843
- });
844
- }
845
- _removeSession(session) {
846
- const index = this._sessions.indexOf(session);
847
- if (index >= 0) {
848
- const s = this._sessions.splice(index, 1)[0];
849
- (0, node_opcua_assert_1.assert)(s === session);
850
- (0, node_opcua_assert_1.assert)(session._client === this);
851
- session._client = null;
852
- }
853
- (0, node_opcua_assert_1.assert)(this._sessions.indexOf(session) === -1);
854
- }
855
- _closeSession(session, deleteSubscriptions, callback) {
856
- (0, node_opcua_assert_1.assert)(typeof callback === "function");
857
- (0, node_opcua_assert_1.assert)(typeof deleteSubscriptions === "boolean");
858
- // istanbul ignore next
859
- if (!this._secureChannel) {
860
- return callback(null); // new Error("no channel"));
861
- }
862
- (0, node_opcua_assert_1.assert)(this._secureChannel);
863
- if (!this._secureChannel.isValid()) {
864
- return callback(null);
865
- }
866
- debugLog(chalk.bgWhite.green("_closeSession ") + this._secureChannel.channelId);
867
- if (this.isReconnecting) {
868
- errorLog("OPCUAClientImpl#_closeSession called while reconnection in progress ! What shall we do");
869
- return callback(null);
870
- }
871
- const request = new node_opcua_service_session_1.CloseSessionRequest({
872
- deleteSubscriptions
873
- });
874
- session.performMessageTransaction(request, (err, response) => {
875
- if (err) {
876
- callback(err);
877
- }
878
- else {
879
- callback(err, response);
880
- }
881
- });
882
- }
883
- closeSession(...args) {
884
- const session = args[0];
885
- const deleteSubscriptions = args[1];
886
- const callback = args[2];
887
- (0, node_opcua_assert_1.assert)(typeof deleteSubscriptions === "boolean");
888
- (0, node_opcua_assert_1.assert)(typeof callback === "function");
889
- (0, node_opcua_assert_1.assert)(session);
890
- (0, node_opcua_assert_1.assert)(session._client === this, "session must be attached to this");
891
- session._closed = true;
892
- // todo : send close session on secure channel
893
- this._closeSession(session, deleteSubscriptions, (err, response) => {
894
- session.emitCloseEvent(node_opcua_status_code_1.StatusCodes.Good);
895
- this._removeSession(session);
896
- session.dispose();
897
- (0, node_opcua_assert_1.assert)(this._sessions.indexOf(session) === -1);
898
- (0, node_opcua_assert_1.assert)(session._closed, "session must indicate it is closed");
899
- callback(err ? err : undefined);
900
- });
901
- }
902
- // eslint-disable-next-line max-statements
903
- disconnect(...args) {
904
- const callback = args[0];
905
- (0, node_opcua_assert_1.assert)(typeof callback === "function", "expecting a callback function here");
906
- this.reconnectionIsCanceled = true;
907
- this.disconnecting = true;
908
- if (this._tmpClient) {
909
- this._tmpClient.disconnect((err) => {
910
- this._tmpClient = undefined;
911
- (0, node_opcua_assert_1.assert)(!this._tmpClient);
912
- // retry disconnect on main client
913
- this.disconnect(callback);
914
- });
915
- return;
916
- }
917
- debugLog("ClientBaseImpl#disconnect", this.endpointUrl);
918
- if (this.isReconnecting && !this.reconnectionIsCanceled) {
919
- debugLog("ClientBaseImpl#disconnect called while reconnection is in progress");
920
- // let's abort the reconnection process
921
- this._cancel_reconnection((err) => {
922
- debugLog("ClientBaseImpl#disconnect reconnection has been canceled", this.applicationName);
923
- (0, node_opcua_assert_1.assert)(!err, " why would this fail ?");
924
- // sessions cannot be cancelled properly and must be discarded.
925
- this.disconnect(callback);
926
- });
927
- return;
928
- }
929
- if (this._sessions.length && !this.keepPendingSessionsOnDisconnect) {
930
- debugLog("warning : disconnection : closing pending sessions");
931
- // disconnect has been called whereas living session exists
932
- // we need to close them first .... (unless keepPendingSessionsOnDisconnect)
933
- this._close_pending_sessions(( /*err*/) => {
934
- this.disconnect(callback);
935
- });
936
- return;
937
- }
938
- if (this.clientCertificateManager) {
939
- const tmp = this.clientCertificateManager;
940
- this.clientCertificateManager = null;
941
- tmp.dispose();
942
- }
943
- if (this._internalState === "disconnected" || this._internalState === "disconnecting") {
944
- return callback();
945
- }
946
- debugLog("Disconnecting !");
947
- this._setInternalState("disconnecting");
948
- if (this._sessions.length) {
949
- // transfer active session to orphan and detach them from channel
950
- const tmp = [...this._sessions];
951
- for (const session of tmp) {
952
- this._removeSession(session);
953
- }
954
- this._sessions = [];
955
- }
956
- (0, node_opcua_assert_1.assert)(this._sessions.length === 0, " attempt to disconnect a client with live sessions ");
957
- client_base_1.OPCUAClientBase.registry.unregister(this);
958
- if (this._clockAdjuster) {
959
- this._clockAdjuster.dispose();
960
- this._clockAdjuster = undefined;
961
- }
962
- if (this._secureChannel) {
963
- let tmpChannel = this._secureChannel;
964
- this._secureChannel = null;
965
- debugLog("Closing channel");
966
- tmpChannel.close(() => {
967
- this._secureChannel = tmpChannel;
968
- tmpChannel = null;
969
- this._destroy_secure_channel();
970
- this._setInternalState("disconnected");
971
- setImmediate(callback);
972
- });
973
- }
974
- else {
975
- this.emit("close", null);
976
- this._setInternalState("disconnected");
977
- setImmediate(callback);
978
- }
979
- }
980
- // override me !
981
- _on_connection_reestablished(callback) {
982
- callback();
983
- }
984
- toString() {
985
- let str = "\n";
986
- str += " defaultSecureTokenLifetime.... " + this.defaultSecureTokenLifetime + "\n";
987
- str += " securityMode.................. " + node_opcua_service_secure_channel_1.MessageSecurityMode[this.securityMode] + "\n";
988
- str += " securityPolicy................ " + this.securityPolicy.toString() + "\n";
989
- str += " certificate fingerprint....... " + (0, node_opcua_crypto_1.makeSHA1Thumbprint)(this.getCertificate()).toString("hex") + "\n";
990
- str +=
991
- " server certificate fingerprint " +
992
- (this.serverCertificate ? (0, node_opcua_crypto_1.makeSHA1Thumbprint)(this.serverCertificate).toString("hex") : "") +
993
- "\n";
994
- // this.serverCertificate = options.serverCertificate || null + "\n";
995
- str += " keepSessionAlive.............. " + this.keepSessionAlive + "\n";
996
- str += " bytesRead..................... " + this.bytesRead + "\n";
997
- str += " bytesWritten.................. " + this.bytesWritten + "\n";
998
- str += " transactionsPerformed......... " + this.transactionsPerformed + "\n";
999
- str += " timedOutRequestCount.......... " + this.timedOutRequestCount + "\n";
1000
- str += " connectionStrategy." + "\n";
1001
- str += " .maxRetry............... " + this.connectionStrategy.maxRetry + "\n";
1002
- str += " .initialDelay........... " + this.connectionStrategy.initialDelay + "\n";
1003
- str += " .maxDelay............... " + this.connectionStrategy.maxDelay + "\n";
1004
- str += " .randomisationFactor.... " + this.connectionStrategy.randomisationFactor + "\n";
1005
- str += " keepSessionAlive.............. " + this.keepSessionAlive + "\n";
1006
- str += " applicationName............... " + this.applicationName + "\n";
1007
- str += " applicationUri................ " + this._getBuiltApplicationUri() + "\n";
1008
- str += " clientName.................... " + this.clientName + "\n";
1009
- if (this._secureChannel) {
1010
- str += "secureChannel:\n" + this._secureChannel.toString();
1011
- }
1012
- return str;
1013
- }
1014
- getSessions() {
1015
- return this._sessions;
1016
- }
1017
- _addSession(session) {
1018
- (0, node_opcua_assert_1.assert)(!session._client || session._client === this);
1019
- (0, node_opcua_assert_1.assert)(this._sessions.indexOf(session) === -1, "session already added");
1020
- session._client = this;
1021
- this._sessions.push(session);
1022
- }
1023
- fetchServerCertificate(endpointUrl, callback) {
1024
- const discoveryUrl = this.discoveryUrl.length > 0 ? this.discoveryUrl : endpointUrl;
1025
- debugLog("OPCUAClientImpl : getting serverCertificate");
1026
- // we have not been given the serverCertificate but this certificate
1027
- // is required as the connection is to be secured.
1028
- //
1029
- // Let's explore the server endpoint that matches our security settings
1030
- // This will give us the missing Certificate as well from the server.
1031
- // todo :
1032
- // Once we have the certificate, we cannot trust it straight away
1033
- // we have to verify that the certificate is valid and not outdated and not revoked.
1034
- // if the certificate is self-signed the certificate must appear in the trust certificate
1035
- // list.
1036
- // if the certificate has been certified by an Certificate Authority we have to
1037
- // verify that the certificates in the chain are valid and not revoked.
1038
- //
1039
- const certificateFile = this.certificateFile;
1040
- const privateKeyFile = this.privateKeyFile;
1041
- const applicationName = this.applicationName;
1042
- const applicationUri = this._applicationUri;
1043
- const params = {
1044
- connectionStrategy: this.connectionStrategy,
1045
- endpointMustExist: false,
1046
- securityMode: this.securityMode,
1047
- securityPolicy: this.securityPolicy,
1048
- applicationName,
1049
- applicationUri,
1050
- certificateFile,
1051
- privateKeyFile,
1052
- clientCertificateManager: this.clientCertificateManager
1053
- };
1054
- return __findEndpoint.call(this, discoveryUrl, params, (err, result) => {
1055
- if (err) {
1056
- return callback(err);
1057
- }
1058
- // istanbul ignore next
1059
- if (!result) {
1060
- const err1 = new Error("internal error");
1061
- return callback(err1);
1062
- }
1063
- const endpoint = result.selectedEndpoint;
1064
- if (!endpoint) {
1065
- // no matching end point can be found ...
1066
- const err1 = new Error("cannot find endpoint for securityMode=" +
1067
- node_opcua_service_secure_channel_1.MessageSecurityMode[this.securityMode] +
1068
- " policy = " +
1069
- this.securityPolicy);
1070
- return callback(err1);
1071
- }
1072
- (0, node_opcua_assert_1.assert)(endpoint);
1073
- _verify_serverCertificate(this.clientCertificateManager, endpoint.serverCertificate, (err1) => {
1074
- if (err1) {
1075
- warningLog("[NODE-OPCUA-W25] client's server certificate verification has failed ", err1.message);
1076
- warningLog(" ", this.clientCertificateManager.rootDir);
1077
- warningLog(" ", endpoint.serverCertificate.toString("base64").replace(/(.{80})/g, "$1\n "));
1078
- warningLog(" verify that server certificate is trusted or that server certificate issuer's certificate is present in the issuer folder");
1079
- return callback(err1);
1080
- }
1081
- this.serverCertificate = endpoint.serverCertificate;
1082
- callback(null, endpoint.endpointUrl);
1083
- });
1084
- });
1085
- }
1086
- _accumulate_statistics() {
1087
- if (this._secureChannel) {
1088
- // keep accumulated statistics
1089
- this._byteWritten += this._secureChannel.bytesWritten;
1090
- this._byteRead += this._secureChannel.bytesRead;
1091
- this._transactionsPerformed += this._secureChannel.transactionsPerformed;
1092
- this._timedOutRequestCount += this._secureChannel.timedOutRequestCount;
1093
- if (doDebug) {
1094
- debugLog(chalk.cyan(` Client ${this._instanceNumber} ${this.clientName} byteWritten = `), this._byteWritten);
1095
- debugLog(chalk.cyan(` Client ${this._instanceNumber} ${this.clientName} byteRead = `), this._byteRead);
1096
- debugLog(chalk.cyan(` Client ${this._instanceNumber} ${this.clientName} transactions = `), this._transactionsPerformed);
1097
- debugLog(chalk.cyan(` Client ${this._instanceNumber} ${this.clientName} timedOutRequestCount = `), this._timedOutRequestCount);
1098
- }
1099
- }
1100
- }
1101
- _destroy_secure_channel() {
1102
- if (this._secureChannel) {
1103
- if (doDebug) {
1104
- debugLog(" DESTROYING SECURE CHANNEL (isTransactionInProgress ?", this._secureChannel.isTransactionInProgress(), ")");
1105
- }
1106
- this._accumulate_statistics();
1107
- this._secureChannel.dispose();
1108
- this._secureChannel.removeAllListeners();
1109
- this._secureChannel = null;
1110
- }
1111
- }
1112
- _close_pending_sessions(callback) {
1113
- const sessions = [...this._sessions];
1114
- async.map(sessions, (session, next) => {
1115
- (0, node_opcua_assert_1.assert)(session._client === this);
1116
- // note: to prevent next to be call twice
1117
- let _next_already_call = false;
1118
- session.close((err) => {
1119
- if (_next_already_call) {
1120
- return;
1121
- }
1122
- _next_already_call = true;
1123
- // We should not bother if we have an error here
1124
- // Session may fail to close , if they haven't been activate and forcefully closed by server
1125
- // in a attempt to preserve resources in the case of a DDOS attack for instance.
1126
- if (err) {
1127
- const msg = session.authenticationToken ? session.authenticationToken.toString() : "";
1128
- debugLog(" failing to close session " + msg);
1129
- }
1130
- next();
1131
- });
1132
- }, (err) => {
1133
- // istanbul ignore next
1134
- if (this._sessions.length > 0) {
1135
- debugLog(this._sessions
1136
- .map((s) => (s.authenticationToken ? s.authenticationToken.toString() : ""))
1137
- .join(" "));
1138
- }
1139
- (0, node_opcua_assert_1.assert)(this._sessions.length === 0, " failed to disconnect exiting sessions ");
1140
- callback(err);
1141
- });
1142
- }
1143
- _install_secure_channel_event_handlers(secureChannel) {
1144
- (0, node_opcua_assert_1.assert)(this instanceof ClientBaseImpl);
1145
- secureChannel.on("send_chunk", (chunk) => {
1146
- /**
1147
- * notify the observer that a message_chunk has been sent
1148
- * @event send_chunk
1149
- * @param message_chunk
1150
- */
1151
- this.emit("send_chunk", chunk);
1152
- });
1153
- secureChannel.on("receive_chunk", (chunk) => {
1154
- /**
1155
- * notify the observer that a message_chunk has been received
1156
- * @event receive_chunk
1157
- * @param message_chunk
1158
- */
1159
- this.emit("receive_chunk", chunk);
1160
- });
1161
- secureChannel.on("send_request", (message) => {
1162
- /**
1163
- * notify the observer that a request has been sent to the server.
1164
- * @event send_request
1165
- * @param message
1166
- */
1167
- this.emit("send_request", message);
1168
- });
1169
- secureChannel.on("receive_response", (message) => {
1170
- /**
1171
- * notify the observer that a response has been received from the server.
1172
- * @event receive_response
1173
- * @param message
1174
- */
1175
- this.emit("receive_response", message);
1176
- });
1177
- secureChannel.on("lifetime_75", (token) => {
1178
- // secureChannel requests a new token
1179
- debugLog("SecureChannel Security Token ", token.tokenId, "live time was =", token.revisedLifetime, " is about to expired , it's time to request a new token");
1180
- // forward message to upper level
1181
- this.emit("lifetime_75", token, secureChannel);
1182
- });
1183
- secureChannel.on("security_token_renewed", () => {
1184
- // forward message to upper level
1185
- this.emit("security_token_renewed", secureChannel);
1186
- });
1187
- secureChannel.on("close", (err) => {
1188
- debugLog(chalk.yellow.bold(" ClientBaseImpl emitting close"), err === null || err === void 0 ? void 0 : err.message);
1189
- if (!err || !this.reconnectOnFailure) {
1190
- // this is a normal close operation initiated by us
1191
- /**
1192
- * @event close
1193
- * @param error
1194
- */
1195
- this.emit("close", err);
1196
- setImmediate(() => this._destroy_secure_channel());
1197
- }
1198
- else {
1199
- /**
1200
- * @event connection_lost
1201
- */
1202
- this.emit("connection_lost", err === null || err === void 0 ? void 0 : err.message); // instead of "close"
1203
- this._repairConnection();
1204
- }
1205
- });
1206
- secureChannel.on("timed_out_request", (request) => {
1207
- /**
1208
- * send when a request has timed out without receiving a response
1209
- * @event timed_out_request
1210
- * @param request
1211
- */
1212
- this.emit("timed_out_request", request);
1213
- });
1214
- }
1215
- _repairConnection() {
1216
- setImmediate(() => {
1217
- debugLog("recreating new secure channel ");
1218
- this._recreate_secure_channel((err1) => {
1219
- debugLog("secureChannel#on(close) => _recreate_secure_channel returns ", err1 ? err1.message : "OK");
1220
- if (err1) {
1221
- // xx assert(!this._secureChannel);
1222
- debugLog("_recreate_secure_channel has failed");
1223
- this.emit("close", err1);
1224
- this._setInternalState("disconnected");
1225
- return;
1226
- }
1227
- else {
1228
- this._finalReconnectionStep((err2) => {
1229
- if (err2) {
1230
- // istanbul ignore next
1231
- if (doDebug) {
1232
- debugLog("connection_reestablished has failed");
1233
- debugLog("err= ", err2);
1234
- }
1235
- this.disconnect(() => {
1236
- // we still need to retry connecting here !!!
1237
- warningLog("Disconnected following reconnection failure", err2.message);
1238
- warningLog("I will retry OPCUA client reconnection in 5 seconds");
1239
- setTimeout(() => this._repairConnection(), 5000);
1240
- });
1241
- return;
1242
- }
1243
- else {
1244
- /**
1245
- * @event connection_reestablished
1246
- * send when the connection is reestablished after a connection break
1247
- */
1248
- this.emit("connection_reestablished");
1249
- this._setInternalState("connected");
1250
- }
1251
- });
1252
- }
1253
- });
1254
- });
1255
- }
1256
- _finalReconnectionStep(callback) {
1257
- // now delegate to upper class the
1258
- if (this._on_connection_reestablished) {
1259
- (0, node_opcua_assert_1.assert)(typeof this._on_connection_reestablished === "function");
1260
- this._on_connection_reestablished((err2) => {
1261
- callback(err2);
1262
- });
1263
- }
1264
- else {
1265
- callback();
1266
- }
1267
- }
1268
- /**
1269
- *
1270
- * @internal
1271
- * @private
1272
- */
1273
- __createSession_step2(session, callback) {
1274
- throw new Error("Please override");
1275
- }
1276
- _activateSession(session, callback) {
1277
- throw new Error("Please override");
1278
- }
1279
- }
1280
- exports.ClientBaseImpl = ClientBaseImpl;
1281
- // tslint:disable-next-line: max-classes-per-file
1282
- class TmpClient extends ClientBaseImpl {
1283
- constructor(options) {
1284
- options.clientName = (options.clientName || "") + "_TmpClient";
1285
- super(options);
1286
- }
1287
- connect(endpoint, callback) {
1288
- debugLog("connecting to TmpClient");
1289
- // istanbul ignore next
1290
- if (this._internalState !== "disconnected") {
1291
- callback(new Error("TmpClient#connect: invalid internal state " + this._internalState));
1292
- return;
1293
- }
1294
- if (this.disconnecting) {
1295
- return this._handleUnrecoverableConnectionFailure(new Error("premature disconnection 3"), callback);
1296
- }
1297
- this._setInternalState("connecting");
1298
- this._connectStep2(endpoint, (err) => {
1299
- if (this.disconnecting) {
1300
- return this._handleUnrecoverableConnectionFailure(new Error("premature disconnection 4"), callback);
1301
- }
1302
- callback(err);
1303
- });
1304
- }
1305
- }
1306
- // tslint:disable:no-var-requires
1307
- // tslint:disable:max-line-length
1308
- const thenify = require("thenify");
1309
- ClientBaseImpl.prototype.connect = thenify.withCallback(ClientBaseImpl.prototype.connect);
1310
- ClientBaseImpl.prototype.disconnect = thenify.withCallback(ClientBaseImpl.prototype.disconnect);
1311
- ClientBaseImpl.prototype.getEndpoints = thenify.withCallback(ClientBaseImpl.prototype.getEndpoints);
1312
- ClientBaseImpl.prototype.findServers = thenify.withCallback(ClientBaseImpl.prototype.findServers);
1313
- ClientBaseImpl.prototype.findServersOnNetwork = thenify.withCallback(ClientBaseImpl.prototype.findServersOnNetwork);
1314
- client_base_1.OPCUAClientBase.create = (options) => {
1315
- return new ClientBaseImpl(options);
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
+ // transportTimeout:
453
+ });
454
+ secureChannel.protocolVersion = this.protocolVersion;
455
+ this._secureChannel = secureChannel;
456
+ async.series([
457
+ // ------------------------------------------------- STEP 2 : OpenSecureChannel
458
+ (_innerCallback) => {
459
+ debugLog("_internal_create_secure_channel before secureChannel.create");
460
+ secureChannel.create(this.endpointUrl, (err) => {
461
+ debugLog("_internal_create_secure_channel after secureChannel.create");
462
+ if (!this._secureChannel) {
463
+ debugLog("_secureChannel has been closed during the transaction !");
464
+ return _innerCallback(new Error("Secure Channel Closed"));
465
+ }
466
+ if (err) {
467
+ debugLog(chalk.yellow("Cannot create secureChannel"), err.message ? chalk.cyan(err.message) : "");
468
+ this._destroy_secure_channel();
469
+ }
470
+ else {
471
+ (0, node_opcua_assert_1.assert)(this._secureChannel !== null);
472
+ this._install_secure_channel_event_handlers(secureChannel);
473
+ }
474
+ _innerCallback(err);
475
+ });
476
+ secureChannel.on("backoff", (count, delay) => {
477
+ this.emit("backoff", count, delay);
478
+ });
479
+ secureChannel.on("abort", () => {
480
+ this.emit("abort");
481
+ });
482
+ },
483
+ // ------------------------------------------------- STEP 3 : GetEndpointsRequest
484
+ (innerCallback) => {
485
+ (0, node_opcua_assert_1.assert)(this._secureChannel !== null);
486
+ if (!this.knowsServerEndpoint) {
487
+ this.getEndpoints((err /*, endpoints?: EndpointDescription[]*/) => {
488
+ if (this._secureChannel === null) {
489
+ (0, node_opcua_assert_1.assert)(this.disconnecting);
490
+ innerCallback(new Error("disconnecting"));
491
+ }
492
+ innerCallback(err ? err : undefined);
493
+ });
494
+ }
495
+ else {
496
+ // end points are already known
497
+ innerCallback();
498
+ }
499
+ }
500
+ ], (err) => {
501
+ if (err) {
502
+ debugLog("Inner create secure channel has failed", err.message);
503
+ this._secureChannel = null;
504
+ callback(err);
505
+ }
506
+ else {
507
+ (0, node_opcua_assert_1.assert)(this._secureChannel !== null);
508
+ callback(null, secureChannel);
509
+ }
510
+ });
511
+ }
512
+ static createCertificate(clientCertificateManager, certificateFile, applicationName, applicationUri) {
513
+ return __awaiter(this, void 0, void 0, function* () {
514
+ if (!fs.existsSync(certificateFile)) {
515
+ const hostname = (0, node_opcua_hostname_1.getHostname)();
516
+ // this.serverInfo.applicationUri!;
517
+ yield clientCertificateManager.createSelfSignedCertificate({
518
+ applicationUri,
519
+ dns: [hostname],
520
+ // ip: await getIpAddresses(),
521
+ outputFile: certificateFile,
522
+ subject: (0, node_opcua_certificate_manager_1.makeSubject)(applicationName, hostname),
523
+ startDate: new Date(),
524
+ validity: 365 * 10 // 10 years
525
+ });
526
+ }
527
+ // istanbul ignore next
528
+ if (!fs.existsSync(certificateFile)) {
529
+ throw new Error(" cannot locate certificate file " + certificateFile);
530
+ }
531
+ });
532
+ }
533
+ createDefaultCertificate() {
534
+ return __awaiter(this, void 0, void 0, function* () {
535
+ // istanbul ignore next
536
+ if (this._inCreateDefaultCertificate) {
537
+ errorLog("Internal error : re-entrancy in createDefaultCertificate!");
538
+ }
539
+ this._inCreateDefaultCertificate = true;
540
+ if (!fs.existsSync(this.certificateFile)) {
541
+ const lockfile = path.join(this.certificateFile + ".lock");
542
+ yield (0, global_mutex_1.withLock)({ lockfile: lockfile, maxStaleDuration: 60 * 1000, retryInterval: 100 }, () => __awaiter(this, void 0, void 0, function* () {
543
+ if (this.disconnecting)
544
+ return;
545
+ yield ClientBaseImpl.createCertificate(this.clientCertificateManager, this.certificateFile, this.applicationName, this._getBuiltApplicationUri());
546
+ debugLog("privateKey = ", this.privateKeyFile);
547
+ debugLog(" = ", this.clientCertificateManager.privateKey);
548
+ debugLog("certificateFile = ", this.certificateFile);
549
+ const certificate = this.getCertificate();
550
+ const privateKey = this.getPrivateKey();
551
+ }));
552
+ }
553
+ this._inCreateDefaultCertificate = false;
554
+ });
555
+ }
556
+ _getBuiltApplicationUri() {
557
+ if (!this._applicationUri) {
558
+ this._applicationUri = (0, node_opcua_common_2.makeApplicationUrn)((0, node_opcua_hostname_1.getHostname)(), this.applicationName);
559
+ }
560
+ return this._applicationUri;
561
+ }
562
+ initializeCM() {
563
+ return __awaiter(this, void 0, void 0, function* () {
564
+ if (!this.clientCertificateManager) {
565
+ // this usually happen when the client has been already disconnected,
566
+ // disconnect
567
+ errorLog("[NODE-OPCUA-E08] initializeCM: clientCertificateManager is null\n" +
568
+ " This happen when you disconnected the client, to free resources.\n" +
569
+ " Please create a new OPCUAClient instance if you want to reconnect");
570
+ return;
571
+ }
572
+ yield this.clientCertificateManager.initialize();
573
+ yield this.createDefaultCertificate();
574
+ // istanbul ignore next
575
+ if (!fs.existsSync(this.privateKeyFile)) {
576
+ throw new Error(" cannot locate private key file " + this.privateKeyFile);
577
+ }
578
+ if (this.disconnecting)
579
+ return;
580
+ const lockfile = path.join(this.certificateFile + ".lock");
581
+ yield (0, global_mutex_1.withLock)({ lockfile: lockfile, maxStaleDuration: 60 * 1000, retryInterval: 100 }, () => __awaiter(this, void 0, void 0, function* () {
582
+ if (this.disconnecting)
583
+ return;
584
+ yield verify_1.performCertificateSanityCheck.call(this, "client", this.clientCertificateManager, this._getBuiltApplicationUri());
585
+ }));
586
+ });
587
+ }
588
+ _handleUnrecoverableConnectionFailure(err, callback) {
589
+ debugLog(err.message);
590
+ this.emit("connection_failed");
591
+ this._setInternalState("disconnected");
592
+ return callback(err);
593
+ }
594
+ _handleDisconnectionWhileConnecting(err, callback) {
595
+ debugLog(err.message);
596
+ this.emit("connection_failed");
597
+ this._setInternalState("disconnected");
598
+ return callback(err);
599
+ }
600
+ _handleSuccessfulConnection(callback) {
601
+ debugLog(" Connected successfully to ", this.endpointUrl);
602
+ this.emit("connected");
603
+ this._setInternalState("connected");
604
+ callback();
605
+ }
606
+ connect(...args) {
607
+ const endpointUrl = args[0];
608
+ const callback = args[1];
609
+ (0, node_opcua_assert_1.assert)(typeof callback === "function", "expecting a callback");
610
+ if (typeof endpointUrl !== "string" || endpointUrl.length <= 0) {
611
+ errorLog("[NODE-OPCUA-E03] OPCUAClient#connect expects a valid endpoint : " + endpointUrl);
612
+ callback(new Error("Invalid endpoint"));
613
+ return;
614
+ }
615
+ (0, node_opcua_assert_1.assert)(typeof endpointUrl === "string" && endpointUrl.length > 0);
616
+ // istanbul ignore next
617
+ if (this._internalState !== "disconnected") {
618
+ callback(new Error("invalid internal state = " + this._internalState));
619
+ return;
620
+ }
621
+ // prevent illegal call to connect
622
+ if (this._secureChannel !== null) {
623
+ setImmediate(() => callback(new Error("connect already called")));
624
+ return;
625
+ }
626
+ this._setInternalState("connecting");
627
+ this.disconnecting = false;
628
+ this.initializeCM()
629
+ .then(() => {
630
+ debugLog("ClientBaseImpl#connect ", endpointUrl);
631
+ if (this.disconnecting) {
632
+ return this._handleDisconnectionWhileConnecting(new Error("premature disconnection 1"), callback);
633
+ }
634
+ if (!this.serverCertificate &&
635
+ (forceEndpointDiscoveryOnConnect || this.securityMode !== node_opcua_service_secure_channel_1.MessageSecurityMode.None)) {
636
+ debugLog("Fetching certificates from endpoints");
637
+ this.fetchServerCertificate(endpointUrl, (err, adjustedEndpointUrl) => {
638
+ if (err) {
639
+ return this._handleUnrecoverableConnectionFailure(err, callback);
640
+ }
641
+ if (this.disconnecting) {
642
+ return this._handleDisconnectionWhileConnecting(new Error("premature disconnection 2"), callback);
643
+ }
644
+ if (forceEndpointDiscoveryOnConnect) {
645
+ debugLog("connecting with adjusted endpoint : ", adjustedEndpointUrl, " was =", endpointUrl);
646
+ this._connectStep2(adjustedEndpointUrl, callback);
647
+ }
648
+ else {
649
+ debugLog("connecting with endpoint : ", endpointUrl);
650
+ this._connectStep2(endpointUrl, callback);
651
+ }
652
+ });
653
+ }
654
+ else {
655
+ this._connectStep2(endpointUrl, callback);
656
+ }
657
+ })
658
+ .catch((err) => {
659
+ return this._handleUnrecoverableConnectionFailure(err, callback);
660
+ });
661
+ }
662
+ /**
663
+ * @private
664
+ */
665
+ _connectStep2(endpointUrl, callback) {
666
+ // prevent illegal call to connect
667
+ (0, node_opcua_assert_1.assert)(this._secureChannel === null);
668
+ this.endpointUrl = endpointUrl;
669
+ this._clockAdjuster = this._clockAdjuster || new ClockAdjustment();
670
+ client_base_1.OPCUAClientBase.registry.register(this);
671
+ debugLog("__connectStep2");
672
+ this._internal_create_secure_channel(this.connectionStrategy, (err) => {
673
+ if (!err) {
674
+ this._handleSuccessfulConnection(callback);
675
+ }
676
+ else {
677
+ client_base_1.OPCUAClientBase.registry.unregister(this);
678
+ if (this._clockAdjuster) {
679
+ this._clockAdjuster.dispose();
680
+ this._clockAdjuster = undefined;
681
+ }
682
+ debugLog(chalk.red("SecureChannel creation has failed with error :", err.message));
683
+ if (err.message.match(/ECONNABORTED/)) {
684
+ debugLog(chalk.yellow("- The client cannot to :" + endpointUrl + ". Connection has been aborted."));
685
+ err = new Error("The connection has been aborted");
686
+ this._handleUnrecoverableConnectionFailure(err, callback);
687
+ }
688
+ else if (err.message.match(/ECONNREF/)) {
689
+ debugLog(chalk.yellow("- The client cannot to :" + endpointUrl + ". Server is not reachable."));
690
+ err = new Error("The connection cannot be established with server " +
691
+ endpointUrl +
692
+ " .\n" +
693
+ "Please check that the server is up and running or your network configuration.\n" +
694
+ "Err = (" +
695
+ err.message +
696
+ ")");
697
+ this._handleUnrecoverableConnectionFailure(err, callback);
698
+ }
699
+ else if (err.message.match(/disconnecting/)) {
700
+ /* */
701
+ this._handleDisconnectionWhileConnecting(err, callback);
702
+ }
703
+ else {
704
+ err = new Error("The connection may have been rejected by server,\n" + "Err = (" + err.message + ")");
705
+ this._handleUnrecoverableConnectionFailure(err, callback);
706
+ }
707
+ }
708
+ });
709
+ }
710
+ getClientNonce() {
711
+ return this._secureChannel ? this._secureChannel.getClientNonce() : null;
712
+ }
713
+ performMessageTransaction(request, callback) {
714
+ if (!this._secureChannel) {
715
+ // this may happen if the Server has closed the connection abruptly for some unknown reason
716
+ // or if the tcp connection has been broken.
717
+ return callback(new Error("No SecureChannel , connection may have been canceled abruptly by server"));
718
+ }
719
+ if (this._internalState !== "connected" && this._internalState !== "connecting") {
720
+ return callback(new Error("Invalid client state " + this._internalState));
721
+ }
722
+ (0, node_opcua_assert_1.assert)(this._secureChannel);
723
+ (0, node_opcua_assert_1.assert)(request);
724
+ (0, node_opcua_assert_1.assert)(request.requestHeader);
725
+ (0, node_opcua_assert_1.assert)(typeof callback === "function");
726
+ this._secureChannel.performMessageTransaction(request, callback);
727
+ }
728
+ /**
729
+ *
730
+ * return the endpoint information matching security mode and security policy.
731
+ * @method findEndpoint
732
+ */
733
+ findEndpointForSecurity(securityMode, securityPolicy) {
734
+ securityMode = (0, node_opcua_service_secure_channel_1.coerceMessageSecurityMode)(securityMode);
735
+ securityPolicy = (0, node_opcua_secure_channel_1.coerceSecurityPolicy)(securityPolicy);
736
+ (0, node_opcua_assert_1.assert)(this.knowsServerEndpoint, "Server end point are not known yet");
737
+ return this._serverEndpoints.find((endpoint) => {
738
+ return endpoint.securityMode === securityMode && endpoint.securityPolicyUri === securityPolicy;
739
+ });
740
+ }
741
+ /**
742
+ *
743
+ * return the endpoint information matching the specified url , security mode and security policy.
744
+ * @method findEndpoint
745
+ */
746
+ findEndpoint(endpointUrl, securityMode, securityPolicy) {
747
+ (0, node_opcua_assert_1.assert)(this.knowsServerEndpoint, "Server end point are not known yet");
748
+ if (!this._serverEndpoints || this._serverEndpoints.length === 0) {
749
+ return undefined;
750
+ }
751
+ return this._serverEndpoints.find((endpoint) => {
752
+ return ((0, node_opcua_utils_1.matchUri)(endpoint.endpointUrl, endpointUrl) &&
753
+ endpoint.securityMode === securityMode &&
754
+ endpoint.securityPolicyUri === securityPolicy);
755
+ });
756
+ }
757
+ getEndpoints(...args) {
758
+ if (args.length === 1) {
759
+ return this.getEndpoints({}, args[0]);
760
+ }
761
+ const options = args[0];
762
+ const callback = args[1];
763
+ (0, node_opcua_assert_1.assert)(typeof callback === "function");
764
+ options.localeIds = options.localeIds || [];
765
+ options.profileUris = options.profileUris || [];
766
+ const request = new node_opcua_service_endpoints_1.GetEndpointsRequest({
767
+ endpointUrl: options.endpointUrl || this.endpointUrl,
768
+ localeIds: options.localeIds,
769
+ profileUris: options.profileUris,
770
+ requestHeader: {
771
+ auditEntryId: null
772
+ }
773
+ });
774
+ this.performMessageTransaction(request, (err, response) => {
775
+ this._serverEndpoints = [];
776
+ if (err) {
777
+ return callback(err);
778
+ }
779
+ // istanbul ignore next
780
+ if (!response || !(response instanceof node_opcua_service_endpoints_1.GetEndpointsResponse)) {
781
+ return callback(new Error("Internal Error"));
782
+ }
783
+ if (response && response.endpoints) {
784
+ this._serverEndpoints = response.endpoints;
785
+ }
786
+ callback(null, this._serverEndpoints);
787
+ });
788
+ }
789
+ /**
790
+ * @deprecated
791
+ */
792
+ getEndpointsRequest(options, callback) {
793
+ warningLog("note: ClientBaseImpl#getEndpointsRequest is deprecated, use ClientBaseImpl#getEndpoints instead");
794
+ return this.getEndpoints(options, callback);
795
+ }
796
+ findServers(...args) {
797
+ if (!this._secureChannel) {
798
+ setImmediate(() => {
799
+ callback(new Error("Invalid Secure Channel"));
800
+ });
801
+ return;
802
+ }
803
+ if (args.length === 1) {
804
+ return this.findServers({}, args[0]);
805
+ }
806
+ const options = args[0];
807
+ const callback = args[1];
808
+ const request = new node_opcua_service_discovery_1.FindServersRequest({
809
+ endpointUrl: options.endpointUrl || this.endpointUrl,
810
+ localeIds: options.localeIds || [],
811
+ serverUris: options.serverUris || []
812
+ });
813
+ this.performMessageTransaction(request, (err, response) => {
814
+ if (err) {
815
+ return callback(err);
816
+ }
817
+ /* istanbul ignore next */
818
+ if (!response || !(response instanceof node_opcua_service_discovery_1.FindServersResponse)) {
819
+ return callback(new Error("Internal Error"));
820
+ }
821
+ response.servers = response.servers || [];
822
+ callback(null, response.servers);
823
+ });
824
+ }
825
+ findServersOnNetwork(...args) {
826
+ if (args.length === 1) {
827
+ return this.findServersOnNetwork({}, args[0]);
828
+ }
829
+ const options = args[0];
830
+ const callback = args[1];
831
+ if (!this._secureChannel) {
832
+ setImmediate(() => {
833
+ callback(new Error("Invalid Secure Channel"));
834
+ });
835
+ return;
836
+ }
837
+ const request = new node_opcua_service_discovery_1.FindServersOnNetworkRequest(options);
838
+ this.performMessageTransaction(request, (err, response) => {
839
+ if (err) {
840
+ return callback(err);
841
+ }
842
+ /* istanbul ignore next */
843
+ if (!response || !(response instanceof node_opcua_service_discovery_1.FindServersOnNetworkResponse)) {
844
+ return new Error("Internal Error");
845
+ }
846
+ response.servers = response.servers || [];
847
+ callback(null, response.servers);
848
+ });
849
+ }
850
+ _removeSession(session) {
851
+ const index = this._sessions.indexOf(session);
852
+ if (index >= 0) {
853
+ const s = this._sessions.splice(index, 1)[0];
854
+ (0, node_opcua_assert_1.assert)(s === session);
855
+ (0, node_opcua_assert_1.assert)(session._client === this);
856
+ session._client = null;
857
+ }
858
+ (0, node_opcua_assert_1.assert)(this._sessions.indexOf(session) === -1);
859
+ }
860
+ _closeSession(session, deleteSubscriptions, callback) {
861
+ (0, node_opcua_assert_1.assert)(typeof callback === "function");
862
+ (0, node_opcua_assert_1.assert)(typeof deleteSubscriptions === "boolean");
863
+ // istanbul ignore next
864
+ if (!this._secureChannel) {
865
+ return callback(null); // new Error("no channel"));
866
+ }
867
+ (0, node_opcua_assert_1.assert)(this._secureChannel);
868
+ if (!this._secureChannel.isValid()) {
869
+ return callback(null);
870
+ }
871
+ debugLog(chalk.bgWhite.green("_closeSession ") + this._secureChannel.channelId);
872
+ if (this.isReconnecting) {
873
+ errorLog("OPCUAClientImpl#_closeSession called while reconnection in progress ! What shall we do");
874
+ return callback(null);
875
+ }
876
+ const request = new node_opcua_service_session_1.CloseSessionRequest({
877
+ deleteSubscriptions
878
+ });
879
+ session.performMessageTransaction(request, (err, response) => {
880
+ if (err) {
881
+ callback(err);
882
+ }
883
+ else {
884
+ callback(err, response);
885
+ }
886
+ });
887
+ }
888
+ closeSession(...args) {
889
+ const session = args[0];
890
+ const deleteSubscriptions = args[1];
891
+ const callback = args[2];
892
+ (0, node_opcua_assert_1.assert)(typeof deleteSubscriptions === "boolean");
893
+ (0, node_opcua_assert_1.assert)(typeof callback === "function");
894
+ (0, node_opcua_assert_1.assert)(session);
895
+ (0, node_opcua_assert_1.assert)(session._client === this, "session must be attached to this");
896
+ session._closed = true;
897
+ // todo : send close session on secure channel
898
+ this._closeSession(session, deleteSubscriptions, (err, response) => {
899
+ session.emitCloseEvent(node_opcua_status_code_1.StatusCodes.Good);
900
+ this._removeSession(session);
901
+ session.dispose();
902
+ (0, node_opcua_assert_1.assert)(this._sessions.indexOf(session) === -1);
903
+ (0, node_opcua_assert_1.assert)(session._closed, "session must indicate it is closed");
904
+ callback(err ? err : undefined);
905
+ });
906
+ }
907
+ // eslint-disable-next-line max-statements
908
+ disconnect(...args) {
909
+ const callback = args[0];
910
+ (0, node_opcua_assert_1.assert)(typeof callback === "function", "expecting a callback function here");
911
+ if (this._internalState === "disconnected" || this._internalState === "disconnecting") {
912
+ if (this._internalState === "disconnecting") {
913
+ warningLog("[NODE-OPCUA-W26] OPCUAClient#disconnect called while already disconnecting");
914
+ }
915
+ return callback();
916
+ }
917
+ this.reconnectionIsCanceled = true;
918
+ this.disconnecting = true;
919
+ if (this._tmpClient) {
920
+ this._tmpClient.disconnect((err) => {
921
+ this._tmpClient = undefined;
922
+ (0, node_opcua_assert_1.assert)(!this._tmpClient);
923
+ // retry disconnect on main client
924
+ this.disconnect(callback);
925
+ });
926
+ return;
927
+ }
928
+ debugLog("ClientBaseImpl#disconnect", this.endpointUrl);
929
+ if (this.isReconnecting && !this.reconnectionIsCanceled) {
930
+ debugLog("ClientBaseImpl#disconnect called while reconnection is in progress");
931
+ // let's abort the reconnection process
932
+ this._cancel_reconnection((err) => {
933
+ debugLog("ClientBaseImpl#disconnect reconnection has been canceled", this.applicationName);
934
+ (0, node_opcua_assert_1.assert)(!err, " why would this fail ?");
935
+ // sessions cannot be cancelled properly and must be discarded.
936
+ this.disconnect(callback);
937
+ });
938
+ return;
939
+ }
940
+ if (this._sessions.length && !this.keepPendingSessionsOnDisconnect) {
941
+ debugLog("warning : disconnection : closing pending sessions");
942
+ // disconnect has been called whereas living session exists
943
+ // we need to close them first .... (unless keepPendingSessionsOnDisconnect)
944
+ this._close_pending_sessions(( /*err*/) => {
945
+ this.disconnect(callback);
946
+ });
947
+ return;
948
+ }
949
+ debugLog("Disconnecting !");
950
+ this._setInternalState("disconnecting");
951
+ if (this.clientCertificateManager) {
952
+ const tmp = this.clientCertificateManager;
953
+ // (this as any).clientCertificateManager = null;
954
+ tmp.dispose();
955
+ }
956
+ if (this._sessions.length) {
957
+ // transfer active session to orphan and detach them from channel
958
+ const tmp = [...this._sessions];
959
+ for (const session of tmp) {
960
+ this._removeSession(session);
961
+ }
962
+ this._sessions = [];
963
+ }
964
+ (0, node_opcua_assert_1.assert)(this._sessions.length === 0, " attempt to disconnect a client with live sessions ");
965
+ client_base_1.OPCUAClientBase.registry.unregister(this);
966
+ if (this._clockAdjuster) {
967
+ this._clockAdjuster.dispose();
968
+ this._clockAdjuster = undefined;
969
+ }
970
+ if (this._secureChannel) {
971
+ let tmpChannel = this._secureChannel;
972
+ this._secureChannel = null;
973
+ debugLog("Closing channel");
974
+ tmpChannel.close(() => {
975
+ this._secureChannel = tmpChannel;
976
+ tmpChannel = null;
977
+ this._destroy_secure_channel();
978
+ this._setInternalState("disconnected");
979
+ setImmediate(callback);
980
+ });
981
+ }
982
+ else {
983
+ this.emit("close", null);
984
+ this._setInternalState("disconnected");
985
+ setImmediate(callback);
986
+ }
987
+ }
988
+ // override me !
989
+ _on_connection_reestablished(callback) {
990
+ callback();
991
+ }
992
+ toString() {
993
+ let str = "\n";
994
+ str += " defaultSecureTokenLifetime.... " + this.defaultSecureTokenLifetime + "\n";
995
+ str += " securityMode.................. " + node_opcua_service_secure_channel_1.MessageSecurityMode[this.securityMode] + "\n";
996
+ str += " securityPolicy................ " + this.securityPolicy.toString() + "\n";
997
+ str += " certificate fingerprint....... " + (0, node_opcua_crypto_1.makeSHA1Thumbprint)(this.getCertificate()).toString("hex") + "\n";
998
+ str +=
999
+ " server certificate fingerprint " +
1000
+ (this.serverCertificate ? (0, node_opcua_crypto_1.makeSHA1Thumbprint)(this.serverCertificate).toString("hex") : "") +
1001
+ "\n";
1002
+ // this.serverCertificate = options.serverCertificate || null + "\n";
1003
+ str += " keepSessionAlive.............. " + this.keepSessionAlive + "\n";
1004
+ str += " bytesRead..................... " + this.bytesRead + "\n";
1005
+ str += " bytesWritten.................. " + this.bytesWritten + "\n";
1006
+ str += " transactionsPerformed......... " + this.transactionsPerformed + "\n";
1007
+ str += " timedOutRequestCount.......... " + this.timedOutRequestCount + "\n";
1008
+ str += " connectionStrategy." + "\n";
1009
+ str += " .maxRetry............... " + this.connectionStrategy.maxRetry + "\n";
1010
+ str += " .initialDelay........... " + this.connectionStrategy.initialDelay + "\n";
1011
+ str += " .maxDelay............... " + this.connectionStrategy.maxDelay + "\n";
1012
+ str += " .randomisationFactor.... " + this.connectionStrategy.randomisationFactor + "\n";
1013
+ str += " keepSessionAlive.............. " + this.keepSessionAlive + "\n";
1014
+ str += " applicationName............... " + this.applicationName + "\n";
1015
+ str += " applicationUri................ " + this._getBuiltApplicationUri() + "\n";
1016
+ str += " clientName.................... " + this.clientName + "\n";
1017
+ if (this._secureChannel) {
1018
+ str += "secureChannel:\n" + this._secureChannel.toString();
1019
+ }
1020
+ return str;
1021
+ }
1022
+ getSessions() {
1023
+ return this._sessions;
1024
+ }
1025
+ _addSession(session) {
1026
+ (0, node_opcua_assert_1.assert)(!session._client || session._client === this);
1027
+ (0, node_opcua_assert_1.assert)(this._sessions.indexOf(session) === -1, "session already added");
1028
+ session._client = this;
1029
+ this._sessions.push(session);
1030
+ }
1031
+ fetchServerCertificate(endpointUrl, callback) {
1032
+ const discoveryUrl = this.discoveryUrl.length > 0 ? this.discoveryUrl : endpointUrl;
1033
+ debugLog("OPCUAClientImpl : getting serverCertificate");
1034
+ // we have not been given the serverCertificate but this certificate
1035
+ // is required as the connection is to be secured.
1036
+ //
1037
+ // Let's explore the server endpoint that matches our security settings
1038
+ // This will give us the missing Certificate as well from the server.
1039
+ // todo :
1040
+ // Once we have the certificate, we cannot trust it straight away
1041
+ // we have to verify that the certificate is valid and not outdated and not revoked.
1042
+ // if the certificate is self-signed the certificate must appear in the trust certificate
1043
+ // list.
1044
+ // if the certificate has been certified by an Certificate Authority we have to
1045
+ // verify that the certificates in the chain are valid and not revoked.
1046
+ //
1047
+ const certificateFile = this.certificateFile;
1048
+ const privateKeyFile = this.privateKeyFile;
1049
+ const applicationName = this.applicationName;
1050
+ const applicationUri = this._applicationUri;
1051
+ const params = {
1052
+ connectionStrategy: this.connectionStrategy,
1053
+ endpointMustExist: false,
1054
+ securityMode: this.securityMode,
1055
+ securityPolicy: this.securityPolicy,
1056
+ applicationName,
1057
+ applicationUri,
1058
+ certificateFile,
1059
+ privateKeyFile,
1060
+ clientCertificateManager: this.clientCertificateManager
1061
+ };
1062
+ return __findEndpoint.call(this, discoveryUrl, params, (err, result) => {
1063
+ if (err) {
1064
+ return callback(err);
1065
+ }
1066
+ // istanbul ignore next
1067
+ if (!result) {
1068
+ const err1 = new Error("internal error");
1069
+ return callback(err1);
1070
+ }
1071
+ const endpoint = result.selectedEndpoint;
1072
+ if (!endpoint) {
1073
+ // no matching end point can be found ...
1074
+ const err1 = new Error("cannot find endpoint for securityMode=" +
1075
+ node_opcua_service_secure_channel_1.MessageSecurityMode[this.securityMode] +
1076
+ " policy = " +
1077
+ this.securityPolicy);
1078
+ return callback(err1);
1079
+ }
1080
+ (0, node_opcua_assert_1.assert)(endpoint);
1081
+ _verify_serverCertificate(this.clientCertificateManager, endpoint.serverCertificate, (err1) => {
1082
+ if (err1) {
1083
+ warningLog("[NODE-OPCUA-W25] client's server certificate verification has failed ", err1.message);
1084
+ warningLog(" ", this.clientCertificateManager.rootDir);
1085
+ warningLog(" ", endpoint.serverCertificate.toString("base64").replace(/(.{80})/g, "$1\n "));
1086
+ warningLog(" verify that server certificate is trusted or that server certificate issuer's certificate is present in the issuer folder");
1087
+ return callback(err1);
1088
+ }
1089
+ this.serverCertificate = endpoint.serverCertificate;
1090
+ callback(null, endpoint.endpointUrl);
1091
+ });
1092
+ });
1093
+ }
1094
+ _accumulate_statistics() {
1095
+ if (this._secureChannel) {
1096
+ // keep accumulated statistics
1097
+ this._byteWritten += this._secureChannel.bytesWritten;
1098
+ this._byteRead += this._secureChannel.bytesRead;
1099
+ this._transactionsPerformed += this._secureChannel.transactionsPerformed;
1100
+ this._timedOutRequestCount += this._secureChannel.timedOutRequestCount;
1101
+ if (doDebug) {
1102
+ debugLog(chalk.cyan(` Client ${this._instanceNumber} ${this.clientName} byteWritten = `), this._byteWritten);
1103
+ debugLog(chalk.cyan(` Client ${this._instanceNumber} ${this.clientName} byteRead = `), this._byteRead);
1104
+ debugLog(chalk.cyan(` Client ${this._instanceNumber} ${this.clientName} transactions = `), this._transactionsPerformed);
1105
+ debugLog(chalk.cyan(` Client ${this._instanceNumber} ${this.clientName} timedOutRequestCount = `), this._timedOutRequestCount);
1106
+ }
1107
+ }
1108
+ }
1109
+ _destroy_secure_channel() {
1110
+ if (this._secureChannel) {
1111
+ if (doDebug) {
1112
+ debugLog(" DESTROYING SECURE CHANNEL (isTransactionInProgress ?", this._secureChannel.isTransactionInProgress(), ")");
1113
+ }
1114
+ this._accumulate_statistics();
1115
+ this._secureChannel.dispose();
1116
+ this._secureChannel.removeAllListeners();
1117
+ this._secureChannel = null;
1118
+ }
1119
+ }
1120
+ _close_pending_sessions(callback) {
1121
+ const sessions = [...this._sessions];
1122
+ async.map(sessions, (session, next) => {
1123
+ (0, node_opcua_assert_1.assert)(session._client === this);
1124
+ // note: to prevent next to be call twice
1125
+ let _next_already_call = false;
1126
+ session.close((err) => {
1127
+ if (_next_already_call) {
1128
+ return;
1129
+ }
1130
+ _next_already_call = true;
1131
+ // We should not bother if we have an error here
1132
+ // Session may fail to close , if they haven't been activate and forcefully closed by server
1133
+ // in a attempt to preserve resources in the case of a DDOS attack for instance.
1134
+ if (err) {
1135
+ const msg = session.authenticationToken ? session.authenticationToken.toString() : "";
1136
+ debugLog(" failing to close session " + msg);
1137
+ }
1138
+ next();
1139
+ });
1140
+ }, (err) => {
1141
+ // istanbul ignore next
1142
+ if (this._sessions.length > 0) {
1143
+ debugLog(this._sessions
1144
+ .map((s) => (s.authenticationToken ? s.authenticationToken.toString() : ""))
1145
+ .join(" "));
1146
+ }
1147
+ (0, node_opcua_assert_1.assert)(this._sessions.length === 0, " failed to disconnect exiting sessions ");
1148
+ callback(err);
1149
+ });
1150
+ }
1151
+ _install_secure_channel_event_handlers(secureChannel) {
1152
+ (0, node_opcua_assert_1.assert)(this instanceof ClientBaseImpl);
1153
+ secureChannel.on("send_chunk", (chunk) => {
1154
+ /**
1155
+ * notify the observer that a message_chunk has been sent
1156
+ * @event send_chunk
1157
+ * @param message_chunk
1158
+ */
1159
+ this.emit("send_chunk", chunk);
1160
+ });
1161
+ secureChannel.on("receive_chunk", (chunk) => {
1162
+ /**
1163
+ * notify the observer that a message_chunk has been received
1164
+ * @event receive_chunk
1165
+ * @param message_chunk
1166
+ */
1167
+ this.emit("receive_chunk", chunk);
1168
+ });
1169
+ secureChannel.on("send_request", (message) => {
1170
+ /**
1171
+ * notify the observer that a request has been sent to the server.
1172
+ * @event send_request
1173
+ * @param message
1174
+ */
1175
+ this.emit("send_request", message);
1176
+ });
1177
+ secureChannel.on("receive_response", (message) => {
1178
+ /**
1179
+ * notify the observer that a response has been received from the server.
1180
+ * @event receive_response
1181
+ * @param message
1182
+ */
1183
+ this.emit("receive_response", message);
1184
+ });
1185
+ secureChannel.on("lifetime_75", (token) => {
1186
+ // secureChannel requests a new token
1187
+ debugLog("SecureChannel Security Token ", token.tokenId, "live time was =", token.revisedLifetime, " is about to expired , it's time to request a new token");
1188
+ // forward message to upper level
1189
+ this.emit("lifetime_75", token, secureChannel);
1190
+ });
1191
+ secureChannel.on("security_token_renewed", () => {
1192
+ // forward message to upper level
1193
+ this.emit("security_token_renewed", secureChannel);
1194
+ });
1195
+ secureChannel.on("close", (err) => {
1196
+ debugLog(chalk.yellow.bold(" ClientBaseImpl emitting close"), err === null || err === void 0 ? void 0 : err.message);
1197
+ if (!err || !this.reconnectOnFailure) {
1198
+ // this is a normal close operation initiated by us
1199
+ /**
1200
+ * @event close
1201
+ * @param error
1202
+ */
1203
+ this.emit("close", err);
1204
+ setImmediate(() => this._destroy_secure_channel());
1205
+ }
1206
+ else {
1207
+ /**
1208
+ * @event connection_lost
1209
+ */
1210
+ this.emit("connection_lost", err === null || err === void 0 ? void 0 : err.message); // instead of "close"
1211
+ this._repairConnection();
1212
+ }
1213
+ });
1214
+ secureChannel.on("timed_out_request", (request) => {
1215
+ /**
1216
+ * send when a request has timed out without receiving a response
1217
+ * @event timed_out_request
1218
+ * @param request
1219
+ */
1220
+ this.emit("timed_out_request", request);
1221
+ });
1222
+ }
1223
+ _repairConnection() {
1224
+ setImmediate(() => {
1225
+ debugLog("recreating new secure channel ");
1226
+ this._recreate_secure_channel((err1) => {
1227
+ debugLog("secureChannel#on(close) => _recreate_secure_channel returns ", err1 ? err1.message : "OK");
1228
+ if (err1) {
1229
+ // xx assert(!this._secureChannel);
1230
+ debugLog("_recreate_secure_channel has failed");
1231
+ this.emit("close", err1);
1232
+ this._setInternalState("disconnected");
1233
+ return;
1234
+ }
1235
+ else {
1236
+ this._finalReconnectionStep((err2) => {
1237
+ if (err2) {
1238
+ // istanbul ignore next
1239
+ if (doDebug) {
1240
+ debugLog("connection_reestablished has failed");
1241
+ debugLog("err= ", err2);
1242
+ }
1243
+ this.disconnect(() => {
1244
+ // we still need to retry connecting here !!!
1245
+ warningLog("Disconnected following reconnection failure", err2.message);
1246
+ warningLog("I will retry OPCUA client reconnection in 5 seconds");
1247
+ setTimeout(() => this._repairConnection(), 5000);
1248
+ });
1249
+ return;
1250
+ }
1251
+ else {
1252
+ /**
1253
+ * @event connection_reestablished
1254
+ * send when the connection is reestablished after a connection break
1255
+ */
1256
+ this.emit("connection_reestablished");
1257
+ this._setInternalState("connected");
1258
+ }
1259
+ });
1260
+ }
1261
+ });
1262
+ });
1263
+ }
1264
+ _finalReconnectionStep(callback) {
1265
+ // now delegate to upper class the
1266
+ if (this._on_connection_reestablished) {
1267
+ (0, node_opcua_assert_1.assert)(typeof this._on_connection_reestablished === "function");
1268
+ this._on_connection_reestablished((err2) => {
1269
+ callback(err2);
1270
+ });
1271
+ }
1272
+ else {
1273
+ callback();
1274
+ }
1275
+ }
1276
+ /**
1277
+ *
1278
+ * @internal
1279
+ * @private
1280
+ */
1281
+ __createSession_step2(session, callback) {
1282
+ throw new Error("Please override");
1283
+ }
1284
+ _activateSession(session, callback) {
1285
+ throw new Error("Please override");
1286
+ }
1287
+ }
1288
+ exports.ClientBaseImpl = ClientBaseImpl;
1289
+ // tslint:disable-next-line: max-classes-per-file
1290
+ class TmpClient extends ClientBaseImpl {
1291
+ constructor(options) {
1292
+ options.clientName = (options.clientName || "") + "_TmpClient";
1293
+ super(options);
1294
+ }
1295
+ connect(endpoint, callback) {
1296
+ debugLog("connecting to TmpClient");
1297
+ // istanbul ignore next
1298
+ if (this._internalState !== "disconnected") {
1299
+ callback(new Error("TmpClient#connect: invalid internal state " + this._internalState));
1300
+ return;
1301
+ }
1302
+ if (this.disconnecting) {
1303
+ return this._handleUnrecoverableConnectionFailure(new Error("premature disconnection 3"), callback);
1304
+ }
1305
+ this._setInternalState("connecting");
1306
+ this._connectStep2(endpoint, (err) => {
1307
+ if (this.disconnecting) {
1308
+ return this._handleUnrecoverableConnectionFailure(new Error("premature disconnection 4"), callback);
1309
+ }
1310
+ callback(err);
1311
+ });
1312
+ }
1313
+ }
1314
+ // tslint:disable:no-var-requires
1315
+ // tslint:disable:max-line-length
1316
+ const thenify = require("thenify");
1317
+ ClientBaseImpl.prototype.connect = thenify.withCallback(ClientBaseImpl.prototype.connect);
1318
+ ClientBaseImpl.prototype.disconnect = thenify.withCallback(ClientBaseImpl.prototype.disconnect);
1319
+ ClientBaseImpl.prototype.getEndpoints = thenify.withCallback(ClientBaseImpl.prototype.getEndpoints);
1320
+ ClientBaseImpl.prototype.findServers = thenify.withCallback(ClientBaseImpl.prototype.findServers);
1321
+ ClientBaseImpl.prototype.findServersOnNetwork = thenify.withCallback(ClientBaseImpl.prototype.findServersOnNetwork);
1322
+ client_base_1.OPCUAClientBase.create = (options) => {
1323
+ return new ClientBaseImpl(options);
1324
+ };
1317
1325
  //# sourceMappingURL=client_base_impl.js.map