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.
@@ -4,7 +4,7 @@
4
4
 
5
5
  import os from "os";
6
6
  import path from "path";
7
- import url from "url";
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
- sameService,
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(__filename);
56
- const doDebug = checkDebugFlag(__filename);
57
- const errorLog = make_errorLog(__filename);
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
- interface RegisterServerMap {
85
- [key: string]: RegisteredServerExtended;
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 bonjourHolder: BonjourHolder;
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
- super.start((err?: Error | null) => {
187
- if (err) {
188
- return callback!(err);
189
- }
190
- const endpointUri = this.getEndpointUrl();
191
- const { hostname } = url.parse(endpointUri);
192
-
193
- this.mDnsResponder = new MDNSResponder();
194
- // declare discovery server in bonjour
195
- this.bonjourHolder.announcedOnMulticastSubnetWithCallback(
196
- {
197
- capabilities: this.capabilitiesForMDNS,
198
- name: this.serverInfo.applicationUri!,
199
- path: "/DiscoveryServer",
200
- host: hostname || "",
201
- port: this.endpoints[0].port
202
- },
203
- (err2: Error | null) => {
204
- callback!(err2!);
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
- this.mDnsResponder.dispose();
229
+ debugLog("disposing mDnsResponder");
230
+ await this.mDnsResponder.dispose();
217
231
  this.mDnsResponder = undefined;
232
+ debugLog(" mDnsResponder disposed");
218
233
  }
219
234
 
220
- this.bonjourHolder.stopAnnouncedOnMulticastSubnetWithCallback((err?: Error | null) => {
221
- if (err) {
222
- errorLog("stopAnnouncedOnMulticastSubnet Error ", err.message);
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
- super.shutdown(() => {
229
- setTimeout(() => {
230
- callback!();
231
- }, 100);
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 Object.keys(this.registeredServers).length;
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 Object.values(this.registeredServers)) {
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.__internalRegisterServerWithCallback(
278
+ this.#internalRegisterServer(
264
279
  RegisterServer2Response,
265
280
  request.server,
266
281
  request.discoveryConfiguration as MdnsDiscoveryConfiguration[],
267
- (err: Error | null, response?: Response) => {
268
- // istanbul ignore next
269
- if (err) {
270
- errorLog("What shall I do ?", err.message);
271
- errorLog(err);
272
- let additional_messages = [];
273
- additional_messages.push("EXCEPTION CAUGHT WHILE PROCESSING REQUEST !!! " + request.schema.name);
274
- additional_messages.push(err.message);
275
- if (err.stack) {
276
- additional_messages = additional_messages.concat(err.stack.split("\n"));
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.__internalRegisterServerWithCallback(
307
+ this.#internalRegisterServer(
293
308
  RegisterServerResponse,
294
309
  request.server,
295
- undefined,
296
- (err: Error | null, response?: Response) => {
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 server of this.mDnsResponder.registeredServers) {
362
- debugLog("Exploring server ", server.serverName);
392
+ for (const serverOnNetwork of this.mDnsResponder.registeredServers) {
393
+ debugLog("Exploring server ", serverOnNetwork.serverName);
363
394
 
364
- if (server.recordId <= request.startingRecordId) {
395
+ if (serverOnNetwork.recordId <= request.startingRecordId) {
365
396
  continue;
366
397
  }
367
- if (!hasCapabilities(server.serverCapabilities, serverCapabilityFilter)) {
398
+ if (!hasCapabilities(serverOnNetwork.serverCapabilities, serverCapabilityFilter)) {
368
399
  // istanbul ignore next
369
400
  if (doDebug) {
370
401
  debugLog(
371
402
  " server ",
372
- server.serverName,
373
- server.serverCapabilities ? server.serverCapabilities.join(",") : [],
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 ", server.serverName, " found");
381
- servers.push(server);
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
- protected async __internalRegisterServerWithCallback(
396
- RegisterServerXResponse: any /* RegisterServer2Response | RegisterServerResponse */,
397
- rawServer: RegisteredServer,
398
- discoveryConfigurations: MdnsDiscoveryConfiguration[] | undefined,
399
- callback: (err: Error | null, response?: Response) => void
400
- ) {
401
- // istanbul ignore next
402
- callback(new Error("internal Error"));
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
- protected async __internalRegisterServer(
407
- RegisterServerXResponse: any /* RegisterServer2Response | RegisterServerResponse */,
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
- async function _stop_announcedOnMulticastSubnet(conf: MdnsDiscoveryConfiguration): Promise<void> {
431
- const b = (conf as any).bonjourHolder as BonjourHolder;
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
- async function _announcedOnMulticastSubnet(conf: MdnsDiscoveryConfiguration, announcement: Announcement): Promise<void> {
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
- if (server.isOnline) {
531
- debugLog(chalk.cyan(" registering server : "), chalk.yellow(server.serverUri));
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
- for (const conf of previousServer.discoveryConfiguration!) {
550
- previousConfMap[conf.mdnsServerName!] = conf;
551
- }
552
- }
553
- this.registeredServers[key] = server;
642
+ if (!discoveryConfigurations) {
643
+ discoveryConfigurations = [
644
+ new MdnsDiscoveryConfiguration({
645
+ mdnsServerName: undefined,
646
+ serverCapabilities: ["NA"]
647
+ })
648
+ ];
649
+ }
554
650
 
555
- // xx server.semaphoreFilePath = server.semaphoreFilePath;
556
- // xx server.serverNames = server.serverNames;
557
- server.serverInfo = serverInfo;
558
- server.discoveryConfiguration = discoveryConfigurations;
651
+ const configurationResults = server?.isOnline ?
559
652
 
560
- assert(discoveryConfigurations);
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);