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