refactor(simulator): constify and factor out empty data structure
authorJérôme Benoit <jerome.benoit@sap.com>
Sat, 25 Feb 2023 21:32:48 +0000 (22:32 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Sun, 26 Feb 2023 05:22:22 +0000 (06:22 +0100)
     definitions

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
20 files changed:
src/charging-station/AutomaticTransactionGenerator.ts
src/charging-station/ChargingStation.ts
src/charging-station/ChargingStationConfigurationUtils.ts
src/charging-station/ChargingStationUtils.ts
src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts
src/charging-station/ocpp/1.6/OCPP16ResponseService.ts
src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts
src/charging-station/ocpp/2.0/OCPP20ResponseService.ts
src/charging-station/ocpp/OCPPConstants.ts
src/charging-station/ocpp/OCPPRequestService.ts
src/charging-station/ui-server/UIHttpServer.ts
src/charging-station/ui-server/UIWebSocketServer.ts
src/exception/OCPPError.ts
src/performance/PerformanceStatistics.ts
src/performance/storage/JsonFileStorage.ts
src/utils/Constants.ts
src/worker/WorkerAbstract.ts
src/worker/WorkerConstants.ts
src/worker/WorkerFactory.ts
src/worker/WorkerSet.ts

index 26b3a2a22357c6d6ae5afce2db6ae3ae347a9608..4185215aae0d25ceccf9618bb289712d46d96ed2 100644 (file)
@@ -101,9 +101,7 @@ export class AutomaticTransactionGenerator extends AsyncResource {
         ) => Promise<void>,
         this,
         connectorId
-      ).catch(() => {
-        /* This is intentional */
-      });
+      ).catch(Constants.EMPTY_FUNCTION);
     } else if (this.connectorsStatus.get(connectorId)?.start === true) {
       logger.warn(`${this.logPrefix(connectorId)} is already started on connector`);
     }
index 23724e79014584cdf9d5dc042cd29b0fcce0f249..f57aebed788c3135aa08bae6ebc392c3640bd63e 100644 (file)
@@ -625,7 +625,7 @@ export class ChargingStation {
   }
 
   public openWSConnection(
-    options: WsOptions = this.stationInfo?.wsOptions ?? {},
+    options: WsOptions = this.stationInfo?.wsOptions ?? Constants.EMPTY_OBJECT,
     params: { closeOpened?: boolean; terminateOpened?: boolean } = {
       closeOpened: false,
       terminateOpened: false,
@@ -902,7 +902,7 @@ export class ChargingStation {
         },
         reset: true,
       },
-      stationTemplate?.firmwareUpgrade ?? {}
+      stationTemplate?.firmwareUpgrade ?? Constants.EMPTY_OBJECT
     );
     stationInfo.resetTime = !Utils.isNullOrUndefined(stationTemplate?.resetTime)
       ? stationTemplate.resetTime * 1000
@@ -1362,7 +1362,7 @@ export class ChargingStation {
           fs.mkdirSync(path.dirname(this.configurationFile), { recursive: true });
         }
         const configurationData: ChargingStationConfiguration =
-          Utils.cloneObject(this.getConfigurationFromFile()) ?? {};
+          Utils.cloneObject(this.getConfigurationFromFile()) ?? Constants.EMPTY_OBJECT;
         this.ocppConfiguration?.configurationKey &&
           (configurationData.configurationKey = this.ocppConfiguration.configurationKey);
         this.stationInfo && (configurationData.stationInfo = this.stationInfo);
@@ -2043,7 +2043,10 @@ export class ChargingStation {
         `${this.logPrefix()} WebSocket connection retry #${this.autoReconnectRetryCount.toString()}`
       );
       this.openWSConnection(
-        { ...(this.stationInfo?.wsOptions ?? {}), handshakeTimeout: reconnectTimeout },
+        {
+          ...(this.stationInfo?.wsOptions ?? Constants.EMPTY_OBJECT),
+          handshakeTimeout: reconnectTimeout,
+        },
         { closeOpened: true }
       );
       this.wsConnectionRestarted = true;
index 579e2ab49f2f129f5a7e362768636b39070ed7b0..5e14e4589cba3e63302833cc760ab710835fbed3 100644 (file)
@@ -1,6 +1,6 @@
 import type { ChargingStation } from './internal';
 import type { ConfigurationKey, ConfigurationKeyType } from '../types';
-import { logger } from '../utils';
+import { Constants, logger } from '../utils';
 
 type ConfigurationKeyOptions = { readonly?: boolean; visible?: boolean; reboot?: boolean };
 type DeleteConfigurationKeyParams = { save?: boolean; caseInsensitive?: boolean };
@@ -35,7 +35,7 @@ export class ChargingStationConfigurationUtils {
     },
     params: AddConfigurationKeyParams = { overwrite: false, save: false }
   ): void {
-    options = options ?? ({} as ConfigurationKeyOptions);
+    options = options ?? (Constants.EMPTY_OBJECT as ConfigurationKeyOptions);
     options.readonly = options?.readonly ?? false;
     options.visible = options?.visible ?? true;
     options.reboot = options?.reboot ?? false;
index 74ec539095991ce20cfed09d0b849e2b6aa4f809..22e712d03432a0e4c1a4557f0dbde07db42f54cd 100644 (file)
@@ -263,7 +263,7 @@ export class ChargingStationUtils {
       randomSerialNumber: true,
     }
   ): void {
-    params = params ?? {};
+    params = params ?? Constants.EMPTY_OBJECT;
     params.randomSerialNumberUpperCase = params?.randomSerialNumberUpperCase ?? true;
     params.randomSerialNumber = params?.randomSerialNumber ?? true;
     const serialNumberSuffix = params?.randomSerialNumber
index 9424fcf2c697d6112e26c0c841ae53f092d332d0..1179d425f1e0dd3ff4c92ed6e9c72ed321e0ed98 100644 (file)
@@ -358,9 +358,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       ) => Promise<void>,
       chargingStation,
       `${commandPayload.type}Reset` as OCPP16StopTransactionReason
-    ).catch(() => {
-      /* This is intentional */
-    });
+    ).catch(Constants.EMPTY_FUNCTION);
     logger.info(
       `${chargingStation.logPrefix()} ${
         commandPayload.type
@@ -977,14 +975,10 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
         ) => Promise<void>,
         this,
         chargingStation
-      ).catch(() => {
-        /* This is intentional */
-      });
+      ).catch(Constants.EMPTY_FUNCTION);
     } else {
       setTimeout(() => {
-        this.updateFirmware(chargingStation).catch(() => {
-          /* Intentional */
-        });
+        this.updateFirmware(chargingStation).catch(Constants.EMPTY_FUNCTION);
       }, retrieveDate?.getTime() - now);
     }
     return OCPPConstants.OCPP_RESPONSE_EMPTY;
@@ -1218,9 +1212,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
               .then((response) => {
                 chargingStation.bootNotificationResponse = response;
               })
-              .catch(() => {
-                /* This is intentional */
-              });
+              .catch(Constants.EMPTY_FUNCTION);
           }, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
           return OCPPConstants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
         case OCPP16MessageTrigger.Heartbeat:
@@ -1234,9 +1226,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
                   triggerMessage: true,
                 }
               )
-              .catch(() => {
-                /* This is intentional */
-              });
+              .catch(Constants.EMPTY_FUNCTION);
           }, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
           return OCPPConstants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
         case OCPP16MessageTrigger.StatusNotification:
@@ -1255,9 +1245,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
                     triggerMessage: true,
                   }
                 )
-                .catch(() => {
-                  /* This is intentional */
-                });
+                .catch(Constants.EMPTY_FUNCTION);
             } else {
               for (const connectorId of chargingStation.connectors.keys()) {
                 chargingStation.ocppRequestService
@@ -1276,9 +1264,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
                       triggerMessage: true,
                     }
                   )
-                  .catch(() => {
-                    /* This is intentional */
-                  });
+                  .catch(Constants.EMPTY_FUNCTION);
               }
             }
           }, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
index 6997e3d89b939d91897c8c799d29601674f371c6..df8a02e8ca2b9861a904a328236db4bbf4ea1757 100644 (file)
@@ -353,7 +353,7 @@ export class OCPP16ResponseService extends OCPPResponseService {
         chargingStation,
         OCPP16StandardParametersKey.HeartbeatInterval,
         payload.interval.toString(),
-        {},
+        Constants.EMPTY_OBJECT,
         { overwrite: true, save: true }
       );
       ChargingStationConfigurationUtils.addConfigurationKey(
index 50f6b92540bf35090ced70340431a5f4f3756000..907cee323612146cc01b44675f784dbf15aac435 100644 (file)
@@ -196,7 +196,8 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils {
       connectorId,
       OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT
     );
-    let powerPerPhaseSampledValueTemplates: MeasurandPerPhaseSampledValueTemplates = {};
+    let powerPerPhaseSampledValueTemplates: MeasurandPerPhaseSampledValueTemplates =
+      Constants.EMPTY_OBJECT;
     if (chargingStation.getNumberOfPhases() === 3) {
       powerPerPhaseSampledValueTemplates = {
         L1: OCPP16ServiceUtils.getSampledValueTemplate(
@@ -233,7 +234,7 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils {
         powerSampledValueTemplate.measurand ??
         OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
       } measurand value`;
-      const powerMeasurandValues = {} as MeasurandValues;
+      const powerMeasurandValues = Constants.EMPTY_OBJECT as MeasurandValues;
       const unitDivider = powerSampledValueTemplate?.unit === MeterValueUnit.KILO_WATT ? 1000 : 1;
       const connectorMaximumAvailablePower =
         chargingStation.getConnectorMaximumAvailablePower(connectorId);
@@ -403,7 +404,8 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils {
       connectorId,
       OCPP16MeterValueMeasurand.CURRENT_IMPORT
     );
-    let currentPerPhaseSampledValueTemplates: MeasurandPerPhaseSampledValueTemplates = {};
+    let currentPerPhaseSampledValueTemplates: MeasurandPerPhaseSampledValueTemplates =
+      Constants.EMPTY_OBJECT;
     if (chargingStation.getNumberOfPhases() === 3) {
       currentPerPhaseSampledValueTemplates = {
         L1: OCPP16ServiceUtils.getSampledValueTemplate(
@@ -440,7 +442,7 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils {
         currentSampledValueTemplate.measurand ??
         OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
       } measurand value`;
-      const currentMeasurandValues: MeasurandValues = {} as MeasurandValues;
+      const currentMeasurandValues: MeasurandValues = Constants.EMPTY_OBJECT as MeasurandValues;
       const connectorMaximumAvailablePower =
         chargingStation.getConnectorMaximumAvailablePower(connectorId);
       let connectorMaximumAmperage: number;
index 6772fd46a2b4406166833fa8f8eb17c32d0c6fcf..eb6c00c36de26281bd744811dbc2cc52ae998845 100644 (file)
@@ -19,7 +19,7 @@ import {
   RegistrationStatusEnumType,
   type ResponseHandler,
 } from '../../../types';
-import { logger } from '../../../utils';
+import { Constants, logger } from '../../../utils';
 import { OCPP20ServiceUtils, OCPPResponseService } from '../internal';
 
 const moduleName = 'OCPP20ResponseService';
@@ -161,7 +161,7 @@ export class OCPP20ResponseService extends OCPPResponseService {
         chargingStation,
         OCPP20OptionalVariableName.HeartbeatInterval,
         payload.interval.toString(),
-        {},
+        Constants.EMPTY_OBJECT,
         { overwrite: true, save: true }
       );
       chargingStation.heartbeatSetInterval
index 1064a95a0e3ab1651162b38e1ad1defb7fd59e0c..c8b110e4262131d4ea33f6332cbe65766f53ff70 100644 (file)
@@ -8,10 +8,11 @@ import {
   TriggerMessageStatus,
   UnlockStatus,
 } from '../../types';
+import { Constants } from '../../utils';
 
 export class OCPPConstants {
-  static readonly OCPP_REQUEST_EMPTY = Object.freeze({});
-  static readonly OCPP_RESPONSE_EMPTY = Object.freeze({});
+  static readonly OCPP_REQUEST_EMPTY = Constants.EMPTY_FREEZED_OBJECT;
+  static readonly OCPP_RESPONSE_EMPTY = Constants.EMPTY_FREEZED_OBJECT;
   static readonly OCPP_RESPONSE_ACCEPTED = Object.freeze({ status: GenericStatus.Accepted });
   static readonly OCPP_RESPONSE_REJECTED = Object.freeze({ status: GenericStatus.Rejected });
 
index 0f05d9a3d53082f210eaf93c1225ed04b78f2d0a..4115eff1144f1c50a91e79f7197632f47fd6e553 100644 (file)
@@ -275,7 +275,7 @@ export abstract class OCPPRequestService {
                 ErrorType.GENERIC_ERROR,
                 `WebSocket closed or errored for buffered message id '${messageId}' with content '${messageToSend}'`,
                 commandName,
-                (messagePayload as JsonObject)?.details ?? {}
+                (messagePayload as JsonObject)?.details ?? Constants.EMPTY_FREEZED_OBJECT
               )
             );
           } else if (wsClosedOrErrored) {
@@ -283,7 +283,7 @@ export abstract class OCPPRequestService {
               ErrorType.GENERIC_ERROR,
               `WebSocket closed or errored for non buffered message id '${messageId}' with content '${messageToSend}'`,
               commandName,
-              (messagePayload as JsonObject)?.details ?? {}
+              (messagePayload as JsonObject)?.details ?? Constants.EMPTY_FREEZED_OBJECT
             );
             // Reject response
             if (messageType !== MessageType.CALL_MESSAGE) {
@@ -358,7 +358,7 @@ export abstract class OCPPRequestService {
           ErrorType.GENERIC_ERROR,
           `Timeout for message id '${messageId}'`,
           commandName,
-          (messagePayload as JsonObject)?.details ?? {}
+          (messagePayload as JsonObject)?.details ?? Constants.EMPTY_FREEZED_OBJECT
         ),
         () => {
           messageType === MessageType.CALL_MESSAGE && chargingStation.requests.delete(messageId);
index 186669ef83e96d42c2c2fed420f2153ba4a1bfff..9e33302682533c68d39e9536cc878bd15a3b68c6 100644 (file)
@@ -13,7 +13,7 @@ import {
   ResponseStatus,
   type UIServerConfiguration,
 } from '../../types';
-import { Utils, logger } from '../../utils';
+import { Constants, Utils, logger } from '../../utils';
 import { AbstractUIServer, UIServerUtils } from '../internal';
 
 const moduleName = 'UIHttpServer';
@@ -117,10 +117,14 @@ export class UIHttpServer extends AbstractUIServer {
             const body = JSON.parse(Buffer.concat(bodyBuffer).toString()) as RequestPayload;
             this.uiServices
               .get(version)
-              ?.requestHandler(this.buildProtocolRequest(uuid, procedureName, body ?? {}))
-              .catch(() => {
-                /* Error caught by AbstractUIService */
-              });
+              ?.requestHandler(
+                this.buildProtocolRequest(
+                  uuid,
+                  procedureName,
+                  body ?? Constants.EMPTY_FREEZED_OBJECT
+                )
+              )
+              .catch(Constants.EMPTY_FUNCTION);
           });
       } else {
         throw new BaseError(`Unsupported HTTP method: '${req.method}'`);
index 291e92631bc2864dda4a77c18fd702cf2763263c..bf9eb8b3a66b753907d98a2df18120dcd25291ce 100644 (file)
@@ -10,7 +10,7 @@ import {
   type UIServerConfiguration,
   WebSocketCloseEventStatusCode,
 } from '../../types';
-import { Utils, logger } from '../../utils';
+import { Constants, Utils, logger } from '../../utils';
 import { AbstractUIServer, UIServerUtils } from '../internal';
 
 const moduleName = 'UIWebSocketServer';
@@ -48,12 +48,7 @@ export class UIWebSocketServer extends AbstractUIServer {
         }
         const [requestId] = request as ProtocolRequest;
         this.responseHandlers.set(requestId, ws);
-        this.uiServices
-          .get(version)
-          ?.requestHandler(request)
-          .catch(() => {
-            /* Error caught by AbstractUIService */
-          });
+        this.uiServices.get(version)?.requestHandler(request).catch(Constants.EMPTY_FUNCTION);
       });
       ws.on('error', (error) => {
         logger.error(`${this.logPrefix(moduleName, 'start.ws.onerror')} WebSocket error:`, error);
index 3b23cc3b0d0c18a650a203042810750bd1e89b22..c5d25ddc23d402070437d511dce6a3ea11156bc3 100644 (file)
@@ -7,6 +7,7 @@ import {
   type JsonType,
   type RequestCommand,
 } from '../types';
+import { Constants } from '../utils';
 
 export class OCPPError extends BaseError {
   code: ErrorType;
@@ -23,6 +24,6 @@ export class OCPPError extends BaseError {
 
     this.code = code ?? ErrorType.GENERIC_ERROR;
     this.command = command;
-    this.details = details ?? {};
+    this.details = details ?? Constants.EMPTY_FREEZED_OBJECT;
   }
 }
index 69829ff186e71fd1aca40e465b1c4b654084c8fc..956b8d3606b31c5554f802061b457149d4051a1c 100644 (file)
@@ -226,7 +226,7 @@ export class PerformanceStatistics {
     const entryName = entry.name;
     // Initialize command statistics
     if (!this.statistics.statisticsData.has(entryName)) {
-      this.statistics.statisticsData.set(entryName, {});
+      this.statistics.statisticsData.set(entryName, Constants.EMPTY_OBJECT);
     }
     // Update current statistics
     this.statistics.updatedAt = new Date();
index 44340cc4e425a9b1faf5f520a9f69e344f8fab77..fcb35a4df0507569d941edbcb1aac223561e6be4 100644 (file)
@@ -5,7 +5,7 @@ import fs from 'node:fs';
 import lockfile from 'proper-lockfile';
 
 import { FileType, type Statistics } from '../../types';
-import { FileUtils, Utils } from '../../utils';
+import { Constants, FileUtils, Utils } from '../../utils';
 import { Storage } from '../internal';
 
 export class JsonFileStorage extends Storage {
@@ -42,9 +42,7 @@ export class JsonFileStorage extends Storage {
         }
         await release();
       })
-      .catch(() => {
-        /* This is intentional */
-      });
+      .catch(Constants.EMPTY_FUNCTION);
   }
 
   public open(): void {
index 246aa7882e92a2b99b3dc54e074f833f6f9ecc6d..67b40146464c168ded98a8f17e9eb3d1a5b04c31 100644 (file)
@@ -47,6 +47,12 @@ export class Constants {
 
   static readonly MAX_RANDOM_INTEGER = 281474976710654;
 
+  static EMPTY_OBJECT = {};
+  static readonly EMPTY_FREEZED_OBJECT = Object.freeze({});
+  static readonly EMPTY_FUNCTION = Object.freeze(() => {
+    /* This is intentional */
+  });
+
   private constructor() {
     // This is intentional
   }
index f677794883822ef2f4b2c1f075c793ae90612af0..2803eea464da27115e45e1a6a3546fdee46418a9 100644 (file)
@@ -23,10 +23,8 @@ export abstract class WorkerAbstract<T extends WorkerData> {
       poolMinSize: WorkerConstants.DEFAULT_POOL_MIN_SIZE,
       poolMaxSize: WorkerConstants.DEFAULT_POOL_MAX_SIZE,
       elementsPerWorker: WorkerConstants.DEFAULT_ELEMENTS_PER_WORKER,
-      poolOptions: {},
-      messageHandler: () => {
-        /* This is intentional */
-      },
+      poolOptions: WorkerConstants.EMPTY_OBJECT,
+      messageHandler: WorkerConstants.EMPTY_FUNCTION,
     }
   ) {
     if (!workerScript) {
index 8e34a165c7fcb0eecb60856e86d487f1483fbe90..12bb70accb53f170137313da6f1abc8d43cd8f68 100644 (file)
@@ -1,4 +1,9 @@
 export class WorkerConstants {
+  public static EMPTY_OBJECT = {};
+  public static readonly EMPTY_FUNCTION = Object.freeze(() => {
+    /* This is intentional */
+  });
+
   static readonly DEFAULT_ELEMENT_START_DELAY = 0;
   static readonly DEFAULT_WORKER_START_DELAY = 500;
   static readonly POOL_MAX_INACTIVE_TIME = 60000;
index e590ad14749974bacd9b0c6aa4022164d3323b48..ff13b80fec190e3ebd4050d38f76266c64b74bb2 100644 (file)
@@ -22,12 +22,13 @@ export class WorkerFactory {
     if (!isMainThread) {
       throw new Error('Cannot get a worker implementation outside the main thread');
     }
-    workerOptions = workerOptions ?? ({} as WorkerOptions);
+    workerOptions = workerOptions ?? (WorkerConstants.EMPTY_OBJECT as WorkerOptions);
     workerOptions.workerStartDelay =
       workerOptions?.workerStartDelay ?? WorkerConstants.DEFAULT_WORKER_START_DELAY;
     workerOptions.elementStartDelay =
       workerOptions?.elementStartDelay ?? WorkerConstants.DEFAULT_ELEMENT_START_DELAY;
-    workerOptions.poolOptions = workerOptions?.poolOptions ?? ({} as PoolOptions<Worker>);
+    workerOptions.poolOptions =
+      workerOptions?.poolOptions ?? (WorkerConstants.EMPTY_OBJECT as PoolOptions<Worker>);
     workerOptions?.messageHandler &&
       (workerOptions.poolOptions.messageHandler = workerOptions.messageHandler);
     let workerImplementation: WorkerAbstract<T> | null = null;
index a8a06a39a764fdc105f886e34ad8aab1d2075119..b8507d53fe96d24898d418ae1006bfca7cdfddbf 100644 (file)
@@ -3,6 +3,7 @@
 import { Worker } from 'node:worker_threads';
 
 import { WorkerAbstract } from './WorkerAbstract';
+import { WorkerConstants } from './WorkerConstants';
 import {
   type MessageHandler,
   type WorkerData,
@@ -89,12 +90,9 @@ export class WorkerSet extends WorkerAbstract<WorkerData> {
     const worker = new Worker(this.workerScript);
     worker.on(
       'message',
-      (
-        this.workerOptions?.messageHandler ??
-        (() => {
-          /* This is intentional */
-        })
-      ).bind(this) as MessageHandler<Worker>
+      (this.workerOptions?.messageHandler ?? WorkerConstants.EMPTY_FUNCTION).bind(
+        this
+      ) as MessageHandler<Worker>
     );
     worker.on('error', WorkerUtils.defaultErrorHandler.bind(this) as (err: Error) => void);
     worker.on('exit', (code) => {