node-opcua-server 2.156.0 → 2.158.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addressSpace_accessor.js +1 -0
- package/dist/addressSpace_accessor.js.map +1 -1
- package/dist/base_server.js +7 -1
- package/dist/base_server.js.map +1 -1
- package/dist/factory.js +1 -0
- package/dist/factory.js.map +1 -1
- package/dist/history_server_capabilities.js +14 -0
- package/dist/history_server_capabilities.js.map +1 -1
- package/dist/i_register_server_manager.d.ts +63 -3
- package/dist/i_register_server_manager.js +47 -0
- package/dist/i_register_server_manager.js.map +1 -1
- package/dist/i_server_side_publish_engine.js +4 -0
- package/dist/i_server_side_publish_engine.js.map +1 -1
- package/dist/index.d.ts +22 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -1
- package/dist/monitored_item.d.ts +3 -6
- package/dist/monitored_item.js +44 -17
- package/dist/monitored_item.js.map +1 -1
- package/dist/opcua_server.js +44 -26
- package/dist/opcua_server.js.map +1 -1
- package/dist/queue.js +2 -1
- package/dist/queue.js.map +1 -1
- package/dist/register_server_manager.d.ts +14 -26
- package/dist/register_server_manager.js +282 -293
- package/dist/register_server_manager.js.map +1 -1
- package/dist/register_server_manager_hidden.d.ts +4 -3
- package/dist/register_server_manager_hidden.js +7 -5
- package/dist/register_server_manager_hidden.js.map +1 -1
- package/dist/register_server_manager_mdns_only.d.ts +5 -3
- package/dist/register_server_manager_mdns_only.js +25 -14
- package/dist/register_server_manager_mdns_only.js.map +1 -1
- package/dist/server_capabilities.js +33 -0
- package/dist/server_capabilities.js.map +1 -1
- package/dist/server_end_point.js +29 -3
- package/dist/server_end_point.js.map +1 -1
- package/dist/server_engine.js +20 -3
- package/dist/server_engine.js.map +1 -1
- package/dist/server_publish_engine.js +95 -98
- package/dist/server_publish_engine.js.map +1 -1
- package/dist/server_session.js +33 -5
- package/dist/server_session.js.map +1 -1
- package/dist/server_subscription.js +70 -15
- package/dist/server_subscription.js.map +1 -1
- package/dist/user_manager.js +1 -0
- package/dist/user_manager.js.map +1 -1
- package/package.json +49 -47
- package/source/i_register_server_manager.ts +66 -5
- package/source/index.ts +22 -0
- package/source/monitored_item.ts +28 -19
- package/source/opcua_server.ts +33 -23
- package/source/register_server_manager.ts +294 -354
- package/source/register_server_manager_hidden.ts +6 -5
- package/source/register_server_manager_mdns_only.ts +25 -14
|
@@ -3,13 +3,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.RegisterServerManager =
|
|
6
|
+
exports.RegisterServerManager = void 0;
|
|
7
7
|
/**
|
|
8
8
|
* @module node-opcua-server
|
|
9
9
|
*/
|
|
10
10
|
// tslint:disable:no-console
|
|
11
11
|
const events_1 = require("events");
|
|
12
|
-
const async_1 = __importDefault(require("async"));
|
|
13
12
|
const chalk_1 = __importDefault(require("chalk"));
|
|
14
13
|
const node_opcua_assert_1 = require("node-opcua-assert");
|
|
15
14
|
const node_opcua_client_1 = require("node-opcua-client");
|
|
@@ -19,17 +18,10 @@ const node_opcua_secure_channel_1 = require("node-opcua-secure-channel");
|
|
|
19
18
|
const node_opcua_service_discovery_1 = require("node-opcua-service-discovery");
|
|
20
19
|
const node_opcua_types_1 = require("node-opcua-types");
|
|
21
20
|
const web_1 = require("node-opcua-crypto/web");
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
(function (RegisterServerManagerStatus) {
|
|
27
|
-
RegisterServerManagerStatus[RegisterServerManagerStatus["INACTIVE"] = 1] = "INACTIVE";
|
|
28
|
-
RegisterServerManagerStatus[RegisterServerManagerStatus["INITIALIZING"] = 2] = "INITIALIZING";
|
|
29
|
-
RegisterServerManagerStatus[RegisterServerManagerStatus["REGISTERING"] = 3] = "REGISTERING";
|
|
30
|
-
RegisterServerManagerStatus[RegisterServerManagerStatus["WAITING"] = 4] = "WAITING";
|
|
31
|
-
RegisterServerManagerStatus[RegisterServerManagerStatus["UNREGISTERING"] = 5] = "UNREGISTERING";
|
|
32
|
-
})(RegisterServerManagerStatus || (exports.RegisterServerManagerStatus = RegisterServerManagerStatus = {}));
|
|
21
|
+
const i_register_server_manager_1 = require("./i_register_server_manager");
|
|
22
|
+
const doDebug = (0, node_opcua_debug_1.checkDebugFlag)("REGISTER_LDS");
|
|
23
|
+
const debugLog = (0, node_opcua_debug_1.make_debugLog)("REGISTER_LDS");
|
|
24
|
+
const warningLog = (0, node_opcua_debug_1.make_warningLog)("REGISTER_LDS");
|
|
33
25
|
const g_DefaultRegistrationServerTimeout = 8 * 60 * 1000; // 8 minutes
|
|
34
26
|
function securityPolicyLevel(securityPolicy) {
|
|
35
27
|
switch (securityPolicy) {
|
|
@@ -100,7 +92,7 @@ function findSecureEndpoint(endpoints) {
|
|
|
100
92
|
}
|
|
101
93
|
function constructRegisteredServer(server, isOnline) {
|
|
102
94
|
const discoveryUrls = server.getDiscoveryUrls();
|
|
103
|
-
(0, node_opcua_assert_1.assert)(!isOnline || discoveryUrls.length >= 1, "expecting some discoveryUrls if we go online ....");
|
|
95
|
+
(0, node_opcua_assert_1.assert)(!isOnline || discoveryUrls.length >= 1, "expecting some discoveryUrls if we go online .... ");
|
|
104
96
|
const info = (0, web_1.exploreCertificate)(server.getCertificate());
|
|
105
97
|
const commonName = info.tbsCertificate.subject.commonName;
|
|
106
98
|
const serverUri = info.tbsCertificate.extensions?.subjectAltName.uniformResourceIdentifier[0];
|
|
@@ -150,9 +142,9 @@ function constructRegisterServer2Request(serverB, isOnline) {
|
|
|
150
142
|
server
|
|
151
143
|
});
|
|
152
144
|
}
|
|
153
|
-
const
|
|
154
|
-
initialDelay:
|
|
155
|
-
maxDelay:
|
|
145
|
+
const no_retry_connectivity_strategy = {
|
|
146
|
+
initialDelay: 1000,
|
|
147
|
+
maxDelay: 2000,
|
|
156
148
|
maxRetry: 1, // NO RETRY !!!
|
|
157
149
|
randomisationFactor: 0
|
|
158
150
|
};
|
|
@@ -162,17 +154,17 @@ const infinite_connectivity_strategy = {
|
|
|
162
154
|
maxRetry: 10000000,
|
|
163
155
|
randomisationFactor: 0
|
|
164
156
|
};
|
|
165
|
-
|
|
157
|
+
const pause = async (duration) => await new Promise((resolve) => setTimeout(resolve, duration));
|
|
158
|
+
async function sendRegisterServerRequest(server, client, isOnline) {
|
|
166
159
|
// try to send a RegisterServer2Request
|
|
167
160
|
const request = constructRegisterServer2Request(server, isOnline);
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
else {
|
|
161
|
+
await new Promise((resolve, reject) => {
|
|
162
|
+
client.performMessageTransaction(request, (err, response) => {
|
|
163
|
+
if (!err) {
|
|
164
|
+
// RegisterServerResponse
|
|
165
|
+
debugLog("RegisterServerManager#_registerServer sendRegisterServer2Request has succeeded (isOnline", isOnline, ")");
|
|
166
|
+
return resolve();
|
|
167
|
+
}
|
|
176
168
|
debugLog("RegisterServerManager#_registerServer sendRegisterServer2Request has failed " + "(isOnline", isOnline, ")");
|
|
177
169
|
debugLog("RegisterServerManager#_registerServer" + " falling back to using sendRegisterServerRequest instead");
|
|
178
170
|
// fall back to
|
|
@@ -180,26 +172,24 @@ function sendRegisterServerRequest(server, client, isOnline, callback) {
|
|
|
180
172
|
client.performMessageTransaction(request1, (err1, response1) => {
|
|
181
173
|
if (!err1) {
|
|
182
174
|
debugLog("RegisterServerManager#_registerServer sendRegisterServerRequest " + "has succeeded (isOnline", isOnline, ")");
|
|
183
|
-
|
|
184
|
-
}
|
|
185
|
-
else {
|
|
186
|
-
debugLog("RegisterServerManager#_registerServer sendRegisterServerRequest " + "has failed (isOnline", isOnline, ")");
|
|
175
|
+
return resolve();
|
|
187
176
|
}
|
|
188
|
-
|
|
177
|
+
debugLog("RegisterServerManager#_registerServer sendRegisterServerRequest " + "has failed (isOnline", isOnline, ")");
|
|
178
|
+
reject(err1);
|
|
189
179
|
});
|
|
190
|
-
}
|
|
180
|
+
});
|
|
191
181
|
});
|
|
192
182
|
}
|
|
193
183
|
let g_registeringClientCounter = 0;
|
|
194
184
|
/**
|
|
195
185
|
* RegisterServerManager is responsible to Register an opcua server on a LDS or LDS-ME server
|
|
196
186
|
* This class takes in charge :
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
187
|
+
* - the initial registration of a server
|
|
188
|
+
* - the regular registration renewal (every 8 minutes or so ...)
|
|
189
|
+
* - dealing with cases where LDS is not up and running when server starts.
|
|
190
|
+
* ( in this case the connection will be continuously attempted using the infinite
|
|
191
|
+
* back-off strategy
|
|
192
|
+
* - the un-registration of the server ( during shutdown for instance)
|
|
203
193
|
*
|
|
204
194
|
* Events:
|
|
205
195
|
*
|
|
@@ -223,13 +213,21 @@ let g_registeringClientCounter = 0;
|
|
|
223
213
|
* (LDS => Local Discovery Server)
|
|
224
214
|
*/
|
|
225
215
|
class RegisterServerManager extends events_1.EventEmitter {
|
|
216
|
+
discoveryServerEndpointUrl;
|
|
217
|
+
timeout;
|
|
218
|
+
server;
|
|
219
|
+
_registrationTimerId;
|
|
220
|
+
state = i_register_server_manager_1.RegisterServerManagerStatus.INACTIVE;
|
|
221
|
+
_registration_client = null;
|
|
222
|
+
selectedEndpoint;
|
|
223
|
+
_serverEndpoints = [];
|
|
224
|
+
getState() {
|
|
225
|
+
return this.state;
|
|
226
|
+
}
|
|
226
227
|
constructor(options) {
|
|
227
228
|
super();
|
|
228
|
-
this.state = RegisterServerManagerStatus.INACTIVE;
|
|
229
|
-
this._registration_client = null;
|
|
230
|
-
this._serverEndpoints = [];
|
|
231
229
|
this.server = options.server;
|
|
232
|
-
this
|
|
230
|
+
this.#_setState(i_register_server_manager_1.RegisterServerManagerStatus.INACTIVE);
|
|
233
231
|
this.timeout = g_DefaultRegistrationServerTimeout;
|
|
234
232
|
this.discoveryServerEndpointUrl = options.discoveryServerEndpointUrl || "opc.tcp://localhost:4840";
|
|
235
233
|
(0, node_opcua_assert_1.assert)(typeof this.discoveryServerEndpointUrl === "string");
|
|
@@ -238,7 +236,6 @@ class RegisterServerManager extends events_1.EventEmitter {
|
|
|
238
236
|
dispose() {
|
|
239
237
|
this.server = null;
|
|
240
238
|
debugLog("RegisterServerManager#dispose", this.state.toString());
|
|
241
|
-
(0, node_opcua_assert_1.assert)(this.state === RegisterServerManagerStatus.INACTIVE);
|
|
242
239
|
if (this._registrationTimerId) {
|
|
243
240
|
clearTimeout(this._registrationTimerId);
|
|
244
241
|
this._registrationTimerId = null;
|
|
@@ -246,335 +243,327 @@ class RegisterServerManager extends events_1.EventEmitter {
|
|
|
246
243
|
(0, node_opcua_assert_1.assert)(this._registrationTimerId === null, "stop has not been called");
|
|
247
244
|
this.removeAllListeners();
|
|
248
245
|
}
|
|
249
|
-
_emitEvent(eventName) {
|
|
246
|
+
#_emitEvent(eventName) {
|
|
250
247
|
setImmediate(() => {
|
|
248
|
+
debugLog("emiting event", eventName);
|
|
251
249
|
this.emit(eventName);
|
|
252
250
|
});
|
|
253
251
|
}
|
|
254
|
-
_setState(status) {
|
|
255
|
-
const previousState = this.state || RegisterServerManagerStatus.INACTIVE;
|
|
256
|
-
debugLog("RegisterServerManager#setState : ", RegisterServerManagerStatus[previousState], " => ", RegisterServerManagerStatus[status]);
|
|
252
|
+
#_setState(status) {
|
|
253
|
+
const previousState = this.state || i_register_server_manager_1.RegisterServerManagerStatus.INACTIVE;
|
|
254
|
+
debugLog("RegisterServerManager#setState : ", i_register_server_manager_1.RegisterServerManagerStatus[previousState], " => ", i_register_server_manager_1.RegisterServerManagerStatus[status]);
|
|
257
255
|
this.state = status;
|
|
258
256
|
}
|
|
259
|
-
|
|
257
|
+
/**
|
|
258
|
+
* The start method initiates the registration process in a non-blocking way.
|
|
259
|
+
* It immediately returns while the actual work is performed in a background task.
|
|
260
|
+
*/
|
|
261
|
+
async start() {
|
|
260
262
|
debugLog("RegisterServerManager#start");
|
|
261
|
-
if (this.state !== RegisterServerManagerStatus.INACTIVE) {
|
|
262
|
-
|
|
263
|
+
if (this.state !== i_register_server_manager_1.RegisterServerManagerStatus.INACTIVE) {
|
|
264
|
+
throw new Error("RegisterServer process already started: " + i_register_server_manager_1.RegisterServerManagerStatus[this.state]);
|
|
263
265
|
}
|
|
264
266
|
this.discoveryServerEndpointUrl = (0, node_opcua_hostname_1.resolveFullyQualifiedDomainName)(this.discoveryServerEndpointUrl);
|
|
265
|
-
//
|
|
266
|
-
this.
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
267
|
+
// Immediately set the state to INITIALIZING and run the process in the background.
|
|
268
|
+
this.#_setState(i_register_server_manager_1.RegisterServerManagerStatus.INITIALIZING);
|
|
269
|
+
// This method is called without await to ensure it is non-blocking.
|
|
270
|
+
// The catch block handles any synchronous errors.
|
|
271
|
+
this.#_runRegistrationProcess().catch((err) => {
|
|
272
|
+
warningLog("Synchronous error in #_runRegistrationProcess: ", (err?.message));
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Private method to run the entire registration process in the background.
|
|
277
|
+
* It handles the state machine transitions and re-connection logic.
|
|
278
|
+
* @private
|
|
279
|
+
*/
|
|
280
|
+
async #_runRegistrationProcess() {
|
|
281
|
+
while (this.getState() !== i_register_server_manager_1.RegisterServerManagerStatus.WAITING && !this.#_isTerminating()) {
|
|
282
|
+
debugLog("RegisterServerManager#_runRegistrationProcess - state =", i_register_server_manager_1.RegisterServerManagerStatus[this.state], "isTerminating =", this.#_isTerminating());
|
|
283
|
+
try {
|
|
284
|
+
if (this.getState() === i_register_server_manager_1.RegisterServerManagerStatus.INACTIVE) {
|
|
285
|
+
this.#_setState(i_register_server_manager_1.RegisterServerManagerStatus.INITIALIZING);
|
|
286
|
+
}
|
|
287
|
+
await this.#_establish_initial_connection();
|
|
288
|
+
if (this.getState() !== i_register_server_manager_1.RegisterServerManagerStatus.INITIALIZING) {
|
|
289
|
+
debugLog("RegisterServerManager#_runRegistrationProcess: aborted during initialization");
|
|
290
|
+
return;
|
|
279
291
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
292
|
+
this.#_setState(i_register_server_manager_1.RegisterServerManagerStatus.INITIALIZED);
|
|
293
|
+
this.#_setState(i_register_server_manager_1.RegisterServerManagerStatus.REGISTERING);
|
|
294
|
+
this.#_emitEvent("serverRegistrationPending");
|
|
295
|
+
await this.#_registerOrUnregisterServer(true);
|
|
296
|
+
if (this.getState() !== i_register_server_manager_1.RegisterServerManagerStatus.REGISTERING) {
|
|
297
|
+
debugLog("RegisterServerManager#_runRegistrationProcess: aborted during registration");
|
|
298
|
+
return;
|
|
285
299
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
300
|
+
this.#_setState(i_register_server_manager_1.RegisterServerManagerStatus.REGISTERED);
|
|
301
|
+
this.#_emitEvent("serverRegistered");
|
|
302
|
+
this.#_setState(i_register_server_manager_1.RegisterServerManagerStatus.WAITING);
|
|
303
|
+
this.#_trigger_next();
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
catch (err) {
|
|
307
|
+
debugLog("RegisterServerManager#_runRegistrationProcess - operation failed!", (err.message));
|
|
308
|
+
if (!this.#_isTerminating()) {
|
|
309
|
+
this.#_setState(i_register_server_manager_1.RegisterServerManagerStatus.INACTIVE);
|
|
310
|
+
this.#_emitEvent("serverRegistrationFailure");
|
|
311
|
+
await pause(Math.min(5000, this.timeout));
|
|
290
312
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
});
|
|
313
|
+
}
|
|
314
|
+
}
|
|
294
315
|
}
|
|
295
|
-
|
|
296
|
-
|
|
316
|
+
#_isTerminating() {
|
|
317
|
+
return this.getState() === i_register_server_manager_1.RegisterServerManagerStatus.UNREGISTERING || this.getState() === i_register_server_manager_1.RegisterServerManagerStatus.DISPOSING;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Establish the initial connection with the Discovery Server to extract best endpoint to use.
|
|
321
|
+
* @private
|
|
322
|
+
*/
|
|
323
|
+
async #_establish_initial_connection() {
|
|
297
324
|
if (!this.server) {
|
|
298
|
-
|
|
325
|
+
this.#_setState(i_register_server_manager_1.RegisterServerManagerStatus.DISPOSING);
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
if (this.state !== i_register_server_manager_1.RegisterServerManagerStatus.INITIALIZING) {
|
|
329
|
+
debugLog("RegisterServerManager#_establish_initial_connection: aborting due to state change");
|
|
330
|
+
return;
|
|
299
331
|
}
|
|
300
332
|
debugLog("RegisterServerManager#_establish_initial_connection");
|
|
301
333
|
(0, node_opcua_assert_1.assert)(!this._registration_client);
|
|
302
334
|
(0, node_opcua_assert_1.assert)(typeof this.discoveryServerEndpointUrl === "string");
|
|
303
|
-
(0, node_opcua_assert_1.assert)(this.state === RegisterServerManagerStatus.
|
|
304
|
-
this._setState(RegisterServerManagerStatus.INITIALIZING);
|
|
335
|
+
(0, node_opcua_assert_1.assert)(this.state === i_register_server_manager_1.RegisterServerManagerStatus.INITIALIZING);
|
|
305
336
|
this.selectedEndpoint = undefined;
|
|
306
337
|
const applicationName = (0, node_opcua_client_1.coerceLocalizedText)(this.server.serverInfo.applicationName)?.text || undefined;
|
|
307
|
-
// Retry Strategy must be set
|
|
308
338
|
this.server.serverCertificateManager.referenceCounter++;
|
|
309
|
-
const
|
|
339
|
+
const server = this.server;
|
|
340
|
+
const prefix = `Client-${g_registeringClientCounter++}`;
|
|
341
|
+
const action = "initializing";
|
|
342
|
+
const ldsInfo = this.discoveryServerEndpointUrl;
|
|
343
|
+
const serverInfo = this.server?.serverInfo.applicationUri;
|
|
344
|
+
const clientName = `${prefix} for server ${serverInfo} to LDS ${ldsInfo} for ${action}`;
|
|
310
345
|
const registrationClient = node_opcua_client_1.OPCUAClientBase.create({
|
|
311
|
-
clientName
|
|
346
|
+
clientName,
|
|
312
347
|
applicationName,
|
|
313
|
-
applicationUri:
|
|
348
|
+
applicationUri: server.serverInfo.applicationUri,
|
|
314
349
|
connectionStrategy: infinite_connectivity_strategy,
|
|
315
|
-
clientCertificateManager:
|
|
316
|
-
certificateFile:
|
|
317
|
-
privateKeyFile:
|
|
350
|
+
clientCertificateManager: server.serverCertificateManager,
|
|
351
|
+
certificateFile: server.certificateFile,
|
|
352
|
+
privateKeyFile: server.privateKeyFile
|
|
318
353
|
});
|
|
319
|
-
this._registration_client = registrationClient;
|
|
320
354
|
registrationClient.on("backoff", (nbRetry, delay) => {
|
|
355
|
+
if (this.state !== i_register_server_manager_1.RegisterServerManagerStatus.INITIALIZING)
|
|
356
|
+
return; // Ignore event if state has changed
|
|
321
357
|
debugLog("RegisterServerManager - received backoff");
|
|
322
|
-
|
|
323
|
-
this
|
|
358
|
+
debugLog(registrationClient.clientName, chalk_1.default.bgWhite.cyan("contacting discovery server backoff "), this.discoveryServerEndpointUrl, " attempt #", nbRetry, " retrying in ", delay / 1000.0, " seconds");
|
|
359
|
+
this.#_emitEvent("serverRegistrationPending");
|
|
324
360
|
});
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
});
|
|
335
|
-
},
|
|
336
|
-
// getEndpoints_on_discovery_server
|
|
337
|
-
(callback) => {
|
|
338
|
-
registrationClient.getEndpoints((err, endpoints) => {
|
|
339
|
-
if (!err) {
|
|
340
|
-
const endpoint = findSecureEndpoint(endpoints);
|
|
341
|
-
if (!endpoint) {
|
|
342
|
-
throw new Error("Cannot find Secure endpoint");
|
|
343
|
-
}
|
|
344
|
-
if (endpoint.serverCertificate) {
|
|
345
|
-
(0, node_opcua_assert_1.assert)(endpoint.serverCertificate);
|
|
346
|
-
this.selectedEndpoint = endpoint;
|
|
347
|
-
}
|
|
348
|
-
else {
|
|
349
|
-
this.selectedEndpoint = undefined;
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
else {
|
|
353
|
-
debugLog("RegisterServerManager#_establish_initial_connection " + ": getEndpointsRequest has failed");
|
|
354
|
-
debugLog(err);
|
|
355
|
-
}
|
|
356
|
-
callback(err);
|
|
357
|
-
});
|
|
358
|
-
},
|
|
359
|
-
// function closing_discovery_server_connection
|
|
360
|
-
(callback) => {
|
|
361
|
-
this._serverEndpoints = registrationClient._serverEndpoints;
|
|
362
|
-
registrationClient.disconnect((err) => {
|
|
363
|
-
this._registration_client = null;
|
|
364
|
-
callback(err);
|
|
365
|
-
});
|
|
366
|
-
},
|
|
367
|
-
// function wait_a_little_bit
|
|
368
|
-
(callback) => {
|
|
369
|
-
setTimeout(callback, 10);
|
|
370
|
-
}
|
|
371
|
-
], (err) => {
|
|
372
|
-
debugLog("-------------------------------", !!err);
|
|
373
|
-
if (this.state !== RegisterServerManagerStatus.INITIALIZING) {
|
|
374
|
-
debugLog("RegisterServerManager#_establish_initial_connection has been interrupted ", RegisterServerManagerStatus[this.state]);
|
|
375
|
-
this._setState(RegisterServerManagerStatus.INACTIVE);
|
|
376
|
-
if (this._registration_client) {
|
|
377
|
-
this._registration_client.disconnect((err2) => {
|
|
378
|
-
this._registration_client = null;
|
|
379
|
-
outer_callback(new Error("Initialization has been canceled"));
|
|
380
|
-
});
|
|
381
|
-
}
|
|
382
|
-
else {
|
|
383
|
-
outer_callback(new Error("Initialization has been canceled"));
|
|
384
|
-
}
|
|
361
|
+
// Keep track of the client to allow cancellation during connect()
|
|
362
|
+
this._registration_client = registrationClient;
|
|
363
|
+
try {
|
|
364
|
+
await registrationClient.connect(this.discoveryServerEndpointUrl);
|
|
365
|
+
if (!this._registration_client)
|
|
366
|
+
return;
|
|
367
|
+
// Re-check state after the long-running connect operation
|
|
368
|
+
if (this.state !== i_register_server_manager_1.RegisterServerManagerStatus.INITIALIZING) {
|
|
369
|
+
debugLog("RegisterServerManager#_establish_initial_connection: aborted after connection");
|
|
385
370
|
return;
|
|
386
371
|
}
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
372
|
+
const endpoints = await registrationClient.getEndpoints();
|
|
373
|
+
const endpoint = findSecureEndpoint(endpoints);
|
|
374
|
+
if (!endpoint) {
|
|
375
|
+
throw new Error("Cannot find Secure endpoint");
|
|
376
|
+
}
|
|
377
|
+
if (endpoint.serverCertificate) {
|
|
378
|
+
(0, node_opcua_assert_1.assert)(endpoint.serverCertificate);
|
|
379
|
+
this.selectedEndpoint = endpoint;
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
this.selectedEndpoint = undefined;
|
|
383
|
+
}
|
|
384
|
+
this._serverEndpoints = registrationClient._serverEndpoints;
|
|
385
|
+
}
|
|
386
|
+
catch (err) {
|
|
387
|
+
// Do not set state to INACTIVE or rethrow here, let the caller handle it.
|
|
388
|
+
throw err;
|
|
389
|
+
}
|
|
390
|
+
finally {
|
|
391
|
+
if (this._registration_client) {
|
|
392
|
+
const tmp = this._registration_client;
|
|
393
|
+
this._registration_client = null;
|
|
394
|
+
try {
|
|
395
|
+
await tmp.disconnect();
|
|
396
|
+
}
|
|
397
|
+
catch (err) {
|
|
398
|
+
warningLog("RegisterServerManager#_establish_initial_connection: error disconnecting client", err);
|
|
396
399
|
}
|
|
397
400
|
}
|
|
398
|
-
|
|
399
|
-
});
|
|
401
|
+
}
|
|
400
402
|
}
|
|
401
|
-
_trigger_next() {
|
|
403
|
+
#_trigger_next() {
|
|
402
404
|
(0, node_opcua_assert_1.assert)(!this._registrationTimerId);
|
|
403
|
-
(0, node_opcua_assert_1.assert)(this.state === RegisterServerManagerStatus.WAITING);
|
|
404
|
-
// from spec 1.04 part 4:
|
|
405
|
-
// The registration process is designed to be platform independent, robust and able to minimize
|
|
406
|
-
// problems created by configuration errors. For that reason, Servers shall register themselves more
|
|
407
|
-
// than once.
|
|
408
|
-
// Under normal conditions, manually launched Servers shall periodically register with the Discovery
|
|
409
|
-
// Server as long as they are able to receive connections from Clients. If a Server goes offline then it
|
|
410
|
-
// shall register itself once more and indicate that it is going offline. The registration frequency
|
|
411
|
-
// should be configurable; however, the maximum is 10 minutes. If an error occurs during registration
|
|
412
|
-
// (e.g. the Discovery Server is not running) then the Server shall periodically re-attempt registration.
|
|
413
|
-
// The frequency of these attempts should start at 1 second but gradually increase until the
|
|
414
|
-
// registration frequency is the same as what it would be if no errors occurred. The recommended
|
|
415
|
-
// approach would be to double the period of each attempt until reaching the maximum.
|
|
416
|
-
// When an automatically launched Server (or its install program) registers with the Discovery Server
|
|
417
|
-
// it shall provide a path to a semaphore file which the Discovery Server can use to determine if the
|
|
418
|
-
// Server has been uninstalled from the machine. The Discovery Server shall have read access to
|
|
419
|
-
// the file system that contains the file
|
|
420
|
-
// install a registration
|
|
405
|
+
(0, node_opcua_assert_1.assert)(this.state === i_register_server_manager_1.RegisterServerManagerStatus.WAITING);
|
|
421
406
|
debugLog("RegisterServerManager#_trigger_next " + ": installing timeout to perform registerServer renewal (timeout =", this.timeout, ")");
|
|
407
|
+
if (this._registrationTimerId)
|
|
408
|
+
clearTimeout(this._registrationTimerId);
|
|
422
409
|
this._registrationTimerId = setTimeout(() => {
|
|
423
410
|
if (!this._registrationTimerId) {
|
|
424
411
|
debugLog("RegisterServerManager => cancelling re registration");
|
|
425
412
|
return;
|
|
426
413
|
}
|
|
427
414
|
this._registrationTimerId = null;
|
|
415
|
+
if (this.#_isTerminating()) {
|
|
416
|
+
debugLog("RegisterServerManager#_trigger_next : cancelling re registration");
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
428
419
|
debugLog("RegisterServerManager#_trigger_next : renewing RegisterServer");
|
|
429
|
-
|
|
430
|
-
if (this
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
this
|
|
434
|
-
this
|
|
435
|
-
this._trigger_next();
|
|
420
|
+
const after_register = (err) => {
|
|
421
|
+
if (!this.#_isTerminating()) {
|
|
422
|
+
debugLog("RegisterServerManager#_trigger_next : renewed ! err:", err?.message);
|
|
423
|
+
this.#_setState(i_register_server_manager_1.RegisterServerManagerStatus.WAITING);
|
|
424
|
+
this.#_emitEvent("serverRegistrationRenewed");
|
|
425
|
+
this.#_trigger_next();
|
|
436
426
|
}
|
|
437
|
-
}
|
|
427
|
+
};
|
|
428
|
+
// State transition before the call
|
|
429
|
+
this.#_setState(i_register_server_manager_1.RegisterServerManagerStatus.REGISTERING);
|
|
430
|
+
this.#_emitEvent("serverRegistrationPending");
|
|
431
|
+
this.#_registerOrUnregisterServer(/*isOnline=*/ true)
|
|
432
|
+
.then(() => after_register())
|
|
433
|
+
.catch((err) => after_register(err));
|
|
438
434
|
}, this.timeout);
|
|
439
435
|
}
|
|
440
|
-
stop(
|
|
436
|
+
async stop() {
|
|
441
437
|
debugLog("RegisterServerManager#stop");
|
|
438
|
+
if (this.#_isTerminating()) {
|
|
439
|
+
debugLog("Already stopping or stopped...");
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
// make sure we don't have any timer running
|
|
443
|
+
// so a registration renewal won't happen while we are stopping
|
|
442
444
|
if (this._registrationTimerId) {
|
|
443
|
-
debugLog("RegisterServerManager#stop :clearing timeout");
|
|
444
445
|
clearTimeout(this._registrationTimerId);
|
|
445
446
|
this._registrationTimerId = null;
|
|
446
447
|
}
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
448
|
+
// Immediately set state to signal a stop
|
|
449
|
+
this.#_setState(i_register_server_manager_1.RegisterServerManagerStatus.UNREGISTERING);
|
|
450
|
+
// Cancel any pending client connections
|
|
451
|
+
await this.#_cancel_pending_client_if_any();
|
|
452
|
+
if (this.selectedEndpoint) {
|
|
453
|
+
try {
|
|
454
|
+
await this.#_registerOrUnregisterServer(/* isOnline= */ false);
|
|
455
|
+
this.#_setState(i_register_server_manager_1.RegisterServerManagerStatus.UNREGISTERED);
|
|
456
|
+
this.#_emitEvent("serverUnregistered");
|
|
453
457
|
}
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
458
|
+
catch (err) {
|
|
459
|
+
warningLog(err);
|
|
460
|
+
warningLog("RegisterServerManager#stop: Unregistration failed.", err.message);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
// Final state transition to INACTIVE
|
|
464
|
+
this.#_setState(i_register_server_manager_1.RegisterServerManagerStatus.DISPOSING);
|
|
460
465
|
}
|
|
461
466
|
/**
|
|
462
|
-
*
|
|
463
|
-
*
|
|
467
|
+
* Handles the actual registration/unregistration request.
|
|
468
|
+
* It is designed to be interruptible by checking the state.
|
|
469
|
+
* @param isOnline - true for registration, false for unregistration
|
|
464
470
|
* @private
|
|
465
471
|
*/
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
472
|
+
async #_registerOrUnregisterServer(isOnline) {
|
|
473
|
+
const expectedState = isOnline ? i_register_server_manager_1.RegisterServerManagerStatus.REGISTERING : i_register_server_manager_1.RegisterServerManagerStatus.UNREGISTERING;
|
|
474
|
+
if (this.getState() !== expectedState) {
|
|
475
|
+
debugLog("RegisterServerManager#_registerServer: aborting due to state change");
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
debugLog("RegisterServerManager#_registerServer isOnline:", isOnline);
|
|
479
|
+
(0, node_opcua_assert_1.assert)(this.selectedEndpoint, "must have a selected endpoint");
|
|
470
480
|
(0, node_opcua_assert_1.assert)(this.server.serverType !== undefined, " must have a valid server Type");
|
|
471
|
-
// construct connection
|
|
472
481
|
const server = this.server;
|
|
473
482
|
const selectedEndpoint = this.selectedEndpoint;
|
|
474
483
|
if (!selectedEndpoint) {
|
|
475
|
-
warningLog("Warning
|
|
476
|
-
|
|
484
|
+
warningLog("Warning: cannot register server - no endpoint available");
|
|
485
|
+
// Do not rethrow here, let the caller handle it.
|
|
486
|
+
return;
|
|
477
487
|
}
|
|
478
488
|
server.serverCertificateManager.referenceCounter++;
|
|
479
489
|
const applicationName = (0, node_opcua_client_1.coerceLocalizedText)(server.serverInfo.applicationName)?.text || undefined;
|
|
480
|
-
const
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
warningLog(`Warning there is already a registering/un-registering task taking place: ${RegisterServerManagerStatus[this.state]} state`);
|
|
492
|
-
}
|
|
493
|
-
const options = {
|
|
490
|
+
const prefix = `Client-${g_registeringClientCounter++}`;
|
|
491
|
+
const action = isOnline ? "registering" : "unregistering";
|
|
492
|
+
const ldsInfo = this.discoveryServerEndpointUrl;
|
|
493
|
+
const serverInfo = server.serverInfo.applicationUri;
|
|
494
|
+
const clientName = `${prefix} for server ${serverInfo} to LDS ${ldsInfo} for ${action}`;
|
|
495
|
+
const client = node_opcua_client_1.OPCUAClientBase.create({
|
|
496
|
+
clientName,
|
|
497
|
+
applicationName,
|
|
498
|
+
applicationUri: server.serverInfo.applicationUri,
|
|
499
|
+
connectionStrategy: no_retry_connectivity_strategy,
|
|
500
|
+
clientCertificateManager: server.serverCertificateManager,
|
|
494
501
|
securityMode: selectedEndpoint.securityMode,
|
|
495
502
|
securityPolicy: (0, node_opcua_secure_channel_1.coerceSecurityPolicy)(selectedEndpoint.securityPolicyUri),
|
|
496
503
|
serverCertificate: selectedEndpoint.serverCertificate,
|
|
497
|
-
clientCertificateManager: server.serverCertificateManager,
|
|
498
504
|
certificateFile: server.certificateFile,
|
|
499
505
|
privateKeyFile: server.privateKeyFile,
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
clientName: "server client to LDS " + RegisterServerManagerStatus[theStatus]
|
|
505
|
-
};
|
|
506
|
-
const client = node_opcua_client_1.OPCUAClientBase.create(options);
|
|
507
|
-
const tmp = this._serverEndpoints;
|
|
508
|
-
client._serverEndpoints = tmp;
|
|
506
|
+
});
|
|
507
|
+
client.on("backoff", (nbRetry, delay) => {
|
|
508
|
+
debugLog(client.clientCertificateManager, "backoff trying to connect to the LDS has failed", nbRetry, delay);
|
|
509
|
+
});
|
|
509
510
|
this._registration_client = client;
|
|
510
|
-
debugLog("
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
//
|
|
515
|
-
(
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
if (err) {
|
|
519
|
-
debugLog("RegisterServerManager#_registerServer connection to client has failed");
|
|
520
|
-
debugLog("RegisterServerManager#_registerServer " +
|
|
521
|
-
"=> please check that you server certificate is trusted by the LDS");
|
|
522
|
-
warningLog("RegisterServer to the LDS has failed during secure connection " +
|
|
523
|
-
"=> please check that you server certificate is trusted by the LDS.", "\nerr: " + err.message, "\nLDS endpoint :", selectedEndpoint.endpointUrl, "\nsecurity mode :", node_opcua_secure_channel_1.MessageSecurityMode[selectedEndpoint.securityMode], "\nsecurity policy :", (0, node_opcua_secure_channel_1.coerceSecurityPolicy)(selectedEndpoint.securityPolicyUri));
|
|
524
|
-
// xx debugLog(options);
|
|
525
|
-
client.disconnect(() => {
|
|
526
|
-
this._registration_client = null;
|
|
527
|
-
debugLog("RegisterServerManager#_registerServer client disconnected");
|
|
528
|
-
callback( /* intentionally no error propagation*/);
|
|
529
|
-
});
|
|
530
|
-
}
|
|
531
|
-
else {
|
|
532
|
-
callback();
|
|
533
|
-
}
|
|
534
|
-
});
|
|
535
|
-
},
|
|
536
|
-
(callback) => {
|
|
537
|
-
if (!this._registration_client) {
|
|
538
|
-
callback();
|
|
539
|
-
return;
|
|
511
|
+
debugLog("lds endpoint uri : ", selectedEndpoint.endpointUrl);
|
|
512
|
+
const state = isOnline ? "UnRegisterServer" : "RegisterServer";
|
|
513
|
+
try {
|
|
514
|
+
await client.connect(selectedEndpoint.endpointUrl);
|
|
515
|
+
// Check state again after connection is established
|
|
516
|
+
if (this.getState() === expectedState) {
|
|
517
|
+
try {
|
|
518
|
+
await sendRegisterServerRequest(server, client, isOnline);
|
|
540
519
|
}
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
(callback) => {
|
|
547
|
-
if (!this._registration_client) {
|
|
548
|
-
callback();
|
|
549
|
-
return;
|
|
520
|
+
catch (err) {
|
|
521
|
+
if (this.getState() !== expectedState) {
|
|
522
|
+
warningLog(`${state} '${this.server.serverInfo.applicationUri}' to the LDS has failed during secure connection to the LDS server`);
|
|
523
|
+
warningLog(chalk_1.default.red(" Error message:"), err.message); // Do not rethrow here, let the caller
|
|
524
|
+
}
|
|
550
525
|
}
|
|
551
|
-
client.disconnect(callback);
|
|
552
526
|
}
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
527
|
+
else {
|
|
528
|
+
debugLog("RegisterServerManager#_registerServer: aborted ");
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
catch (err) {
|
|
532
|
+
if (this.getState() !== expectedState) {
|
|
533
|
+
warningLog(`${state} '${this.server.serverInfo.applicationUri}' cannot connect to LDS at endpoint ${client.clientName}, ${selectedEndpoint.endpointUrl} :`);
|
|
534
|
+
warningLog(chalk_1.default.red(" Error message:"), err.message);
|
|
558
535
|
}
|
|
559
|
-
|
|
560
|
-
|
|
536
|
+
}
|
|
537
|
+
finally {
|
|
538
|
+
if (this._registration_client) {
|
|
539
|
+
const tmp = this._registration_client;
|
|
561
540
|
this._registration_client = null;
|
|
562
|
-
|
|
563
|
-
}
|
|
564
|
-
}
|
|
541
|
+
await tmp.disconnect();
|
|
542
|
+
}
|
|
543
|
+
}
|
|
565
544
|
}
|
|
566
|
-
|
|
545
|
+
/**
|
|
546
|
+
* Cancels any pending client connections.
|
|
547
|
+
* This is crucial for a clean shutdown.
|
|
548
|
+
* @private
|
|
549
|
+
*/
|
|
550
|
+
async #_cancel_pending_client_if_any() {
|
|
567
551
|
debugLog("RegisterServerManager#_cancel_pending_client_if_any");
|
|
568
552
|
if (this._registration_client) {
|
|
569
|
-
|
|
570
|
-
this._registration_client
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
553
|
+
const client = this._registration_client;
|
|
554
|
+
this._registration_client = null;
|
|
555
|
+
debugLog("RegisterServerManager#_cancel_pending_client_if_any "
|
|
556
|
+
+ "=> wee need to disconnect_registration_client");
|
|
557
|
+
try {
|
|
558
|
+
await client.disconnect();
|
|
559
|
+
}
|
|
560
|
+
catch (err) {
|
|
561
|
+
warningLog("Error disconnecting registration client:", err.message);
|
|
562
|
+
}
|
|
563
|
+
await this.#_cancel_pending_client_if_any(); // Recursive call to ensure all are handled
|
|
574
564
|
}
|
|
575
565
|
else {
|
|
576
566
|
debugLog("RegisterServerManager#_cancel_pending_client_if_any : done (nothing to do)");
|
|
577
|
-
callback();
|
|
578
567
|
}
|
|
579
568
|
}
|
|
580
569
|
}
|