Add a configuration section for the UI WS server
authorJérôme Benoit <jerome.benoit@sap.com>
Wed, 1 Dec 2021 12:07:27 +0000 (13:07 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Wed, 1 Dec 2021 12:07:27 +0000 (13:07 +0100)
Signed-off-by: Jérôme Benoit <jerome.benoit@piment-noir.org>
src/charging-station/Bootstrap.ts
src/charging-station/UIWebSocketServer.ts
src/types/ConfigurationData.ts
src/utils/Configuration.ts
src/utils/Constants.ts

index 74fb74b7cb6e195524f0440b3eb831e85f25804d..ce20f0bff96c498c8be4331d90a62dd56e9ae1c1 100644 (file)
@@ -18,8 +18,8 @@ import { version } from '../../package.json';
 export default class Bootstrap {
   private static instance: Bootstrap | null = null;
   private workerImplementation: WorkerAbstract | null = null;
-  private readonly uiWebSocketServer: UIWebSocketServer;
-  private readonly storage: Storage;
+  private readonly uiWebSocketServer!: UIWebSocketServer;
+  private readonly storage!: Storage;
   private numberOfChargingStations: number;
   private readonly version: string = version;
   private started: boolean;
@@ -29,8 +29,14 @@ export default class Bootstrap {
     this.started = false;
     this.workerScript = path.join(path.resolve(__dirname, '../'), 'charging-station', 'ChargingStationWorker.js');
     this.initWorkerImplementation();
-    this.uiWebSocketServer = new UIWebSocketServer({ port: 80, handleProtocols: UIServiceUtils.handleProtocols });
-    this.storage = StorageFactory.getStorage(Configuration.getPerformanceStorage().type, Configuration.getPerformanceStorage().URI, this.logPrefix());
+    Configuration.getUIWebSocketServer().enabled && (this.uiWebSocketServer = new UIWebSocketServer({
+      ...Configuration.getUIWebSocketServer().options, handleProtocols: UIServiceUtils.handleProtocols
+    }));
+    Configuration.getPerformanceStorage().enabled && (this.storage = StorageFactory.getStorage(
+      Configuration.getPerformanceStorage().type,
+      Configuration.getPerformanceStorage().URI,
+      this.logPrefix()
+    ));
     Configuration.setConfigurationChangeCallback(async () => Bootstrap.getInstance().restart());
   }
 
@@ -45,9 +51,9 @@ export default class Bootstrap {
     if (isMainThread && !this.started) {
       try {
         this.numberOfChargingStations = 0;
-        await this.storage.open();
+        await this.storage?.open();
         await this.workerImplementation.start();
-        this.uiWebSocketServer.start();
+        this.uiWebSocketServer?.start();
         // Start ChargingStation object in worker thread
         if (Configuration.getStationTemplateURLs()) {
           for (const stationURL of Configuration.getStationTemplateURLs()) {
@@ -85,8 +91,8 @@ export default class Bootstrap {
   public async stop(): Promise<void> {
     if (isMainThread && this.started) {
       await this.workerImplementation.stop();
-      this.uiWebSocketServer.stop();
-      await this.storage.close();
+      this.uiWebSocketServer?.stop();
+      await this.storage?.close();
     } else {
       console.error(chalk.red('Trying to stop the charging stations simulator while not started'));
     }
index f941b138d505540f3fa3c12bee916ffda4e28ec8..5903b85c48cad0112b0eacee9a64dc6f09e9ed0d 100644 (file)
@@ -1,24 +1,25 @@
 import { Protocol, ProtocolCommand, ProtocolRequest, ProtocolVersion } from '../types/UIProtocol';
+import WebSocket, { OPEN, Server, ServerOptions } from 'ws';
 
 import AbstractUIService from './UIWebSocketServices/AbstractUIService';
 import BaseError from '../exception/BaseError';
+import Configuration from '../utils/Configuration';
 import { IncomingMessage } from 'http';
 import UIServiceFactory from './UIWebSocketServices/UIServiceFactory';
 import Utils from '../utils/Utils';
-import WebSocket from 'ws';
 import logger from '../utils/Logger';
 
-export default class UIWebSocketServer extends WebSocket.Server {
+export default class UIWebSocketServer extends Server {
   public uiService: AbstractUIService;
 
-  public constructor(options?: WebSocket.ServerOptions, callback?: () => void) {
+  public constructor(options?: ServerOptions, callback?: () => void) {
     // Create the WebSocket Server
-    super(options ?? { port: 80 }, callback);
+    super(options ?? Configuration.getUIWebSocketServer().options, callback);
   }
 
   public broadcastToClients(message: string | Record<string, unknown>): void {
     for (const client of this.clients) {
-      if (client?.readyState === WebSocket.OPEN) {
+      if (client?.readyState === OPEN) {
         client.send(message);
       }
     }
index 1a2dd165113188d52690eafb4ed5d4f64da553d5..d218e08a3067917daa1a321e11281eef9c4affbd 100644 (file)
@@ -1,3 +1,4 @@
+import { ServerOptions } from 'ws';
 import { StorageType } from './Storage';
 import type { WorkerChoiceStrategy } from 'poolifier';
 import { WorkerProcessType } from './Worker';
@@ -7,6 +8,11 @@ export interface StationTemplateURL {
   numberOfStations: number;
 }
 
+export interface UIWebSocketServerConfiguration {
+  enabled?: boolean;
+  options?: ServerOptions;
+}
+
 export interface StorageConfiguration {
   enabled?: boolean;
   type?: StorageType;
@@ -16,6 +22,7 @@ export interface StorageConfiguration {
 export default interface ConfigurationData {
   supervisionURLs?: string[];
   stationTemplateURLs: StationTemplateURL[];
+  uiWebSocketServer?: UIWebSocketServerConfiguration;
   performanceStorage?: StorageConfiguration;
   autoReconnectMaxRetries?: number;
   distributeStationsToTenantsEqually?: boolean;
index 2ac2664285173756e32a23dc3f905b6e3187231f..391db0c0131f8821df52df28f84d5f16fc03f11b 100644 (file)
@@ -1,6 +1,7 @@
-import ConfigurationData, { StationTemplateURL, StorageConfiguration } from '../types/ConfigurationData';
+import ConfigurationData, { StationTemplateURL, StorageConfiguration, UIWebSocketServerConfiguration } from '../types/ConfigurationData';
 
 import Constants from './Constants';
+import { ServerOptions } from 'ws';
 import { StorageType } from '../types/Storage';
 import type { WorkerChoiceStrategy } from 'poolifier';
 import { WorkerProcessType } from '../types/Worker';
@@ -24,24 +25,46 @@ export default class Configuration {
     return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'logStatisticsInterval') ? Configuration.getConfig().logStatisticsInterval : 60;
   }
 
+  static getUIWebSocketServer(): UIWebSocketServerConfiguration {
+    let options: ServerOptions = {
+      host: Constants.DEFAULT_UI_WEBSOCKET_SERVER_HOST,
+      port: Constants.DEFAULT_UI_WEBSOCKET_SERVER_PORT
+    };
+    let uiWebSocketServerConfiguration: UIWebSocketServerConfiguration = {
+      enabled: true,
+      options
+    };
+    if (Configuration.objectHasOwnProperty(Configuration.getConfig(), 'uiWebSocketServer')) {
+      if (Configuration.objectHasOwnProperty(Configuration.getConfig().uiWebSocketServer, 'options')) {
+        options = {
+          ...Configuration.objectHasOwnProperty(Configuration.getConfig().uiWebSocketServer.options, 'host') && { host: Configuration.getConfig().uiWebSocketServer.options.host },
+          ...Configuration.objectHasOwnProperty(Configuration.getConfig().uiWebSocketServer.options, 'port') && { port: Configuration.getConfig().uiWebSocketServer.options.port }
+        };
+      }
+      uiWebSocketServerConfiguration =
+      {
+        ...Configuration.objectHasOwnProperty(Configuration.getConfig().uiWebSocketServer, 'enabled') && { enabled: Configuration.getConfig().uiWebSocketServer.enabled },
+        options
+      };
+    }
+    return uiWebSocketServerConfiguration;
+  }
+
   static getPerformanceStorage(): StorageConfiguration {
-    let storageConfiguration: StorageConfiguration;
+    let storageConfiguration: StorageConfiguration = {
+      enabled: false,
+      type: StorageType.JSON_FILE,
+      URI: this.getDefaultPerformanceStorageURI(StorageType.JSON_FILE)
+    };
     if (Configuration.objectHasOwnProperty(Configuration.getConfig(), 'performanceStorage')) {
       storageConfiguration =
       {
-        ...Configuration.objectHasOwnProperty(Configuration.getConfig().performanceStorage, 'enabled') ? { enabled: Configuration.getConfig().performanceStorage.enabled } : { enabled: false },
-        ...Configuration.objectHasOwnProperty(Configuration.getConfig().performanceStorage, 'type') ? { type: Configuration.getConfig().performanceStorage.type } : { type: StorageType.JSON_FILE },
+        ...Configuration.objectHasOwnProperty(Configuration.getConfig().performanceStorage, 'enabled') && { enabled: Configuration.getConfig().performanceStorage.enabled },
+        ...Configuration.objectHasOwnProperty(Configuration.getConfig().performanceStorage, 'type') && { type: Configuration.getConfig().performanceStorage.type },
         ...Configuration.objectHasOwnProperty(Configuration.getConfig().performanceStorage, 'URI')
           ? { URI: Configuration.getConfig().performanceStorage.URI }
           : { URI: this.getDefaultPerformanceStorageURI(Configuration.getConfig()?.performanceStorage?.type ?? StorageType.JSON_FILE) }
       };
-    } else {
-      storageConfiguration =
-      {
-        enabled: false,
-        type: StorageType.JSON_FILE,
-        URI: this.getDefaultPerformanceStorageURI(StorageType.JSON_FILE)
-      };
     }
     return storageConfiguration;
   }
index c10a320bc8d71ed23775e94be0c88b936e1b610e..034d79700f8260c3ea7bd58c13f784bc349a2d3e 100644 (file)
@@ -45,8 +45,13 @@ export default class Constants {
 
   static readonly DEFAULT_HEARTBEAT_INTERVAL = 60000; // Ms
 
-  static readonly SUPPORTED_MEASURANDS = Object.freeze([MeterValueMeasurand.STATE_OF_CHARGE, MeterValueMeasurand.VOLTAGE,
-    MeterValueMeasurand.POWER_ACTIVE_IMPORT, MeterValueMeasurand.CURRENT_IMPORT, MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER]);
+  static readonly SUPPORTED_MEASURANDS = Object.freeze([
+    MeterValueMeasurand.STATE_OF_CHARGE,
+    MeterValueMeasurand.VOLTAGE,
+    MeterValueMeasurand.POWER_ACTIVE_IMPORT,
+    MeterValueMeasurand.CURRENT_IMPORT,
+    MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+  ]);
 
   static readonly DEFAULT_FLUCTUATION_PERCENT = 5;
 
@@ -54,4 +59,7 @@ export default class Constants {
   static readonly DEFAULT_PERFORMANCE_RECORDS_FILENAME = 'performanceRecords.json';
   static readonly DEFAULT_PERFORMANCE_RECORDS_DB_NAME = 'charging-stations-simulator';
   static readonly PERFORMANCE_RECORDS_TABLE = 'performance_records';
+
+  static readonly DEFAULT_UI_WEBSOCKET_SERVER_HOST = 'localhost';
+  static readonly DEFAULT_UI_WEBSOCKET_SERVER_PORT = 80;
 }