docs: fix README.md formatting
[e-mobility-charging-stations-simulator.git] / src / charging-station / ui-server / ui-services / AbstractUIService.ts
index a4edbcaa1ac2b9195b9ff19bec57697530586c41..9d044a09e2a0ce11a0514884fa2e58ca3e64d6c6 100644 (file)
@@ -12,7 +12,7 @@ import {
   type ResponsePayload,
   ResponseStatus
 } from '../../../types/index.js'
-import { isNotEmptyArray, logger } from '../../../utils/index.js'
+import { isAsyncFunction, isNotEmptyArray, logger } from '../../../utils/index.js'
 import { Bootstrap } from '../../Bootstrap.js'
 import { UIServiceWorkerBroadcastChannel } from '../../broadcast-channel/UIServiceWorkerBroadcastChannel.js'
 import type { AbstractUIServer } from '../AbstractUIServer.js'
@@ -65,7 +65,9 @@ export abstract class AbstractUIService {
     this.uiServer = uiServer
     this.version = version
     this.requestHandlers = new Map<ProcedureName, ProtocolRequestHandler>([
+      [ProcedureName.LIST_TEMPLATES, this.handleListTemplates.bind(this)],
       [ProcedureName.LIST_CHARGING_STATIONS, this.handleListChargingStations.bind(this)],
+      [ProcedureName.ADD_CHARGING_STATIONS, this.handleAddChargingStations.bind(this)],
       [ProcedureName.START_SIMULATOR, this.handleStartSimulator.bind(this)],
       [ProcedureName.STOP_SIMULATOR, this.handleStopSimulator.bind(this)]
     ])
@@ -93,7 +95,18 @@ export abstract class AbstractUIService {
 
       // Call the request handler to build the response payload
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      responsePayload = await this.requestHandlers.get(command)!(messageId, command, requestPayload)
+      const requestHandler = this.requestHandlers.get(command)!
+      if (isAsyncFunction(requestHandler)) {
+        responsePayload = await requestHandler(messageId, command, requestPayload)
+      } else {
+        responsePayload = (
+          requestHandler as (
+            uuid?: string,
+            procedureName?: ProcedureName,
+            payload?: RequestPayload
+          ) => undefined | ResponsePayload
+        )(messageId, command, requestPayload)
+      }
     } catch (error) {
       // Log
       logger.error(`${this.logPrefix(moduleName, 'requestHandler')} Handle request error:`, error)
@@ -106,7 +119,7 @@ export abstract class AbstractUIService {
         errorMessage: (error as OCPPError).message,
         errorStack: (error as OCPPError).stack,
         errorDetails: (error as OCPPError).details
-      }
+      } satisfies ResponsePayload
     }
     if (responsePayload != null) {
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -163,7 +176,7 @@ export abstract class AbstractUIService {
   ): void {
     if (isNotEmptyArray(payload.hashIds)) {
       payload.hashIds = payload.hashIds
-        ?.map((hashId) => {
+        .map(hashId => {
           if (this.uiServer.chargingStations.has(hashId)) {
             return hashId
           }
@@ -175,7 +188,7 @@ export abstract class AbstractUIService {
           )
           return undefined
         })
-        ?.filter((hashId) => hashId != null) as string[]
+        .filter(hashId => hashId != null) as string[]
     } else {
       delete payload.hashIds
     }
@@ -191,6 +204,13 @@ export abstract class AbstractUIService {
     this.broadcastChannelRequests.set(uuid, expectedNumberOfResponses)
   }
 
+  private handleListTemplates (): ResponsePayload {
+    return {
+      status: ResponseStatus.SUCCESS,
+      templates: [...this.uiServer.chargingStationTemplates.values()] as JsonType[]
+    } satisfies ResponsePayload
+  }
+
   private handleListChargingStations (): ResponsePayload {
     return {
       status: ResponseStatus.SUCCESS,
@@ -198,6 +218,40 @@ export abstract class AbstractUIService {
     } satisfies ResponsePayload
   }
 
+  private async handleAddChargingStations (
+    messageId?: string,
+    procedureName?: ProcedureName,
+    requestPayload?: RequestPayload
+  ): Promise<ResponsePayload> {
+    const { template, numberOfStations } = requestPayload as {
+      template: string
+      numberOfStations: number
+    }
+    if (!this.uiServer.chargingStationTemplates.has(template)) {
+      return {
+        status: ResponseStatus.FAILURE,
+        errorMessage: `Template '${template}' not found`
+      } satisfies ResponsePayload
+    }
+    for (let i = 0; i < numberOfStations; i++) {
+      try {
+        await Bootstrap.getInstance().addChargingStation(
+          Bootstrap.getInstance().getLastIndex(template) + 1,
+          `${template}.json`
+        )
+      } catch (error) {
+        return {
+          status: ResponseStatus.FAILURE,
+          errorMessage: (error as Error).message,
+          errorStack: (error as Error).stack
+        } satisfies ResponsePayload
+      }
+    }
+    return {
+      status: ResponseStatus.SUCCESS
+    }
+  }
+
   private async handleStartSimulator (): Promise<ResponsePayload> {
     try {
       await Bootstrap.getInstance().start()