feat: allow to override supervisionUrls at adding charging stations
[e-mobility-charging-stations-simulator.git] / src / charging-station / Bootstrap.ts
index 5356a15569fbce4db81a738dc7e24274d93f2118..3993ae1f2a34a23ea3113b04b447512deb6474b9 100644 (file)
@@ -41,8 +41,7 @@ import {
   isAsyncFunction,
   isNotEmptyArray,
   logPrefix,
-  logger,
-  max
+  logger
 } from '../utils/index.js'
 import { type WorkerAbstract, WorkerFactory } from '../worker/index.js'
 
@@ -60,7 +59,7 @@ interface TemplateChargingStations {
   configured: number
   added: number
   started: number
-  lastIndex: number
+  indexes: Set<number>
 }
 
 export class Bootstrap extends EventEmitter {
@@ -68,7 +67,7 @@ export class Bootstrap extends EventEmitter {
   private workerImplementation?: WorkerAbstract<ChargingStationWorkerData>
   private readonly uiServer?: AbstractUIServer
   private storage?: Storage
-  private readonly chargingStationsByTemplate: Map<string, TemplateChargingStations>
+  private readonly templatesChargingStations: Map<string, TemplateChargingStations>
   private readonly version: string = version
   private initializedCounters: boolean
   private started: boolean
@@ -86,7 +85,7 @@ export class Bootstrap extends EventEmitter {
     this.started = false
     this.starting = false
     this.stopping = false
-    this.chargingStationsByTemplate = new Map<string, TemplateChargingStations>()
+    this.templatesChargingStations = new Map<string, TemplateChargingStations>()
     this.uiServer = UIServerFactory.getUIServerImplementation(
       Configuration.getConfigurationSection<UIServerConfiguration>(ConfigurationSection.uiServer)
     )
@@ -107,18 +106,27 @@ export class Bootstrap extends EventEmitter {
   }
 
   public get numberOfChargingStationTemplates (): number {
-    return this.chargingStationsByTemplate.size
+    return this.templatesChargingStations.size
   }
 
   public get numberOfConfiguredChargingStations (): number {
-    return [...this.chargingStationsByTemplate.values()].reduce(
+    return [...this.templatesChargingStations.values()].reduce(
       (accumulator, value) => accumulator + value.configured,
       0
     )
   }
 
   public getLastIndex (templateName: string): number {
-    return this.chargingStationsByTemplate.get(templateName)?.lastIndex ?? 0
+    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+    const indexes = [...this.templatesChargingStations.get(templateName)!.indexes]
+      .concat(0)
+      .sort((a, b) => a - b)
+    for (let i = 0; i < indexes.length - 1; i++) {
+      if (indexes[i + 1] - indexes[i] !== 1) {
+        return indexes[i]
+      }
+    }
+    return indexes[indexes.length - 1]
   }
 
   public getPerformanceStatistics (): IterableIterator<Statistics> | undefined {
@@ -126,14 +134,14 @@ export class Bootstrap extends EventEmitter {
   }
 
   private get numberOfAddedChargingStations (): number {
-    return [...this.chargingStationsByTemplate.values()].reduce(
+    return [...this.templatesChargingStations.values()].reduce(
       (accumulator, value) => accumulator + value.added,
       0
     )
   }
 
   private get numberOfStartedChargingStations (): number {
-    return [...this.chargingStationsByTemplate.values()].reduce(
+    return [...this.templatesChargingStations.values()].reduce(
       (accumulator, value) => accumulator + value.started,
       0
     )
@@ -188,8 +196,8 @@ export class Bootstrap extends EventEmitter {
         for (const stationTemplateUrl of Configuration.getStationTemplateUrls()!) {
           try {
             const nbStations =
-              this.chargingStationsByTemplate.get(parse(stationTemplateUrl.file).name)
-                ?.configured ?? stationTemplateUrl.numberOfStations
+              this.templatesChargingStations.get(parse(stationTemplateUrl.file).name)?.configured ??
+              stationTemplateUrl.numberOfStations
             for (let index = 1; index <= nbStations; index++) {
               await this.addChargingStation(index, stationTemplateUrl.file)
             }
@@ -392,8 +400,6 @@ export class Bootstrap extends EventEmitter {
 
   private readonly workerEventAdded = (data: ChargingStationData): void => {
     this.uiServer?.chargingStations.set(data.stationInfo.hashId, data)
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    ++this.chargingStationsByTemplate.get(data.stationInfo.templateName)!.added
     logger.info(
       `${this.logPrefix()} ${moduleName}.workerEventAdded: Charging station ${
         data.stationInfo.chargingStationId
@@ -406,7 +412,11 @@ export class Bootstrap extends EventEmitter {
   private readonly workerEventDeleted = (data: ChargingStationData): void => {
     this.uiServer?.chargingStations.delete(data.stationInfo.hashId)
     // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    --this.chargingStationsByTemplate.get(data.stationInfo.templateName)!.added
+    const templateChargingStations = this.templatesChargingStations.get(
+      data.stationInfo.templateName
+    )!
+    --templateChargingStations.added
+    templateChargingStations.indexes.delete(data.stationInfo.templateIndex)
     logger.info(
       `${this.logPrefix()} ${moduleName}.workerEventDeleted: Charging station ${
         data.stationInfo.chargingStationId
@@ -419,7 +429,7 @@ export class Bootstrap extends EventEmitter {
   private readonly workerEventStarted = (data: ChargingStationData): void => {
     this.uiServer?.chargingStations.set(data.stationInfo.hashId, data)
     // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    ++this.chargingStationsByTemplate.get(data.stationInfo.templateName)!.started
+    ++this.templatesChargingStations.get(data.stationInfo.templateName)!.started
     logger.info(
       `${this.logPrefix()} ${moduleName}.workerEventStarted: Charging station ${
         data.stationInfo.chargingStationId
@@ -432,7 +442,7 @@ export class Bootstrap extends EventEmitter {
   private readonly workerEventStopped = (data: ChargingStationData): void => {
     this.uiServer?.chargingStations.set(data.stationInfo.hashId, data)
     // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    --this.chargingStationsByTemplate.get(data.stationInfo.templateName)!.started
+    --this.templatesChargingStations.get(data.stationInfo.templateName)!.started
     logger.info(
       `${this.logPrefix()} ${moduleName}.workerEventStopped: Charging station ${
         data.stationInfo.chargingStationId
@@ -468,15 +478,15 @@ export class Bootstrap extends EventEmitter {
       if (isNotEmptyArray(stationTemplateUrls)) {
         for (const stationTemplateUrl of stationTemplateUrls) {
           const templateName = parse(stationTemplateUrl.file).name
-          this.chargingStationsByTemplate.set(templateName, {
+          this.templatesChargingStations.set(templateName, {
             configured: stationTemplateUrl.numberOfStations,
             added: 0,
             started: 0,
-            lastIndex: 0
+            indexes: new Set<number>()
           })
           this.uiServer?.chargingStationTemplates.add(templateName)
         }
-        if (this.chargingStationsByTemplate.size !== stationTemplateUrls.length) {
+        if (this.templatesChargingStations.size !== stationTemplateUrls.length) {
           console.error(
             chalk.red(
               "'stationTemplateUrls' contains duplicate entries, please check your configuration"
@@ -522,10 +532,11 @@ export class Bootstrap extends EventEmitter {
       options
     })
     // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    this.chargingStationsByTemplate.get(parse(stationTemplateFile).name)!.lastIndex = max(
-      index,
-      this.chargingStationsByTemplate.get(parse(stationTemplateFile).name)?.lastIndex ?? -Infinity
-    )
+    const templateChargingStations = this.templatesChargingStations.get(
+      parse(stationTemplateFile).name
+    )!
+    ++templateChargingStations.added
+    templateChargingStations.indexes.add(index)
   }
 
   private gracefulShutdown (): void {