node-opcua-server-discovery 2.156.0 → 2.157.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/mdns_responder.d.ts +2 -4
- package/dist/mdns_responder.js +31 -13
- package/dist/mdns_responder.js.map +1 -1
- package/dist/opcua_discovery_server.d.ts +9 -9
- package/dist/opcua_discovery_server.js +231 -197
- package/dist/opcua_discovery_server.js.map +1 -1
- package/package.json +17 -15
- package/source/mdns_responder.ts +27 -17
- package/source/opcua_discovery_server.ts +311 -249
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import os from "os";
|
|
6
6
|
import path from "path";
|
|
7
|
-
import
|
|
7
|
+
import { URL } from "url";
|
|
8
8
|
import { callbackify } from "util";
|
|
9
9
|
|
|
10
10
|
import chalk from "chalk";
|
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
RegisterServer2Response,
|
|
41
41
|
RegisterServerRequest,
|
|
42
42
|
RegisterServerResponse,
|
|
43
|
-
|
|
43
|
+
isSameService,
|
|
44
44
|
serviceToString,
|
|
45
45
|
announcementToServiceConfig,
|
|
46
46
|
ServerOnNetwork
|
|
@@ -52,9 +52,9 @@ import { ErrorCallback, StatusCode, StatusCodes } from "node-opcua-status-code";
|
|
|
52
52
|
|
|
53
53
|
import { MDNSResponder } from "./mdns_responder";
|
|
54
54
|
|
|
55
|
-
const debugLog = make_debugLog(
|
|
56
|
-
const doDebug = checkDebugFlag(
|
|
57
|
-
const errorLog = make_errorLog(
|
|
55
|
+
const debugLog = make_debugLog("LDSSERVER");
|
|
56
|
+
const doDebug = checkDebugFlag("LDSSERVER");
|
|
57
|
+
const errorLog = make_errorLog("LDSSERVER");
|
|
58
58
|
|
|
59
59
|
function hasCapabilities(serverCapabilities: UAString[] | null, serverCapabilityFilter: string): boolean {
|
|
60
60
|
if (serverCapabilities == null) {
|
|
@@ -81,9 +81,8 @@ interface RegisteredServerExtended extends RegisteredServer {
|
|
|
81
81
|
discoveryConfiguration?: MdnsDiscoveryConfiguration[];
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
84
|
+
type RegisterServerMap = Map<string, RegisteredServerExtended>;
|
|
85
|
+
|
|
87
86
|
|
|
88
87
|
const defaultProductUri = "NodeOPCUA-LocalDiscoveryServer";
|
|
89
88
|
const defaultApplicationUri = makeApplicationUrn(os.hostname(), defaultProductUri);
|
|
@@ -98,14 +97,23 @@ function getDefaultCertificateManager(): OPCUACertificateManager {
|
|
|
98
97
|
});
|
|
99
98
|
}
|
|
100
99
|
|
|
100
|
+
export interface OPCUADiscoveryServer {
|
|
101
|
+
on(eventName: "onUnregisterServer", eventHandler: (server: RegisteredServer, forced: boolean) => void): this;
|
|
102
|
+
on(eventName: "onRegisterServer", eventHandler: (server: RegisteredServer, firstTime: boolean) => void): this;
|
|
103
|
+
once(eventName: "onUnregisterServer", eventHandler: (server: RegisteredServer, forced: boolean) => void): this;
|
|
104
|
+
once(eventName: "onRegisterServer", eventHandler: (server: RegisteredServer, firstTime: boolean) => void): this;
|
|
105
|
+
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// const weakMap = new WeakMap<MdnsDiscoveryConfiguration, BonjourHolder>;
|
|
109
|
+
|
|
101
110
|
export class OPCUADiscoveryServer extends OPCUABaseServer {
|
|
111
|
+
private mDnsLDSAnnouncer?: BonjourHolder;
|
|
102
112
|
public mDnsResponder?: MDNSResponder;
|
|
103
113
|
public readonly registeredServers: RegisterServerMap;
|
|
104
114
|
|
|
105
|
-
private
|
|
106
|
-
private _delayInit?: () => void;
|
|
115
|
+
private _delayInit?: () => Promise<void>;
|
|
107
116
|
|
|
108
|
-
|
|
109
117
|
constructor(options: OPCUADiscoveryServerOptions) {
|
|
110
118
|
options.serverInfo = options.serverInfo || {};
|
|
111
119
|
const serverInfo = options.serverInfo;
|
|
@@ -118,7 +126,6 @@ export class OPCUADiscoveryServer extends OPCUABaseServer {
|
|
|
118
126
|
|
|
119
127
|
serverInfo.applicationName = serverInfo.applicationName || {
|
|
120
128
|
text: defaultProductUri,
|
|
121
|
-
|
|
122
129
|
locale: null
|
|
123
130
|
};
|
|
124
131
|
|
|
@@ -130,14 +137,13 @@ export class OPCUADiscoveryServer extends OPCUABaseServer {
|
|
|
130
137
|
|
|
131
138
|
super(options);
|
|
132
139
|
|
|
133
|
-
this.bonjourHolder = new BonjourHolder();
|
|
134
140
|
|
|
135
141
|
// see OPC UA Spec 1.2 part 6 : 7.4 Well Known Addresses
|
|
136
142
|
// opc.tcp://localhost:4840/UADiscovery
|
|
137
143
|
const port = options.port || 4840;
|
|
138
144
|
|
|
139
145
|
this.capabilitiesForMDNS = ["LDS"];
|
|
140
|
-
this.registeredServers =
|
|
146
|
+
this.registeredServers = new Map();
|
|
141
147
|
|
|
142
148
|
this.mDnsResponder = undefined;
|
|
143
149
|
|
|
@@ -173,9 +179,7 @@ export class OPCUADiscoveryServer extends OPCUABaseServer {
|
|
|
173
179
|
};
|
|
174
180
|
}
|
|
175
181
|
|
|
176
|
-
public async start(): Promise<void
|
|
177
|
-
public start(callback: ErrorCallback): void;
|
|
178
|
-
public start(callback?: ErrorCallback): any {
|
|
182
|
+
public async start(): Promise<void> {
|
|
179
183
|
assert(!this.mDnsResponder);
|
|
180
184
|
assert(Array.isArray(this.capabilitiesForMDNS));
|
|
181
185
|
|
|
@@ -183,61 +187,72 @@ export class OPCUADiscoveryServer extends OPCUABaseServer {
|
|
|
183
187
|
await this._delayInit!();
|
|
184
188
|
});
|
|
185
189
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
);
|
|
207
|
-
});
|
|
190
|
+
await new Promise<void>((resolve, reject) =>
|
|
191
|
+
super.start((err?: Error | null) =>
|
|
192
|
+
err ? reject(err) : resolve()));
|
|
193
|
+
|
|
194
|
+
const endpointUri = this.getEndpointUrl();
|
|
195
|
+
const { hostname } = new URL(endpointUri);
|
|
196
|
+
|
|
197
|
+
this.mDnsResponder = new MDNSResponder();
|
|
198
|
+
|
|
199
|
+
this.mDnsLDSAnnouncer = new BonjourHolder();
|
|
200
|
+
|
|
201
|
+
// declare the discovery server itself in bonjour
|
|
202
|
+
await this.mDnsLDSAnnouncer.announcedOnMulticastSubnet(
|
|
203
|
+
{
|
|
204
|
+
capabilities: this.capabilitiesForMDNS,
|
|
205
|
+
name: this.serverInfo.applicationUri!,
|
|
206
|
+
path: "/DiscoveryServer",
|
|
207
|
+
host: hostname || "",
|
|
208
|
+
port: this.endpoints[0].port
|
|
209
|
+
});
|
|
208
210
|
}
|
|
209
211
|
|
|
210
|
-
public async shutdown(): Promise<void>;
|
|
211
|
-
public shutdown(callback: ErrorCallback): void;
|
|
212
|
-
public shutdown(callback?: ErrorCallback): any {
|
|
213
|
-
debugLog("stopping announcement of LDS on mDNS");
|
|
214
212
|
|
|
213
|
+
#shutting_down = false;
|
|
214
|
+
public async shutdown(): Promise<void> {
|
|
215
|
+
if (this.#shutting_down) return;
|
|
216
|
+
this.#shutting_down = true;
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
debugLog("stopping announcement of LDS on mDNS");
|
|
222
|
+
//
|
|
223
|
+
for (const registeredServer of this.registeredServers.values()) {
|
|
224
|
+
debugLog("LDS is shutting down and is forcefuly unregistering server", registeredServer.serverUri);
|
|
225
|
+
await this.#internalRegisterServerOffline(registeredServer, true);
|
|
226
|
+
}
|
|
227
|
+
|
|
215
228
|
if (this.mDnsResponder) {
|
|
216
|
-
|
|
229
|
+
debugLog("disposing mDnsResponder");
|
|
230
|
+
await this.mDnsResponder.dispose();
|
|
217
231
|
this.mDnsResponder = undefined;
|
|
232
|
+
debugLog(" mDnsResponder disposed");
|
|
218
233
|
}
|
|
219
234
|
|
|
220
|
-
this.
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
debugLog("stopping announcement of LDS on mDNS - DONE");
|
|
226
|
-
debugLog("Shutting down Discovery Server");
|
|
235
|
+
if (this.mDnsLDSAnnouncer) {
|
|
236
|
+
debugLog("disposing mDnsLDSAnnouncer of this LDS to the mDNS");
|
|
237
|
+
await this.mDnsLDSAnnouncer.stopAnnouncedOnMulticastSubnet();
|
|
238
|
+
this.mDnsLDSAnnouncer = undefined;
|
|
239
|
+
}
|
|
227
240
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
241
|
+
debugLog("Shutting down Discovery Server");
|
|
242
|
+
await new Promise<void>((resolve, reject) =>
|
|
243
|
+
super.shutdown((err) => err ? reject(err) : resolve())
|
|
244
|
+
);
|
|
245
|
+
debugLog("stopping announcement of LDS on mDNS - DONE");
|
|
246
|
+
// add a extra delay to ensure that the port is really closed
|
|
247
|
+
// and registered server propagated the fact that LDS is not here anymore
|
|
248
|
+
await new Promise<void>((resolve) => setTimeout(resolve, 1000));
|
|
234
249
|
}
|
|
235
250
|
|
|
236
251
|
/**
|
|
237
252
|
* returns the number of registered servers
|
|
238
253
|
*/
|
|
239
254
|
public get registeredServerCount(): number {
|
|
240
|
-
return
|
|
255
|
+
return this.registeredServers.size;
|
|
241
256
|
}
|
|
242
257
|
|
|
243
258
|
public getServers(channel: ServerSecureChannelLayer): ApplicationDescription[] {
|
|
@@ -245,7 +260,7 @@ export class OPCUADiscoveryServer extends OPCUABaseServer {
|
|
|
245
260
|
|
|
246
261
|
const servers: ApplicationDescription[] = [this.serverInfo];
|
|
247
262
|
|
|
248
|
-
for (const registered_server of
|
|
263
|
+
for (const registered_server of this.registeredServers.values()) {
|
|
249
264
|
const serverInfo: ApplicationDescription = new ApplicationDescription(registered_server.serverInfo);
|
|
250
265
|
servers.push(serverInfo);
|
|
251
266
|
}
|
|
@@ -260,43 +275,55 @@ export class OPCUADiscoveryServer extends OPCUABaseServer {
|
|
|
260
275
|
assert(request.schema.name === "RegisterServer2Request");
|
|
261
276
|
|
|
262
277
|
request.discoveryConfiguration = request.discoveryConfiguration || [];
|
|
263
|
-
this
|
|
278
|
+
this.#internalRegisterServer(
|
|
264
279
|
RegisterServer2Response,
|
|
265
280
|
request.server,
|
|
266
281
|
request.discoveryConfiguration as MdnsDiscoveryConfiguration[],
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
response = OPCUADiscoveryServer.makeServiceFault(StatusCodes.BadInternalError, additional_messages);
|
|
280
|
-
channel.send_response("MSG", response, message);
|
|
281
|
-
} else {
|
|
282
|
-
channel.send_response("MSG", response!, message);
|
|
283
|
-
}
|
|
282
|
+
).then((response?: Response) => {
|
|
283
|
+
channel.send_response("MSG", response!, message);
|
|
284
|
+
}).catch((err: Error) => {
|
|
285
|
+
errorLog("What shall I do ?", err.message);
|
|
286
|
+
errorLog(err);
|
|
287
|
+
let additional_messages = [];
|
|
288
|
+
additional_messages.push("EXCEPTION CAUGHT WHILE PROCESSING REQUEST !!! " + request.schema.name);
|
|
289
|
+
additional_messages.push(err.message);
|
|
290
|
+
if (err.stack) {
|
|
291
|
+
additional_messages = additional_messages.concat(err.stack.split("\n"));
|
|
284
292
|
}
|
|
285
|
-
|
|
293
|
+
|
|
294
|
+
const response = OPCUADiscoveryServer.makeServiceFault(
|
|
295
|
+
StatusCodes.BadInternalError,
|
|
296
|
+
additional_messages
|
|
297
|
+
);
|
|
298
|
+
channel.send_response("MSG", response, message);
|
|
299
|
+
});
|
|
300
|
+
// istanbul ignore next
|
|
286
301
|
}
|
|
287
302
|
|
|
288
303
|
protected _on_RegisterServerRequest(message: Message, channel: ServerSecureChannelLayer) {
|
|
289
304
|
assert(message.request instanceof RegisterServerRequest);
|
|
290
305
|
const request = message.request as RegisterServerRequest;
|
|
291
306
|
assert(request.schema.name === "RegisterServerRequest");
|
|
292
|
-
this
|
|
307
|
+
this.#internalRegisterServer(
|
|
293
308
|
RegisterServerResponse,
|
|
294
309
|
request.server,
|
|
295
|
-
undefined
|
|
296
|
-
|
|
310
|
+
undefined).then((response) => {
|
|
311
|
+
|
|
297
312
|
channel.send_response("MSG", response!, message);
|
|
298
|
-
|
|
299
|
-
|
|
313
|
+
|
|
314
|
+
}).catch((err: Error) => {
|
|
315
|
+
let additional_messages = [];
|
|
316
|
+
additional_messages.push("EXCEPTION CAUGHT WHILE PROCESSING REQUEST !!! " + request.schema.name);
|
|
317
|
+
additional_messages.push(err.message);
|
|
318
|
+
if (err.stack) {
|
|
319
|
+
additional_messages = additional_messages.concat(err.stack.split("\n"));
|
|
320
|
+
}
|
|
321
|
+
const response = OPCUADiscoveryServer.makeServiceFault(
|
|
322
|
+
StatusCodes.BadInternalError,
|
|
323
|
+
additional_messages
|
|
324
|
+
);
|
|
325
|
+
channel.send_response("MSG", response, message);
|
|
326
|
+
});
|
|
300
327
|
}
|
|
301
328
|
|
|
302
329
|
protected _on_FindServersOnNetworkRequest(message: Message, channel: ServerSecureChannelLayer) {
|
|
@@ -328,6 +355,10 @@ export class OPCUADiscoveryServer extends OPCUABaseServer {
|
|
|
328
355
|
return channel.send_response("MSG", response1, message);
|
|
329
356
|
} sendError;
|
|
330
357
|
|
|
358
|
+
if(this.#shutting_down) {
|
|
359
|
+
return sendError(StatusCodes.BadShutdown);
|
|
360
|
+
}
|
|
361
|
+
|
|
331
362
|
// startingRecordId Counter Only records with an identifier greater than this number will be
|
|
332
363
|
// returned.
|
|
333
364
|
// Specify 0 to start with the first record in the cache.
|
|
@@ -358,27 +389,27 @@ export class OPCUADiscoveryServer extends OPCUABaseServer {
|
|
|
358
389
|
debugLog(" startingRecordId = ", request.startingRecordId);
|
|
359
390
|
|
|
360
391
|
if (this.mDnsResponder) {
|
|
361
|
-
for (const
|
|
362
|
-
debugLog("Exploring server ",
|
|
392
|
+
for (const serverOnNetwork of this.mDnsResponder.registeredServers) {
|
|
393
|
+
debugLog("Exploring server ", serverOnNetwork.serverName);
|
|
363
394
|
|
|
364
|
-
if (
|
|
395
|
+
if (serverOnNetwork.recordId <= request.startingRecordId) {
|
|
365
396
|
continue;
|
|
366
397
|
}
|
|
367
|
-
if (!hasCapabilities(
|
|
398
|
+
if (!hasCapabilities(serverOnNetwork.serverCapabilities, serverCapabilityFilter)) {
|
|
368
399
|
// istanbul ignore next
|
|
369
400
|
if (doDebug) {
|
|
370
401
|
debugLog(
|
|
371
402
|
" server ",
|
|
372
|
-
|
|
373
|
-
|
|
403
|
+
serverOnNetwork.serverName,
|
|
404
|
+
serverOnNetwork.serverCapabilities ? serverOnNetwork.serverCapabilities.join(",") : [],
|
|
374
405
|
" does not match serverCapabilities ",
|
|
375
406
|
serverCapabilityFilter
|
|
376
407
|
);
|
|
377
408
|
}
|
|
378
409
|
continue;
|
|
379
410
|
}
|
|
380
|
-
debugLog(" server ",
|
|
381
|
-
servers.push(
|
|
411
|
+
debugLog(" server ", serverOnNetwork.serverName, " found");
|
|
412
|
+
servers.push(serverOnNetwork);
|
|
382
413
|
if (servers.length === request.maxRecordsToReturn) {
|
|
383
414
|
debugLog("max records to return reached", request.maxRecordsToReturn);
|
|
384
415
|
break;
|
|
@@ -392,33 +423,183 @@ export class OPCUADiscoveryServer extends OPCUABaseServer {
|
|
|
392
423
|
channel.send_response("MSG", response, message);
|
|
393
424
|
}
|
|
394
425
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
426
|
+
|
|
427
|
+
async #stopAnnouncedOnMulticastSubnet(conf: MdnsDiscoveryConfiguration): Promise<void> {
|
|
428
|
+
const b = (conf as any).bonjourHolder as BonjourHolder;
|
|
429
|
+
await b.stopAnnouncedOnMulticastSubnet();
|
|
430
|
+
(conf as any).bonjourHolder = undefined;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
async #announcedOnMulticastSubnet(conf: MdnsDiscoveryConfiguration, announcement: Announcement): Promise<void> {
|
|
434
|
+
const serviceConfig = announcementToServiceConfig(announcement);
|
|
435
|
+
|
|
436
|
+
let b = (conf as any).bonjourHolder as BonjourHolder;
|
|
437
|
+
if (b && b.serviceConfig) {
|
|
438
|
+
if (isSameService(b.serviceConfig, serviceConfig)) {
|
|
439
|
+
debugLog("Configuration ", conf.mdnsServerName, " has not changed !");
|
|
440
|
+
// nothing to do
|
|
441
|
+
return;
|
|
442
|
+
} else {
|
|
443
|
+
// istanbul ignore next
|
|
444
|
+
if (doDebug) {
|
|
445
|
+
debugLog("Configuration ", conf.mdnsServerName, " HAS changed !");
|
|
446
|
+
debugLog(" Was ", serviceToString(b.serviceConfig));
|
|
447
|
+
debugLog(" is ", announcement);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
await this.#stopAnnouncedOnMulticastSubnet(conf);
|
|
451
|
+
}
|
|
452
|
+
b = new BonjourHolder();
|
|
453
|
+
(conf as any).bonjourHolder = b;
|
|
454
|
+
await b.announcedOnMulticastSubnet(announcement);
|
|
403
455
|
}
|
|
456
|
+
async #dealWithDiscoveryConfiguration(
|
|
457
|
+
previousConfMap: Map<string, MdnsDiscoveryConfiguration>,
|
|
458
|
+
server1: RegisteredServer,
|
|
459
|
+
serverInfo: ApplicationDescriptionOptions,
|
|
460
|
+
discoveryConfiguration: MdnsDiscoveryConfiguration
|
|
461
|
+
): Promise<StatusCode> {
|
|
462
|
+
// mdnsServerName String The name of the Server when it is announced via mDNS.
|
|
463
|
+
// See Part 12 for the details about mDNS. This string shall be
|
|
464
|
+
// less than 64 bytes.
|
|
465
|
+
// If not specified the first element of the serverNames array
|
|
466
|
+
// is used (truncated to 63 bytes if necessary).
|
|
467
|
+
// serverCapabilities [] String The set of Server capabilities supported by the Server.
|
|
468
|
+
// A Server capability is a short identifier for a feature
|
|
469
|
+
// The set of allowed Server capabilities are defined in Part 12.
|
|
470
|
+
discoveryConfiguration.mdnsServerName ??= server1.serverNames![0].text;
|
|
471
|
+
|
|
472
|
+
serverInfo.discoveryUrls ??= [];
|
|
473
|
+
|
|
474
|
+
const endpointUrl = serverInfo.discoveryUrls[0]!;
|
|
475
|
+
const parsedUrl = new URL(endpointUrl);
|
|
476
|
+
|
|
477
|
+
discoveryConfiguration.serverCapabilities = discoveryConfiguration.serverCapabilities || [];
|
|
478
|
+
const announcement = {
|
|
479
|
+
capabilities: discoveryConfiguration.serverCapabilities.map((x: UAString) => x!) || ["DA"],
|
|
480
|
+
name: discoveryConfiguration.mdnsServerName!,
|
|
481
|
+
host: parsedUrl.hostname || "",
|
|
482
|
+
path: parsedUrl.pathname || "/",
|
|
483
|
+
port: parseInt(parsedUrl.port!, 10)
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
if (previousConfMap.has(discoveryConfiguration.mdnsServerName!)) {
|
|
487
|
+
// configuration already exists
|
|
488
|
+
debugLog("Configuration ", discoveryConfiguration.mdnsServerName, " already exists !");
|
|
489
|
+
const prevConf = previousConfMap.get(discoveryConfiguration.mdnsServerName!)!;
|
|
490
|
+
previousConfMap.delete(discoveryConfiguration.mdnsServerName!);
|
|
491
|
+
(discoveryConfiguration as any).bonjourHolder = (prevConf as any).bonjourHolder;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// let's announce the server on the multicast DNS
|
|
495
|
+
await this.#announcedOnMulticastSubnet(discoveryConfiguration, announcement);
|
|
496
|
+
return StatusCodes.Good;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
*
|
|
502
|
+
* @param server
|
|
503
|
+
* @param forced true :indicated if the LDS is forcing the Server to be seen as unregistered, false
|
|
504
|
+
* when the offline comes from the server it self.
|
|
505
|
+
* @returns
|
|
506
|
+
*/
|
|
507
|
+
async #internalRegisterServerOffline(server: RegisteredServerExtended, forced: boolean) {
|
|
508
|
+
|
|
509
|
+
const key = server.serverUri!;
|
|
510
|
+
|
|
511
|
+
let configurationResults: StatusCode[] | null = null;
|
|
512
|
+
// server is announced offline
|
|
513
|
+
if (this.registeredServers.has(key)) {
|
|
514
|
+
const serverToUnregister = this.registeredServers.get(key)!;
|
|
515
|
+
debugLog(chalk.cyan("unregistering server : "), chalk.yellow(serverToUnregister.serverUri!));
|
|
516
|
+
configurationResults = [];
|
|
517
|
+
|
|
518
|
+
const discoveryConfigurations = serverToUnregister.discoveryConfiguration || [];
|
|
519
|
+
|
|
520
|
+
for (const conf of discoveryConfigurations) {
|
|
521
|
+
await this.#stopAnnouncedOnMulticastSubnet(conf);
|
|
522
|
+
configurationResults.push(StatusCodes.Good);
|
|
523
|
+
}
|
|
524
|
+
this.registeredServers.delete(key);
|
|
525
|
+
serverToUnregister.isOnline= false;
|
|
526
|
+
this.emit("onUnregisterServer", serverToUnregister, forced);
|
|
527
|
+
}
|
|
528
|
+
return configurationResults;
|
|
404
529
|
|
|
530
|
+
}
|
|
531
|
+
async #internalRegisterServerOnline(
|
|
532
|
+
server: RegisteredServerExtended,
|
|
533
|
+
discoveryConfigurations: MdnsDiscoveryConfiguration[]
|
|
534
|
+
) {
|
|
535
|
+
assert(discoveryConfigurations);
|
|
536
|
+
|
|
537
|
+
const key = server.serverUri!;
|
|
538
|
+
|
|
539
|
+
let configurationResults: StatusCode[] | null = null;
|
|
540
|
+
|
|
541
|
+
debugLog(chalk.cyan(" registering server : "), chalk.yellow(server.serverUri));
|
|
542
|
+
|
|
543
|
+
// prepare serverInfo which will be used by FindServers
|
|
544
|
+
const serverInfo: ApplicationDescriptionOptions = {
|
|
545
|
+
applicationName: server.serverNames![0], // which one shall we use ?
|
|
546
|
+
applicationType: server.serverType,
|
|
547
|
+
applicationUri: server.serverUri,
|
|
548
|
+
discoveryUrls: server.discoveryUrls,
|
|
549
|
+
gatewayServerUri: server.gatewayServerUri,
|
|
550
|
+
productUri: server.productUri
|
|
551
|
+
// XXX ?????? serverInfo.discoveryProfileUri = serverInfo.discoveryProfileUri;
|
|
552
|
+
};
|
|
553
|
+
|
|
554
|
+
const previousConfMap: Map<string, MdnsDiscoveryConfiguration> = new Map();
|
|
555
|
+
|
|
556
|
+
// let check in the server has already been registed on this LDS
|
|
557
|
+
let firstTimeRegistration = true;
|
|
558
|
+
if (this.registeredServers.has(key)) {
|
|
559
|
+
// server already exists and must only be updated
|
|
560
|
+
const previousServer = this.registeredServers.get(key)!;
|
|
561
|
+
for (const conf of previousServer.discoveryConfiguration!) {
|
|
562
|
+
previousConfMap.set(conf.mdnsServerName!, conf);
|
|
563
|
+
}
|
|
564
|
+
firstTimeRegistration = false;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
this.registeredServers.set(key, server);
|
|
568
|
+
|
|
569
|
+
this.emit("onRegisterServer", server, firstTimeRegistration);
|
|
570
|
+
|
|
571
|
+
// xx server.semaphoreFilePath = server.semaphoreFilePath;
|
|
572
|
+
// xx server.serverNames = server.serverNames;
|
|
573
|
+
server.serverInfo = serverInfo;
|
|
574
|
+
server.discoveryConfiguration = discoveryConfigurations;
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
configurationResults = [];
|
|
578
|
+
for (const conf of discoveryConfigurations) {
|
|
579
|
+
const statusCode = await this.#dealWithDiscoveryConfiguration(
|
|
580
|
+
previousConfMap,
|
|
581
|
+
server,
|
|
582
|
+
serverInfo,
|
|
583
|
+
conf
|
|
584
|
+
);
|
|
585
|
+
configurationResults.push(statusCode);
|
|
586
|
+
}
|
|
587
|
+
// now also unregister unprocessed
|
|
588
|
+
if (previousConfMap.size !== 0) {
|
|
589
|
+
debugLog(" Warning some conf need to be removed !");
|
|
590
|
+
}
|
|
591
|
+
return configurationResults;
|
|
592
|
+
|
|
593
|
+
}
|
|
405
594
|
// eslint-disable-next-line max-statements
|
|
406
|
-
|
|
407
|
-
RegisterServerXResponse:
|
|
595
|
+
async #internalRegisterServer(
|
|
596
|
+
RegisterServerXResponse: typeof RegisterServer2Response | typeof RegisterServerResponse,
|
|
408
597
|
rawServer: RegisteredServer,
|
|
409
598
|
discoveryConfigurations?: MdnsDiscoveryConfiguration[]
|
|
410
599
|
): Promise<Response> {
|
|
411
|
-
const server = rawServer as any as RegisteredServerExtended;
|
|
412
600
|
|
|
413
|
-
if (!discoveryConfigurations) {
|
|
414
|
-
discoveryConfigurations = [
|
|
415
|
-
new MdnsDiscoveryConfiguration({
|
|
416
|
-
mdnsServerName: undefined,
|
|
417
|
-
serverCapabilities: ["NA"]
|
|
418
|
-
})
|
|
419
|
-
];
|
|
420
|
-
}
|
|
421
601
|
|
|
602
|
+
// #region check parameter validity
|
|
422
603
|
function sendError(statusCode: StatusCode): Response {
|
|
423
604
|
debugLog(chalk.red("_on_RegisterServer(2)Request error"), statusCode.toString());
|
|
424
605
|
const response1 = new ServiceFault({
|
|
@@ -427,167 +608,57 @@ export class OPCUADiscoveryServer extends OPCUABaseServer {
|
|
|
427
608
|
return response1;
|
|
428
609
|
}
|
|
429
610
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
await b.stopAnnouncedOnMulticastSubnet();
|
|
433
|
-
(conf as any).bonjourHolder = undefined;
|
|
611
|
+
if (this.#shutting_down) {
|
|
612
|
+
return sendError(StatusCodes.BadShutdown);
|
|
434
613
|
}
|
|
435
614
|
|
|
436
|
-
|
|
437
|
-
const serviceConfig = announcementToServiceConfig(announcement);
|
|
438
|
-
|
|
439
|
-
let b = (conf as any).bonjourHolder as BonjourHolder;
|
|
440
|
-
if (b && b.serviceConfig) {
|
|
441
|
-
if (sameService(b.serviceConfig, serviceConfig)) {
|
|
442
|
-
debugLog("Configuration ", conf.mdnsServerName, " has not changed !");
|
|
443
|
-
// nothing to do
|
|
444
|
-
return;
|
|
445
|
-
} else {
|
|
446
|
-
// istanbul ignore next
|
|
447
|
-
if (doDebug) {
|
|
448
|
-
debugLog("Configuration ", conf.mdnsServerName, " HAS changed !");
|
|
449
|
-
debugLog(" Was ", serviceToString(b.serviceConfig));
|
|
450
|
-
debugLog(" is ", announcement);
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
await _stop_announcedOnMulticastSubnet(conf);
|
|
454
|
-
}
|
|
455
|
-
b = new BonjourHolder();
|
|
456
|
-
(conf as any).bonjourHolder = b;
|
|
457
|
-
await b.announcedOnMulticastSubnet(announcement);
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
async function dealWithDiscoveryConfiguration(
|
|
461
|
-
previousConfMap: any,
|
|
462
|
-
server1: RegisteredServer,
|
|
463
|
-
serverInfo: ApplicationDescriptionOptions,
|
|
464
|
-
discoveryConfiguration: MdnsDiscoveryConfiguration
|
|
465
|
-
): Promise<StatusCode> {
|
|
466
|
-
// mdnsServerName String The name of the Server when it is announced via mDNS.
|
|
467
|
-
// See Part 12 for the details about mDNS. This string shall be less than 64 bytes.
|
|
468
|
-
// If not specified the first element of the serverNames array is used
|
|
469
|
-
// (truncated to 63 bytes if necessary).
|
|
470
|
-
// serverCapabilities [] String The set of Server capabilities supported by the Server.
|
|
471
|
-
// A Server capability is a short identifier for a feature
|
|
472
|
-
// The set of allowed Server capabilities are defined in Part 12.
|
|
473
|
-
discoveryConfiguration.mdnsServerName = discoveryConfiguration.mdnsServerName || server1.serverNames![0].text;
|
|
474
|
-
|
|
475
|
-
serverInfo.discoveryUrls = serverInfo.discoveryUrls || [];
|
|
476
|
-
|
|
477
|
-
const endpointUrl = serverInfo.discoveryUrls[0]!;
|
|
478
|
-
const parsedUrl = url.parse(endpointUrl);
|
|
479
|
-
|
|
480
|
-
discoveryConfiguration.serverCapabilities = discoveryConfiguration.serverCapabilities || [];
|
|
481
|
-
const announcement = {
|
|
482
|
-
capabilities: discoveryConfiguration.serverCapabilities.map((x: UAString) => x!) || ["DA"],
|
|
483
|
-
name: discoveryConfiguration.mdnsServerName!,
|
|
484
|
-
host: parsedUrl.hostname || "",
|
|
485
|
-
path: parsedUrl.pathname || "/",
|
|
486
|
-
port: parseInt(parsedUrl.port!, 10)
|
|
487
|
-
};
|
|
488
|
-
|
|
489
|
-
if (previousConfMap[discoveryConfiguration.mdnsServerName!]) {
|
|
490
|
-
// configuration already exists
|
|
491
|
-
debugLog("Configuration ", discoveryConfiguration.mdnsServerName, " already exists !");
|
|
492
|
-
const prevConf = previousConfMap[discoveryConfiguration.mdnsServerName!];
|
|
493
|
-
delete previousConfMap[discoveryConfiguration.mdnsServerName!];
|
|
494
|
-
(discoveryConfiguration as any).bonjourHolder = prevConf.bonjourHolder;
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
// let's announce the server on the multicast DNS
|
|
498
|
-
await _announcedOnMulticastSubnet(discoveryConfiguration, announcement);
|
|
499
|
-
return StatusCodes.Good;
|
|
500
|
-
}
|
|
615
|
+
const server = rawServer as any as RegisteredServerExtended;
|
|
501
616
|
|
|
502
617
|
// check serverType is valid
|
|
503
618
|
if (!_isValidServerType(server.serverType)) {
|
|
504
619
|
debugLog("Invalid server Type", ApplicationType[server.serverType]);
|
|
505
620
|
return sendError(StatusCodes.BadInvalidArgument);
|
|
506
621
|
}
|
|
507
|
-
|
|
508
622
|
if (!server.serverUri) {
|
|
509
623
|
debugLog("Missing serverURI");
|
|
510
624
|
return sendError(StatusCodes.BadInvalidArgument);
|
|
511
625
|
}
|
|
512
|
-
|
|
513
|
-
// BadServerUriInvalid
|
|
514
|
-
// TODO
|
|
515
626
|
server.serverNames = server.serverNames || [];
|
|
516
627
|
// BadServerNameMissing
|
|
517
628
|
if (server.serverNames.length === 0 || !server.serverNames[0].text) {
|
|
518
629
|
return sendError(StatusCodes.BadServerNameMissing);
|
|
519
630
|
}
|
|
520
|
-
|
|
521
631
|
// BadDiscoveryUrlMissing
|
|
522
632
|
server.discoveryUrls = server.discoveryUrls || [];
|
|
523
633
|
if (server.discoveryUrls.length === 0 || !server.discoveryUrls[0]) {
|
|
524
634
|
return sendError(StatusCodes.BadDiscoveryUrlMissing);
|
|
525
635
|
}
|
|
526
636
|
|
|
527
|
-
const key = server.serverUri;
|
|
528
|
-
let configurationResults: StatusCode[] | null = null;
|
|
529
637
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
// prepare serverInfo which will be used by FindServers
|
|
534
|
-
const serverInfo: ApplicationDescriptionOptions = {
|
|
535
|
-
applicationName: server.serverNames[0], // which one shall we use ?
|
|
536
|
-
applicationType: server.serverType,
|
|
537
|
-
applicationUri: server.serverUri,
|
|
538
|
-
discoveryUrls: server.discoveryUrls,
|
|
539
|
-
gatewayServerUri: server.gatewayServerUri,
|
|
540
|
-
productUri: server.productUri
|
|
541
|
-
// XXX ?????? serverInfo.discoveryProfileUri = serverInfo.discoveryProfileUri;
|
|
542
|
-
};
|
|
543
|
-
|
|
544
|
-
const previousConfMap: any = [];
|
|
545
|
-
if (this.registeredServers[key]) {
|
|
546
|
-
// server already exists and must only be updated
|
|
547
|
-
const previousServer = this.registeredServers[key];
|
|
638
|
+
// BadServerUriInvalid
|
|
639
|
+
// TODO
|
|
640
|
+
// #endregion
|
|
548
641
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
642
|
+
if (!discoveryConfigurations) {
|
|
643
|
+
discoveryConfigurations = [
|
|
644
|
+
new MdnsDiscoveryConfiguration({
|
|
645
|
+
mdnsServerName: undefined,
|
|
646
|
+
serverCapabilities: ["NA"]
|
|
647
|
+
})
|
|
648
|
+
];
|
|
649
|
+
}
|
|
554
650
|
|
|
555
|
-
|
|
556
|
-
// xx server.serverNames = server.serverNames;
|
|
557
|
-
server.serverInfo = serverInfo;
|
|
558
|
-
server.discoveryConfiguration = discoveryConfigurations;
|
|
651
|
+
const configurationResults = server?.isOnline ?
|
|
559
652
|
|
|
560
|
-
|
|
653
|
+
await this.#internalRegisterServerOnline(server, discoveryConfigurations) :
|
|
654
|
+
await this.#internalRegisterServerOffline(server, false);
|
|
561
655
|
|
|
562
|
-
configurationResults = [];
|
|
563
|
-
for (const conf of discoveryConfigurations) {
|
|
564
|
-
const statusCode = await dealWithDiscoveryConfiguration(previousConfMap, server, serverInfo, conf);
|
|
565
|
-
configurationResults.push(statusCode);
|
|
566
|
-
}
|
|
567
|
-
// now also unregister unprocessed
|
|
568
|
-
if (Object.keys(previousConfMap).length !== 0) {
|
|
569
|
-
debugLog(" Warning some conf need to be removed !");
|
|
570
|
-
}
|
|
571
|
-
} else {
|
|
572
|
-
// server is announced offline
|
|
573
|
-
if (key in this.registeredServers) {
|
|
574
|
-
const server1 = this.registeredServers[key];
|
|
575
|
-
debugLog(chalk.cyan("unregistering server : "), chalk.yellow(server1.serverUri!));
|
|
576
|
-
configurationResults = [];
|
|
577
|
-
|
|
578
|
-
discoveryConfigurations = server1.discoveryConfiguration || [];
|
|
579
|
-
|
|
580
|
-
for (const conf of discoveryConfigurations) {
|
|
581
|
-
await _stop_announcedOnMulticastSubnet(conf);
|
|
582
|
-
configurationResults.push(StatusCodes.Good);
|
|
583
|
-
}
|
|
584
|
-
delete this.registeredServers[key];
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
656
|
|
|
588
657
|
const response = new RegisterServerXResponse({
|
|
589
|
-
configurationResults
|
|
590
658
|
});
|
|
659
|
+
if (response instanceof RegisterServer2Response) {
|
|
660
|
+
response.configurationResults = configurationResults;
|
|
661
|
+
}
|
|
591
662
|
return response;
|
|
592
663
|
}
|
|
593
664
|
}
|
|
@@ -610,12 +681,3 @@ function _isValidServerType(serverType: ApplicationType): boolean {
|
|
|
610
681
|
return false;
|
|
611
682
|
}
|
|
612
683
|
|
|
613
|
-
(OPCUADiscoveryServer as any).prototype.__internalRegisterServerWithCallback = callbackify(
|
|
614
|
-
(OPCUADiscoveryServer as any).prototype.__internalRegisterServer
|
|
615
|
-
);
|
|
616
|
-
|
|
617
|
-
// tslint:disable-next-line: no-var-requires
|
|
618
|
-
import { withCallback } from "thenify-ex";
|
|
619
|
-
const opts = { multiArgs: false };
|
|
620
|
-
OPCUADiscoveryServer.prototype.start = withCallback(OPCUADiscoveryServer.prototype.start, opts);
|
|
621
|
-
OPCUADiscoveryServer.prototype.shutdown = withCallback(OPCUADiscoveryServer.prototype.shutdown, opts);
|