Vue UI + UI server
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / 1.6 / OCPP16IncomingRequestService.ts
index 64314475c8b42ea7ff6e90fd8a854b2d808e7540..b785db03574aaf6afcd10dea5676533153d0a56e 100644 (file)
@@ -9,7 +9,7 @@ import { Client, FTPResponse } from 'basic-ftp';
 import tar from 'tar';
 
 import OCPPError from '../../../exception/OCPPError';
-import { JsonType } from '../../../types/JsonType';
+import { JsonObject, JsonType } from '../../../types/JsonType';
 import { OCPP16ChargePointErrorCode } from '../../../types/ocpp/1.6/ChargePointErrorCode';
 import { OCPP16ChargePointStatus } from '../../../types/ocpp/1.6/ChargePointStatus';
 import {
@@ -88,18 +88,7 @@ const moduleName = 'OCPP16IncomingRequestService';
 
 export default class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
   private incomingRequestHandlers: Map<OCPP16IncomingRequestCommand, IncomingRequestHandler>;
-  private resetJsonSchema: JSONSchemaType<ResetRequest>;
-  private clearCacheJsonSchema: JSONSchemaType<OCPP16ClearCacheRequest>;
-  private getConfigurationJsonSchema: JSONSchemaType<GetConfigurationRequest>;
-  private changeConfigurationJsonSchema: JSONSchemaType<ChangeConfigurationRequest>;
-  private unlockConnectorJsonSchema: JSONSchemaType<UnlockConnectorRequest>;
-  private getDiagnosticsJsonSchema: JSONSchemaType<GetDiagnosticsRequest>;
-  private setChargingProfileJsonSchema: JSONSchemaType<SetChargingProfileRequest>;
-  private clearChargingProfileJsonSchema: JSONSchemaType<ClearChargingProfileRequest>;
-  private changeAvailabilityJsonSchema: JSONSchemaType<ChangeAvailabilityRequest>;
-  private remoteStartTransactionJsonSchema: JSONSchemaType<RemoteStartTransactionRequest>;
-  private remoteStopTransactionJsonSchema: JSONSchemaType<RemoteStopTransactionRequest>;
-  private triggerMessageJsonSchema: JSONSchemaType<OCPP16TriggerMessageRequest>;
+  private jsonSchemas: Map<OCPP16IncomingRequestCommand, JSONSchemaType<JsonObject>>;
 
   public constructor() {
     if (new.target?.name === moduleName) {
@@ -141,114 +130,153 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
       [OCPP16IncomingRequestCommand.GET_DIAGNOSTICS, this.handleRequestGetDiagnostics.bind(this)],
       [OCPP16IncomingRequestCommand.TRIGGER_MESSAGE, this.handleRequestTriggerMessage.bind(this)],
     ]);
-    this.resetJsonSchema = JSON.parse(
-      fs.readFileSync(
-        path.resolve(
-          path.dirname(fileURLToPath(import.meta.url)),
-          '../../../assets/json-schemas/ocpp/1.6/Reset.json'
-        ),
-        'utf8'
-      )
-    ) as JSONSchemaType<ResetRequest>;
-    this.clearCacheJsonSchema = JSON.parse(
-      fs.readFileSync(
-        path.resolve(
-          path.dirname(fileURLToPath(import.meta.url)),
-          '../../../assets/json-schemas/ocpp/1.6/ClearCache.json'
-        ),
-        'utf8'
-      )
-    ) as JSONSchemaType<OCPP16ClearCacheRequest>;
-    this.getConfigurationJsonSchema = JSON.parse(
-      fs.readFileSync(
-        path.resolve(
-          path.dirname(fileURLToPath(import.meta.url)),
-          '../../../assets/json-schemas/ocpp/1.6/GetConfiguration.json'
-        ),
-        'utf8'
-      )
-    ) as JSONSchemaType<GetConfigurationRequest>;
-    this.changeConfigurationJsonSchema = JSON.parse(
-      fs.readFileSync(
-        path.resolve(
-          path.dirname(fileURLToPath(import.meta.url)),
-          '../../../assets/json-schemas/ocpp/1.6/ChangeConfiguration.json'
-        ),
-        'utf8'
-      )
-    ) as JSONSchemaType<ChangeConfigurationRequest>;
-    this.unlockConnectorJsonSchema = JSON.parse(
-      fs.readFileSync(
-        path.resolve(
-          path.dirname(fileURLToPath(import.meta.url)),
-          '../../../assets/json-schemas/ocpp/1.6/UnlockConnector.json'
-        ),
-        'utf8'
-      )
-    ) as JSONSchemaType<UnlockConnectorRequest>;
-    this.getDiagnosticsJsonSchema = JSON.parse(
-      fs.readFileSync(
-        path.resolve(
-          path.dirname(fileURLToPath(import.meta.url)),
-          '../../../assets/json-schemas/ocpp/1.6/GetDiagnostics.json'
-        ),
-        'utf8'
-      )
-    ) as JSONSchemaType<GetDiagnosticsRequest>;
-    this.setChargingProfileJsonSchema = JSON.parse(
-      fs.readFileSync(
-        path.resolve(
-          path.dirname(fileURLToPath(import.meta.url)),
-          '../../../assets/json-schemas/ocpp/1.6/SetChargingProfile.json'
-        ),
-        'utf8'
-      )
-    ) as JSONSchemaType<SetChargingProfileRequest>;
-    this.clearChargingProfileJsonSchema = JSON.parse(
-      fs.readFileSync(
-        path.resolve(
-          path.dirname(fileURLToPath(import.meta.url)),
-          '../../../assets/json-schemas/ocpp/1.6/ClearChargingProfile.json'
-        ),
-        'utf8'
-      )
-    ) as JSONSchemaType<ClearChargingProfileRequest>;
-    this.changeAvailabilityJsonSchema = JSON.parse(
-      fs.readFileSync(
-        path.resolve(
-          path.dirname(fileURLToPath(import.meta.url)),
-          '../../../assets/json-schemas/ocpp/1.6/ChangeAvailability.json'
-        ),
-        'utf8'
-      )
-    ) as JSONSchemaType<ChangeAvailabilityRequest>;
-    this.remoteStartTransactionJsonSchema = JSON.parse(
-      fs.readFileSync(
-        path.resolve(
-          path.dirname(fileURLToPath(import.meta.url)),
-          '../../../assets/json-schemas/ocpp/1.6/RemoteStartTransaction.json'
-        ),
-        'utf8'
-      )
-    ) as JSONSchemaType<RemoteStartTransactionRequest>;
-    this.remoteStopTransactionJsonSchema = JSON.parse(
-      fs.readFileSync(
-        path.resolve(
-          path.dirname(fileURLToPath(import.meta.url)),
-          '../../../assets/json-schemas/ocpp/1.6/RemoteStopTransaction.json'
-        ),
-        'utf8'
-      )
-    ) as JSONSchemaType<RemoteStopTransactionRequest>;
-    this.triggerMessageJsonSchema = JSON.parse(
-      fs.readFileSync(
-        path.resolve(
-          path.dirname(fileURLToPath(import.meta.url)),
-          '../../../assets/json-schemas/ocpp/1.6/TriggerMessage.json'
-        ),
-        'utf8'
-      )
-    ) as JSONSchemaType<OCPP16TriggerMessageRequest>;
+    this.jsonSchemas = new Map<OCPP16IncomingRequestCommand, JSONSchemaType<JsonObject>>([
+      [
+        OCPP16IncomingRequestCommand.RESET,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/Reset.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<ResetRequest>,
+      ],
+      [
+        OCPP16IncomingRequestCommand.CLEAR_CACHE,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/ClearCache.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<OCPP16ClearCacheRequest>,
+      ],
+      [
+        OCPP16IncomingRequestCommand.UNLOCK_CONNECTOR,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/UnlockConnector.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<UnlockConnectorRequest>,
+      ],
+      [
+        OCPP16IncomingRequestCommand.GET_CONFIGURATION,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/GetConfiguration.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<GetConfigurationRequest>,
+      ],
+      [
+        OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/ChangeConfiguration.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<ChangeConfigurationRequest>,
+      ],
+      [
+        OCPP16IncomingRequestCommand.GET_DIAGNOSTICS,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/GetDiagnostics.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<GetDiagnosticsRequest>,
+      ],
+      [
+        OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/SetChargingProfile.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<SetChargingProfileRequest>,
+      ],
+      [
+        OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/ClearChargingProfile.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<ClearChargingProfileRequest>,
+      ],
+      [
+        OCPP16IncomingRequestCommand.CHANGE_AVAILABILITY,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/ChangeAvailability.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<ChangeAvailabilityRequest>,
+      ],
+      [
+        OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/RemoteStartTransaction.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<RemoteStartTransactionRequest>,
+      ],
+      [
+        OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/RemoteStopTransaction.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<RemoteStopTransactionRequest>,
+      ],
+      [
+        OCPP16IncomingRequestCommand.TRIGGER_MESSAGE,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/TriggerMessage.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<OCPP16TriggerMessageRequest>,
+      ],
+    ]);
+    this.validatePayload.bind(this);
   }
 
   public async incomingRequestHandler(
@@ -284,6 +312,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
         ChargingStationUtils.isIncomingRequestCommandSupported(commandName, chargingStation)
       ) {
         try {
+          this.validatePayload(chargingStation, commandName, commandPayload);
           // Call the method to build the response
           response = await this.incomingRequestHandlers.get(commandName)(
             chargingStation,
@@ -291,7 +320,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
           );
         } catch (error) {
           // Log
-          logger.error(chargingStation.logPrefix() + ' Handle request error: %j', error);
+          logger.error(chargingStation.logPrefix() + ' Handle request error:', error);
           throw error;
         }
       } else {
@@ -328,17 +357,30 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     );
   }
 
+  private validatePayload(
+    chargingStation: ChargingStation,
+    commandName: OCPP16IncomingRequestCommand,
+    commandPayload: JsonType
+  ): boolean {
+    if (this.jsonSchemas.has(commandName)) {
+      return this.validateIncomingRequestPayload(
+        chargingStation,
+        commandName,
+        this.jsonSchemas.get(commandName),
+        commandPayload
+      );
+    }
+    logger.warn(
+      `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command ${commandName} PDU validation`
+    );
+    return false;
+  }
+
   // Simulate charging station restart
   private handleRequestReset(
     chargingStation: ChargingStation,
     commandPayload: ResetRequest
   ): DefaultResponse {
-    this.validateIncomingRequestPayload(
-      chargingStation,
-      OCPP16IncomingRequestCommand.RESET,
-      this.resetJsonSchema,
-      commandPayload
-    );
     // eslint-disable-next-line @typescript-eslint/no-misused-promises
     setImmediate(async (): Promise<void> => {
       await chargingStation.reset((commandPayload.type + 'Reset') as OCPP16StopTransactionReason);
@@ -353,16 +395,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     return Constants.OCPP_RESPONSE_ACCEPTED;
   }
 
-  private handleRequestClearCache(
-    chargingStation: ChargingStation,
-    commandPayload: OCPP16ClearCacheRequest
-  ): DefaultResponse {
-    this.validateIncomingRequestPayload(
-      chargingStation,
-      OCPP16IncomingRequestCommand.CLEAR_CACHE,
-      this.clearCacheJsonSchema,
-      commandPayload
-    );
+  private handleRequestClearCache(): DefaultResponse {
     return Constants.OCPP_RESPONSE_ACCEPTED;
   }
 
@@ -370,12 +403,6 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     chargingStation: ChargingStation,
     commandPayload: UnlockConnectorRequest
   ): Promise<UnlockConnectorResponse> {
-    this.validateIncomingRequestPayload(
-      chargingStation,
-      OCPP16IncomingRequestCommand.UNLOCK_CONNECTOR,
-      this.unlockConnectorJsonSchema,
-      commandPayload
-    );
     const connectorId = commandPayload.connectorId;
     if (connectorId === 0) {
       logger.error(
@@ -435,12 +462,6 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     chargingStation: ChargingStation,
     commandPayload: GetConfigurationRequest
   ): GetConfigurationResponse {
-    this.validateIncomingRequestPayload(
-      chargingStation,
-      OCPP16IncomingRequestCommand.GET_CONFIGURATION,
-      this.getConfigurationJsonSchema,
-      commandPayload
-    );
     const configurationKey: OCPPConfigurationKey[] = [];
     const unknownKey: string[] = [];
     if (Utils.isEmptyArray(commandPayload.key)) {
@@ -490,12 +511,6 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     chargingStation: ChargingStation,
     commandPayload: ChangeConfigurationRequest
   ): ChangeConfigurationResponse {
-    this.validateIncomingRequestPayload(
-      chargingStation,
-      OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION,
-      this.changeConfigurationJsonSchema,
-      commandPayload
-    );
     const keyToChange = ChargingStationConfigurationUtils.getConfigurationKey(
       chargingStation,
       commandPayload.key,
@@ -550,12 +565,6 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     chargingStation: ChargingStation,
     commandPayload: SetChargingProfileRequest
   ): SetChargingProfileResponse {
-    this.validateIncomingRequestPayload(
-      chargingStation,
-      OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE,
-      this.setChargingProfileJsonSchema,
-      commandPayload
-    );
     if (
       !OCPP16ServiceUtils.checkFeatureProfile(
         chargingStation,
@@ -605,12 +614,6 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     chargingStation: ChargingStation,
     commandPayload: ClearChargingProfileRequest
   ): ClearChargingProfileResponse {
-    this.validateIncomingRequestPayload(
-      chargingStation,
-      OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE,
-      this.clearChargingProfileJsonSchema,
-      commandPayload
-    );
     if (
       !OCPP16ServiceUtils.checkFeatureProfile(
         chargingStation,
@@ -692,12 +695,6 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     chargingStation: ChargingStation,
     commandPayload: ChangeAvailabilityRequest
   ): Promise<ChangeAvailabilityResponse> {
-    this.validateIncomingRequestPayload(
-      chargingStation,
-      OCPP16IncomingRequestCommand.CHANGE_AVAILABILITY,
-      this.changeAvailabilityJsonSchema,
-      commandPayload
-    );
     const connectorId: number = commandPayload.connectorId;
     if (!chargingStation.getConnectorStatus(connectorId)) {
       logger.error(
@@ -759,12 +756,6 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     chargingStation: ChargingStation,
     commandPayload: RemoteStartTransactionRequest
   ): Promise<DefaultResponse> {
-    this.validateIncomingRequestPayload(
-      chargingStation,
-      OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION,
-      this.remoteStartTransactionJsonSchema,
-      commandPayload
-    );
     const transactionConnectorId = commandPayload.connectorId;
     const connectorStatus = chargingStation.getConnectorStatus(transactionConnectorId);
     if (transactionConnectorId) {
@@ -976,12 +967,6 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     chargingStation: ChargingStation,
     commandPayload: RemoteStopTransactionRequest
   ): Promise<DefaultResponse> {
-    this.validateIncomingRequestPayload(
-      chargingStation,
-      OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION,
-      this.remoteStopTransactionJsonSchema,
-      commandPayload
-    );
     const transactionId = commandPayload.transactionId;
     for (const connectorId of chargingStation.connectors.keys()) {
       if (
@@ -1040,12 +1025,6 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     chargingStation: ChargingStation,
     commandPayload: GetDiagnosticsRequest
   ): Promise<GetDiagnosticsResponse> {
-    this.validateIncomingRequestPayload(
-      chargingStation,
-      OCPP16IncomingRequestCommand.GET_DIAGNOSTICS,
-      this.getDiagnosticsJsonSchema,
-      commandPayload
-    );
     if (
       !OCPP16ServiceUtils.checkFeatureProfile(
         chargingStation,
@@ -1166,12 +1145,6 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     chargingStation: ChargingStation,
     commandPayload: OCPP16TriggerMessageRequest
   ): OCPP16TriggerMessageResponse {
-    this.validateIncomingRequestPayload(
-      chargingStation,
-      OCPP16IncomingRequestCommand.TRIGGER_MESSAGE,
-      this.triggerMessageJsonSchema,
-      commandPayload
-    );
     if (
       !OCPP16ServiceUtils.checkFeatureProfile(
         chargingStation,