fix: move and fix statistic related helpers implementation
[e-mobility-charging-stations-simulator.git] / src / charging-station / ChargingStation.ts
index 56ce26a19e55fd6e5478636264ca832c8c3d3ace..9f1fa7dea8b29435e63592b2645406613d7a1526 100644 (file)
@@ -91,6 +91,8 @@ import {
 } from '../types';
 import {
   ACElectricUtils,
+  AsyncLock,
+  AsyncLockType,
   Configuration,
   Constants,
   DCElectricUtils,
@@ -109,7 +111,7 @@ export class ChargingStation {
   public automaticTransactionGenerator!: AutomaticTransactionGenerator | undefined;
   public ocppConfiguration!: ChargingStationOcppConfiguration | undefined;
   public wsConnection!: WebSocket | null;
-  public connectors: Map<number, ConnectorStatus>;
+  public readonly connectors: Map<number, ConnectorStatus>;
   public readonly evses: Map<number, EvseStatus>;
   public readonly requests: Map<string, CachedRequest>;
   public performanceStatistics!: PerformanceStatistics | undefined;
@@ -183,8 +185,9 @@ export class ChargingStation {
   };
 
   public hasIdTags(): boolean {
-    const idTagsFile = ChargingStationUtils.getIdTagsFile(this.stationInfo);
-    return Utils.isNotEmptyArray(this.idTagsCache.getIdTags(idTagsFile));
+    return Utils.isNotEmptyArray(
+      this.idTagsCache.getIdTags(ChargingStationUtils.getIdTagsFile(this.stationInfo))
+    );
   }
 
   public getEnableStatistics(): boolean {
@@ -1312,18 +1315,15 @@ export class ChargingStation {
 
   private initializeConnectorsOrEvsesFromFile(configuration: ChargingStationConfiguration): void {
     if (configuration?.connectorsStatus && !configuration?.evsesStatus) {
-      this.connectors = new Map<number, ConnectorStatus>(
-        configuration?.connectorsStatus.map((connectorStatus, connectorId) => [
-          connectorId,
-          connectorStatus,
-        ])
-      );
+      for (const [connectorId, connectorStatus] of configuration.connectorsStatus.entries()) {
+        this.connectors.set(connectorId, Utils.cloneObject<ConnectorStatus>(connectorStatus));
+      }
     } else if (configuration?.evsesStatus && !configuration?.connectorsStatus) {
       for (const [evseId, evseStatusConfiguration] of configuration.evsesStatus.entries()) {
-        const evseStatus = Utils.cloneObject(evseStatusConfiguration);
+        const evseStatus = Utils.cloneObject<EvseStatusConfiguration>(evseStatusConfiguration);
         delete evseStatus.connectorsStatus;
         this.evses.set(evseId, {
-          ...evseStatus,
+          ...(evseStatus as EvseStatus),
           connectors: new Map<number, ConnectorStatus>(
             evseStatusConfiguration.connectorsStatus.map((connectorStatus, connectorId) => [
               connectorId,
@@ -1557,7 +1557,7 @@ export class ChargingStation {
           fs.mkdirSync(path.dirname(this.configurationFile), { recursive: true });
         }
         let configurationData: ChargingStationConfiguration =
-          Utils.cloneObject(this.getConfigurationFromFile()) ?? {};
+          Utils.cloneObject<ChargingStationConfiguration>(this.getConfigurationFromFile()) ?? {};
         if (this.getStationInfoPersistentConfiguration() && this.stationInfo) {
           configurationData.stationInfo = this.stationInfo;
         }
@@ -1595,16 +1595,30 @@ export class ChargingStation {
           .update(JSON.stringify(configurationData))
           .digest('hex');
         if (this.configurationFileHash !== configurationHash) {
-          configurationData.configurationHash = configurationHash;
-          const measureId = `${FileType.ChargingStationConfiguration} write`;
-          const beginId = PerformanceStatistics.beginMeasure(measureId);
-          const fileDescriptor = fs.openSync(this.configurationFile, 'w');
-          fs.writeFileSync(fileDescriptor, JSON.stringify(configurationData, null, 2), 'utf8');
-          fs.closeSync(fileDescriptor);
-          PerformanceStatistics.endMeasure(measureId, beginId);
-          this.sharedLRUCache.deleteChargingStationConfiguration(this.configurationFileHash);
-          this.sharedLRUCache.setChargingStationConfiguration(configurationData);
-          this.configurationFileHash = configurationHash;
+          AsyncLock.acquire(AsyncLockType.configuration)
+            .then(() => {
+              configurationData.configurationHash = configurationHash;
+              const measureId = `${FileType.ChargingStationConfiguration} write`;
+              const beginId = PerformanceStatistics.beginMeasure(measureId);
+              const fileDescriptor = fs.openSync(this.configurationFile, 'w');
+              fs.writeFileSync(fileDescriptor, JSON.stringify(configurationData, null, 2), 'utf8');
+              fs.closeSync(fileDescriptor);
+              PerformanceStatistics.endMeasure(measureId, beginId);
+              this.sharedLRUCache.deleteChargingStationConfiguration(this.configurationFileHash);
+              this.sharedLRUCache.setChargingStationConfiguration(configurationData);
+              this.configurationFileHash = configurationHash;
+            })
+            .catch((error) => {
+              FileUtils.handleFileException(
+                this.configurationFile,
+                FileType.ChargingStationConfiguration,
+                error as NodeJS.ErrnoException,
+                this.logPrefix()
+              );
+            })
+            .finally(() => {
+              AsyncLock.release(AsyncLockType.configuration).catch(Constants.EMPTY_FUNCTION);
+            });
         } else {
           logger.debug(
             `${this.logPrefix()} Not saving unchanged charging station configuration file ${
@@ -1632,20 +1646,9 @@ export class ChargingStation {
   }
 
   private getOcppConfigurationFromFile(): ChargingStationOcppConfiguration | undefined {
-    let configuration: ChargingStationConfiguration | undefined;
     if (this.getOcppPersistentConfiguration() === true) {
-      const configurationFromFile = this.getConfigurationFromFile();
-      configuration = configurationFromFile?.configurationKey && configurationFromFile;
+      return { configurationKey: this.getConfigurationFromFile()?.configurationKey };
     }
-    if (!Utils.isNullOrUndefined(configuration)) {
-      delete configuration.stationInfo;
-      delete configuration.connectorsStatus;
-      delete configuration.evsesStatus;
-      delete configuration.automaticTransactionGenerator;
-      delete configuration.automaticTransactionGeneratorStatuses;
-      delete configuration.configurationHash;
-    }
-    return configuration;
   }
 
   private getOcppConfiguration(): ChargingStationOcppConfiguration | undefined {
@@ -2036,7 +2039,8 @@ export class ChargingStation {
             await OCPPServiceUtils.sendAndSetConnectorStatus(
               this,
               connectorId,
-              connectorBootStatus
+              connectorBootStatus,
+              evseId
             );
           }
         }
@@ -2096,7 +2100,8 @@ export class ChargingStation {
               OCPPServiceUtils.buildStatusNotificationRequest(
                 this,
                 connectorId,
-                ConnectorStatusEnum.Unavailable
+                ConnectorStatusEnum.Unavailable,
+                evseId
               )
             );
             delete connectorStatus?.status;