refactor: unflag worker startup at the right time on worker set
[e-mobility-charging-stations-simulator.git] / src / utils / Configuration.ts
index 4aaa2250dc77169cf0113b0958ce23738680da26..b564cd6252ea4366993f24bb5e9961132bd9ad4d 100644 (file)
@@ -20,7 +20,13 @@ import {
   type UIServerConfiguration,
   type WorkerConfiguration,
 } from '../types';
-import { WorkerConstants, WorkerProcessType } from '../worker';
+import {
+  DEFAULT_ELEMENT_START_DELAY,
+  DEFAULT_POOL_MAX_SIZE,
+  DEFAULT_POOL_MIN_SIZE,
+  DEFAULT_WORKER_START_DELAY,
+  WorkerProcessType,
+} from '../worker';
 
 type ConfigurationSectionType =
   | LogConfiguration
@@ -35,8 +41,8 @@ export class Configuration {
     'config.json',
   );
 
-  private static configurationFileWatcher: FSWatcher | undefined;
-  private static configurationData: ConfigurationData | null = null;
+  private static configurationFileWatcher?: FSWatcher;
+  private static configurationData?: ConfigurationData;
   private static configurationSectionCache = new Map<
     ConfigurationSection,
     ConfigurationSectionType
@@ -47,7 +53,7 @@ export class Configuration {
     [ConfigurationSection.uiServer, Configuration.buildUIServerSection()],
   ]);
 
-  private static configurationChangeCallback: () => Promise<void>;
+  private static configurationChangeCallback?: () => Promise<void>;
 
   private constructor() {
     // This is intentional
@@ -60,33 +66,8 @@ export class Configuration {
   public static getConfigurationSection<T extends ConfigurationSectionType>(
     sectionName: ConfigurationSection,
   ): T {
-    if (!Configuration.configurationSectionCache.has(sectionName)) {
-      switch (sectionName) {
-        case ConfigurationSection.log:
-          Configuration.configurationSectionCache.set(sectionName, Configuration.buildLogSection());
-          break;
-        case ConfigurationSection.performanceStorage:
-          Configuration.configurationSectionCache.set(
-            sectionName,
-            Configuration.buildPerformanceStorageSection(),
-          );
-          break;
-        case ConfigurationSection.worker:
-          Configuration.configurationSectionCache.set(
-            sectionName,
-            Configuration.buildWorkerSection(),
-          );
-          break;
-        case ConfigurationSection.uiServer:
-          Configuration.configurationSectionCache.set(
-            sectionName,
-            Configuration.buildUIServerSection(),
-          );
-          break;
-        default:
-          // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
-          throw new Error(`Unknown configuration section '${sectionName}'`);
-      }
+    if (!Configuration.isConfigurationSectionCached(sectionName)) {
+      Configuration.cacheConfigurationSection(sectionName);
     }
     return Configuration.configurationSectionCache.get(sectionName) as T;
   }
@@ -119,16 +100,18 @@ export class Configuration {
       "Use 'stationTemplateUrls' instead",
     );
     // eslint-disable-next-line @typescript-eslint/dot-notation
-    !isUndefined(Configuration.getConfigurationData()!['stationTemplateURLs']) &&
+    !isUndefined(
+      Configuration.getConfigurationData()!['stationTemplateURLs' as keyof ConfigurationData],
+    ) &&
       (Configuration.getConfigurationData()!.stationTemplateUrls =
         Configuration.getConfigurationData()![
           // eslint-disable-next-line @typescript-eslint/dot-notation
-          'stationTemplateURLs'
+          'stationTemplateURLs' as keyof ConfigurationData
         ] as StationTemplateUrl[]);
     Configuration.getConfigurationData()!.stationTemplateUrls.forEach(
       (stationTemplateUrl: StationTemplateUrl) => {
         // eslint-disable-next-line @typescript-eslint/dot-notation
-        if (!isUndefined(stationTemplateUrl['numberOfStation'])) {
+        if (!isUndefined(stationTemplateUrl['numberOfStation' as keyof StationTemplateUrl])) {
           console.error(
             `${chalk.green(Configuration.logPrefix())} ${chalk.red(
               `Deprecated configuration key 'numberOfStation' usage for template file '${stationTemplateUrl.file}' in 'stationTemplateUrls'. Use 'numberOfStations' instead`,
@@ -147,10 +130,14 @@ export class Configuration {
       "Use 'supervisionUrls' instead",
     );
     // eslint-disable-next-line @typescript-eslint/dot-notation
-    if (!isUndefined(Configuration.getConfigurationData()!['supervisionURLs'])) {
+    if (
+      !isUndefined(
+        Configuration.getConfigurationData()!['supervisionURLs' as keyof ConfigurationData],
+      )
+    ) {
       Configuration.getConfigurationData()!.supervisionUrls = Configuration.getConfigurationData()![
         // eslint-disable-next-line @typescript-eslint/dot-notation
-        'supervisionURLs'
+        'supervisionURLs' as keyof ConfigurationData
       ] as string | string[];
     }
     return Configuration.getConfigurationData()?.supervisionUrls;
@@ -182,6 +169,39 @@ export class Configuration {
     return Configuration.buildWorkerSection().processType === WorkerProcessType.dynamicPool;
   }
 
+  private static isConfigurationSectionCached(sectionName: ConfigurationSection): boolean {
+    return Configuration.configurationSectionCache.has(sectionName);
+  }
+
+  private static cacheConfigurationSection(sectionName: ConfigurationSection): void {
+    switch (sectionName) {
+      case ConfigurationSection.log:
+        Configuration.configurationSectionCache.set(sectionName, Configuration.buildLogSection());
+        break;
+      case ConfigurationSection.performanceStorage:
+        Configuration.configurationSectionCache.set(
+          sectionName,
+          Configuration.buildPerformanceStorageSection(),
+        );
+        break;
+      case ConfigurationSection.worker:
+        Configuration.configurationSectionCache.set(
+          sectionName,
+          Configuration.buildWorkerSection(),
+        );
+        break;
+      case ConfigurationSection.uiServer:
+        Configuration.configurationSectionCache.set(
+          sectionName,
+          Configuration.buildUIServerSection(),
+        );
+        break;
+      default:
+        // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
+        throw new Error(`Unknown configuration section '${sectionName}'`);
+    }
+  }
+
   private static buildUIServerSection(): UIServerConfiguration {
     if (hasOwnProp(Configuration.getConfigurationData(), 'uiWebSocketServer')) {
       console.error(
@@ -387,11 +407,11 @@ export class Configuration {
     );
     const defaultWorkerConfiguration: WorkerConfiguration = {
       processType: WorkerProcessType.workerSet,
-      startDelay: WorkerConstants.DEFAULT_WORKER_START_DELAY,
+      startDelay: DEFAULT_WORKER_START_DELAY,
       elementsPerWorker: 'auto',
-      elementStartDelay: WorkerConstants.DEFAULT_ELEMENT_START_DELAY,
-      poolMinSize: WorkerConstants.DEFAULT_POOL_MIN_SIZE,
-      poolMaxSize: WorkerConstants.DEFAULT_POOL_MAX_SIZE,
+      elementStartDelay: DEFAULT_ELEMENT_START_DELAY,
+      poolMinSize: DEFAULT_POOL_MIN_SIZE,
+      poolMaxSize: DEFAULT_POOL_MAX_SIZE,
     };
     hasOwnProp(Configuration.getConfigurationData(), 'workerPoolStrategy') &&
       delete Configuration.getConfigurationData()?.workerPoolStrategy;
@@ -445,9 +465,14 @@ export class Configuration {
   ) {
     if (
       sectionName &&
-      !isUndefined(Configuration.getConfigurationData()![sectionName]) &&
+      !isUndefined(Configuration.getConfigurationData()![sectionName as keyof ConfigurationData]) &&
       !isUndefined(
-        (Configuration.getConfigurationData()![sectionName] as Record<string, unknown>)[key],
+        (
+          Configuration.getConfigurationData()![sectionName as keyof ConfigurationData] as Record<
+            string,
+            unknown
+          >
+        )[key],
       )
     ) {
       console.error(
@@ -457,7 +482,9 @@ export class Configuration {
           }`,
         )}`,
       );
-    } else if (!isUndefined(Configuration.getConfigurationData()![key])) {
+    } else if (
+      !isUndefined(Configuration.getConfigurationData()![key as keyof ConfigurationData])
+    ) {
       console.error(
         `${chalk.green(Configuration.logPrefix())} ${chalk.red(
           `Deprecated configuration key '${key}' usage${
@@ -468,7 +495,7 @@ export class Configuration {
     }
   }
 
-  private static getConfigurationData(): ConfigurationData | null {
+  private static getConfigurationData(): ConfigurationData | undefined {
     if (!Configuration.configurationData) {
       try {
         Configuration.configurationData = JSON.parse(
@@ -493,11 +520,10 @@ export class Configuration {
     try {
       return watch(Configuration.configurationFile, (event, filename): void => {
         if (filename!.trim()!.length > 0 && event === 'change') {
-          // Nullify to force configuration file reading
-          Configuration.configurationData = null;
+          delete Configuration.configurationData;
           Configuration.configurationSectionCache.clear();
           if (!isUndefined(Configuration.configurationChangeCallback)) {
-            Configuration.configurationChangeCallback().catch((error) => {
+            Configuration.configurationChangeCallback!().catch((error) => {
               throw typeof error === 'string' ? new Error(error) : error;
             });
           }
@@ -552,7 +578,7 @@ export class Configuration {
           `${Constants.DEFAULT_PERFORMANCE_DIRECTORY}/${Constants.DEFAULT_PERFORMANCE_RECORDS_DB_NAME}.db`,
         );
       default:
-        throw new Error(`Performance storage URI is mandatory with storage type '${storageType}'`);
+        throw new Error(`Unsupported storage type '${storageType}'`);
     }
   }