feat: allow to provision number of stations by template
[e-mobility-charging-stations-simulator.git] / src / utils / Configuration.ts
index 06c2a5a361ad1c7e56e068485c3b0b3fac26b510..25a1475bc2a5f6ec9a6ea40df049048db9538ad8 100644 (file)
@@ -4,20 +4,11 @@ import { env } from 'node:process'
 import { fileURLToPath } from 'node:url'
 
 import chalk from 'chalk'
-import merge from 'just-merge'
+import { mergeDeepRight, once } from 'rambda'
 
-import {
-  buildPerformanceUriFilePath,
-  checkWorkerElementsPerWorker,
-  checkWorkerProcessType,
-  getDefaultPerformanceStorageUri,
-  handleFileException,
-  logPrefix
-} from './ConfigurationUtils.js'
-import { Constants } from './Constants.js'
-import { hasOwnProp, isCFEnvironment, once } from './Utils.js'
 import {
   ApplicationProtocol,
+  ApplicationProtocolVersion,
   type ConfigurationData,
   ConfigurationSection,
   FileType,
@@ -30,12 +21,22 @@ import {
   type WorkerConfiguration
 } from '../types/index.js'
 import {
-  DEFAULT_ELEMENT_START_DELAY,
+  DEFAULT_ELEMENT_ADD_DELAY,
   DEFAULT_POOL_MAX_SIZE,
   DEFAULT_POOL_MIN_SIZE,
   DEFAULT_WORKER_START_DELAY,
   WorkerProcessType
 } from '../worker/index.js'
+import {
+  buildPerformanceUriFilePath,
+  checkWorkerElementsPerWorker,
+  checkWorkerProcessType,
+  getDefaultPerformanceStorageUri,
+  handleFileException,
+  logPrefix
+} from './ConfigurationUtils.js'
+import { Constants } from './Constants.js'
+import { hasOwnProp, isCFEnvironment } from './Utils.js'
 
 type ConfigurationSectionType =
   | LogConfiguration
@@ -81,8 +82,7 @@ export class Configuration {
 
   public static getStationTemplateUrls (): StationTemplateUrl[] | undefined {
     const checkDeprecatedConfigurationKeysOnce = once(
-      Configuration.checkDeprecatedConfigurationKeys.bind(Configuration),
-      Configuration
+      Configuration.checkDeprecatedConfigurationKeys.bind(Configuration)
     )
     checkDeprecatedConfigurationKeysOnce()
     return Configuration.getConfigurationData()?.stationTemplateUrls
@@ -90,8 +90,7 @@ export class Configuration {
 
   public static getSupervisionUrls (): string | string[] | undefined {
     if (
-      Configuration.getConfigurationData()?.['supervisionURLs' as keyof ConfigurationData] !==
-      undefined
+      Configuration.getConfigurationData()?.['supervisionURLs' as keyof ConfigurationData] != null
     ) {
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
       Configuration.getConfigurationData()!.supervisionUrls = Configuration.getConfigurationData()![
@@ -156,13 +155,14 @@ export class Configuration {
     let uiServerConfiguration: UIServerConfiguration = {
       enabled: false,
       type: ApplicationProtocol.WS,
+      version: ApplicationProtocolVersion.VERSION_11,
       options: {
         host: Constants.DEFAULT_UI_SERVER_HOST,
         port: Constants.DEFAULT_UI_SERVER_PORT
       }
     }
     if (hasOwnProp(Configuration.getConfigurationData(), ConfigurationSection.uiServer)) {
-      uiServerConfiguration = merge<UIServerConfiguration>(
+      uiServerConfiguration = mergeDeepRight(
         uiServerConfiguration,
         // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
         Configuration.getConfigurationData()!.uiServer!
@@ -187,13 +187,19 @@ export class Configuration {
         }
         break
       case StorageType.JSON_FILE:
-      default:
         storageConfiguration = {
           enabled: false,
           type: StorageType.JSON_FILE,
           uri: getDefaultPerformanceStorageUri(StorageType.JSON_FILE)
         }
         break
+      case StorageType.NONE:
+      default:
+        storageConfiguration = {
+          enabled: true,
+          type: StorageType.NONE
+        }
+        break
     }
     if (hasOwnProp(Configuration.getConfigurationData(), ConfigurationSection.performanceStorage)) {
       storageConfiguration = {
@@ -269,10 +275,11 @@ export class Configuration {
       processType: WorkerProcessType.workerSet,
       startDelay: DEFAULT_WORKER_START_DELAY,
       elementsPerWorker: 'auto',
-      elementStartDelay: DEFAULT_ELEMENT_START_DELAY,
+      elementAddDelay: DEFAULT_ELEMENT_ADD_DELAY,
       poolMinSize: DEFAULT_POOL_MIN_SIZE,
       poolMaxSize: DEFAULT_POOL_MAX_SIZE
     }
+
     const deprecatedWorkerConfiguration: WorkerConfiguration = {
       ...(hasOwnProp(Configuration.getConfigurationData(), 'workerProcess') && {
         processType: Configuration.getConfigurationData()?.workerProcess
@@ -283,8 +290,11 @@ export class Configuration {
       ...(hasOwnProp(Configuration.getConfigurationData(), 'chargingStationsPerWorker') && {
         elementsPerWorker: Configuration.getConfigurationData()?.chargingStationsPerWorker
       }),
-      ...(hasOwnProp(Configuration.getConfigurationData(), 'elementStartDelay') && {
-        elementStartDelay: Configuration.getConfigurationData()?.elementStartDelay
+      ...(hasOwnProp(Configuration.getConfigurationData(), 'elementAddDelay') && {
+        elementAddDelay: Configuration.getConfigurationData()?.elementAddDelay
+      }),
+      ...(hasOwnProp(Configuration.getConfigurationData()?.worker, 'elementStartDelay') && {
+        elementAddDelay: Configuration.getConfigurationData()?.worker?.elementStartDelay
       }),
       ...(hasOwnProp(Configuration.getConfigurationData(), 'workerPoolMinSize') && {
         poolMinSize: Configuration.getConfigurationData()?.workerPoolMinSize
@@ -331,8 +341,8 @@ export class Configuration {
       undefined,
       "Use 'stationTemplateUrls' instead"
     )
-    Configuration.getConfigurationData()?.['stationTemplateURLs' as keyof ConfigurationData] !==
-      undefined &&
+    Configuration.getConfigurationData()?.['stationTemplateURLs' as keyof ConfigurationData] !=
+      null &&
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
       (Configuration.getConfigurationData()!.stationTemplateUrls =
         // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -342,7 +352,7 @@ export class Configuration {
     Configuration.getConfigurationData()?.stationTemplateUrls.forEach(
       (stationTemplateUrl: StationTemplateUrl) => {
         // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
-        if (stationTemplateUrl['numberOfStation' as keyof StationTemplateUrl] !== undefined) {
+        if (stationTemplateUrl['numberOfStation' as keyof StationTemplateUrl] != null) {
           console.error(
             `${chalk.green(logPrefix())} ${chalk.red(
               `Deprecated configuration key 'numberOfStation' usage for template file '${stationTemplateUrl.file}' in 'stationTemplateUrls'. Use 'numberOfStations' instead`
@@ -390,9 +400,9 @@ export class Configuration {
       `Use '${ConfigurationSection.worker}' section to define the number of element(s) per worker instead`
     )
     Configuration.warnDeprecatedConfigurationKey(
-      'elementStartDelay',
+      'elementAddDelay',
       undefined,
-      `Use '${ConfigurationSection.worker}' section to define the worker's element start delay instead`
+      `Use '${ConfigurationSection.worker}' section to define the worker's element add delay instead`
     )
     Configuration.warnDeprecatedConfigurationKey(
       'workerPoolMinSize',
@@ -419,6 +429,11 @@ export class Configuration {
       ConfigurationSection.worker,
       'Not publicly exposed to end users'
     )
+    Configuration.warnDeprecatedConfigurationKey(
+      'elementStartDelay',
+      ConfigurationSection.worker,
+      "Use 'elementAddDelay' instead"
+    )
     if (
       Configuration.getConfigurationData()?.worker?.processType ===
       ('staticPool' as WorkerProcessType)
@@ -498,30 +513,27 @@ export class Configuration {
 
   private static warnDeprecatedConfigurationKey (
     key: string,
-    sectionName?: string,
+    configurationSection?: ConfigurationSection,
     logMsgToAppend = ''
   ): void {
     if (
-      sectionName != null &&
-      Configuration.getConfigurationData()?.[sectionName as keyof ConfigurationData] !==
-        undefined &&
+      configurationSection != null &&
+      Configuration.getConfigurationData()?.[configurationSection as keyof ConfigurationData] !=
+        null &&
       (
-        Configuration.getConfigurationData()?.[sectionName as keyof ConfigurationData] as Record<
-        string,
-        unknown
-        >
-      )[key] !== undefined
+        Configuration.getConfigurationData()?.[
+          configurationSection as keyof ConfigurationData
+        ] as Record<string, unknown>
+      )[key] != null
     ) {
       console.error(
         `${chalk.green(logPrefix())} ${chalk.red(
-          `Deprecated configuration key '${key}' usage in section '${sectionName}'${
+          `Deprecated configuration key '${key}' usage in section '${configurationSection}'${
             logMsgToAppend.trim().length > 0 ? `. ${logMsgToAppend}` : ''
           }`
         )}`
       )
-    } else if (
-      Configuration.getConfigurationData()?.[key as keyof ConfigurationData] !== undefined
-    ) {
+    } else if (Configuration.getConfigurationData()?.[key as keyof ConfigurationData] != null) {
       console.error(
         `${chalk.green(logPrefix())} ${chalk.red(
           `Deprecated configuration key '${key}' usage${
@@ -532,7 +544,7 @@ export class Configuration {
     }
   }
 
-  private static getConfigurationData (): ConfigurationData | undefined {
+  public static getConfigurationData (): ConfigurationData | undefined {
     if (Configuration.configurationData == null) {
       try {
         Configuration.configurationData = JSON.parse(
@@ -563,7 +575,7 @@ export class Configuration {
           event === 'change'
         ) {
           Configuration.configurationFileReloading = true
-          const consoleWarnOnce = once(console.warn, this)
+          const consoleWarnOnce = once(console.warn)
           consoleWarnOnce(
             `${chalk.green(logPrefix())} ${chalk.yellow(
               `${FileType.Configuration} ${this.configurationFile} file have changed, reload`
@@ -571,9 +583,9 @@ export class Configuration {
           )
           delete Configuration.configurationData
           Configuration.configurationSectionCache.clear()
-          if (Configuration.configurationChangeCallback !== undefined) {
+          if (Configuration.configurationChangeCallback != null) {
             Configuration.configurationChangeCallback()
-              .catch(error => {
+              .catch((error: unknown) => {
                 throw typeof error === 'string' ? new Error(error) : error
               })
               .finally(() => {