Merge pull request #858 from SAP/combined-prs-branch
[e-mobility-charging-stations-simulator.git] / src / utils / Configuration.ts
index 53eb720ffdf6f467295406f6a3a47ab3ec51d18d..1f370480d4d1b6fc47828792ccbf8271cfb81724 100644 (file)
@@ -42,6 +42,11 @@ type ConfigurationSectionType =
   | WorkerConfiguration
   | UIServerConfiguration;
 
+// Avoid ESM race condition at class initialization
+const configurationLogPrefix = (): string => {
+  return logPrefix(' Simulator configuration |');
+};
+
 export class Configuration {
   public static configurationChangeCallback: () => Promise<void>;
 
@@ -51,6 +56,7 @@ export class Configuration {
     'config.json',
   );
 
+  private static configurationFileReloading = false;
   private static configurationData?: ConfigurationData;
   private static configurationFileWatcher?: FSWatcher;
   private static configurationSectionCache = new Map<
@@ -118,10 +124,6 @@ export class Configuration {
     );
   }
 
-  private static logPrefix = (): string => {
-    return logPrefix(' Simulator configuration |');
-  };
-
   private static isConfigurationSectionCached(sectionName: ConfigurationSection): boolean {
     return Configuration.configurationSectionCache.has(sectionName);
   }
@@ -330,7 +332,7 @@ export class Configuration {
       (stationTemplateUrl: StationTemplateUrl) => {
         if (!isUndefined(stationTemplateUrl?.['numberOfStation' as keyof StationTemplateUrl])) {
           console.error(
-            `${chalk.green(Configuration.logPrefix())} ${chalk.red(
+            `${chalk.green(configurationLogPrefix())} ${chalk.red(
               `Deprecated configuration key 'numberOfStation' usage for template file '${stationTemplateUrl.file}' in 'stationTemplateUrls'. Use 'numberOfStations' instead`,
             )}`,
           );
@@ -410,7 +412,7 @@ export class Configuration {
       ('staticPool' as WorkerProcessType)
     ) {
       console.error(
-        `${chalk.green(Configuration.logPrefix())} ${chalk.red(
+        `${chalk.green(configurationLogPrefix())} ${chalk.red(
           `Deprecated configuration 'staticPool' value usage in worker section 'processType' field. Use '${WorkerProcessType.fixedPool}' value instead`,
         )}`,
       );
@@ -475,7 +477,7 @@ export class Configuration {
     // uiServer section
     if (hasOwnProp(Configuration.getConfigurationData(), 'uiWebSocketServer')) {
       console.error(
-        `${chalk.green(Configuration.logPrefix())} ${chalk.red(
+        `${chalk.green(configurationLogPrefix())} ${chalk.red(
           `Deprecated configuration section 'uiWebSocketServer' usage. Use '${ConfigurationSection.uiServer}' instead`,
         )}`,
       );
@@ -502,7 +504,7 @@ export class Configuration {
       )
     ) {
       console.error(
-        `${chalk.green(Configuration.logPrefix())} ${chalk.red(
+        `${chalk.green(configurationLogPrefix())} ${chalk.red(
           `Deprecated configuration key '${key}' usage in section '${sectionName}'${
             logMsgToAppend.trim().length > 0 ? `. ${logMsgToAppend}` : ''
           }`,
@@ -512,7 +514,7 @@ export class Configuration {
       !isUndefined(Configuration.getConfigurationData()?.[key as keyof ConfigurationData])
     ) {
       console.error(
-        `${chalk.green(Configuration.logPrefix())} ${chalk.red(
+        `${chalk.green(configurationLogPrefix())} ${chalk.red(
           `Deprecated configuration key '${key}' usage${
             logMsgToAppend.trim().length > 0 ? `. ${logMsgToAppend}` : ''
           }`,
@@ -535,7 +537,7 @@ export class Configuration {
           Configuration.configurationFile,
           FileType.Configuration,
           error as NodeJS.ErrnoException,
-          Configuration.logPrefix(),
+          configurationLogPrefix(),
         );
       }
     }
@@ -545,13 +547,30 @@ export class Configuration {
   private static getConfigurationFileWatcher(): FSWatcher | undefined {
     try {
       return watch(Configuration.configurationFile, (event, filename): void => {
-        if (filename!.trim()!.length > 0 && event === 'change') {
+        if (
+          !Configuration.configurationFileReloading &&
+          filename!.trim()!.length > 0 &&
+          event === 'change'
+        ) {
+          Configuration.configurationFileReloading = true;
+          const consoleWarnOnce = once(console.warn, this);
+          consoleWarnOnce(
+            `${chalk.green(configurationLogPrefix())} ${chalk.yellow(
+              `${FileType.Configuration} ${this.configurationFile} file have changed, reload`,
+            )}`,
+          );
           delete Configuration.configurationData;
           Configuration.configurationSectionCache.clear();
           if (!isUndefined(Configuration.configurationChangeCallback)) {
-            Configuration.configurationChangeCallback().catch((error) => {
-              throw typeof error === 'string' ? new Error(error) : error;
-            });
+            Configuration.configurationChangeCallback()
+              .catch((error) => {
+                throw typeof error === 'string' ? new Error(error) : error;
+              })
+              .finally(() => {
+                Configuration.configurationFileReloading = false;
+              });
+          } else {
+            Configuration.configurationFileReloading = false;
           }
         }
       });
@@ -560,7 +579,7 @@ export class Configuration {
         Configuration.configurationFile,
         FileType.Configuration,
         error as NodeJS.ErrnoException,
-        Configuration.logPrefix(),
+        configurationLogPrefix(),
       );
     }
   }