perf: cache only JSON payload validation functions
authorJérôme Benoit <jerome.benoit@sap.com>
Thu, 25 Jan 2024 22:36:49 +0000 (23:36 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Thu, 25 Jan 2024 22:36:49 +0000 (23:36 +0100)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts
src/charging-station/ocpp/1.6/OCPP16RequestService.ts
src/charging-station/ocpp/1.6/OCPP16ResponseService.ts
src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts
src/charging-station/ocpp/2.0/OCPP20RequestService.ts
src/charging-station/ocpp/2.0/OCPP20ResponseService.ts
src/charging-station/ocpp/OCPPIncomingRequestService.ts
src/charging-station/ocpp/OCPPRequestService.ts
src/charging-station/ocpp/OCPPResponseService.ts

index f934d418e6161600982b53d0ec7fb2a034682a6e..5d6172c4f6e273973b083d6f187703fdc1c8aab4 100644 (file)
@@ -4,7 +4,7 @@ import { createWriteStream, readdirSync } from 'node:fs'
 import { dirname, join, resolve } from 'node:path'
 import { URL, fileURLToPath } from 'node:url'
 
-import type { JSONSchemaType } from 'ajv'
+import type { ValidateFunction } from 'ajv'
 import { Client, type FTPResponse } from 'basic-ftp'
 import {
   type Interval,
@@ -113,7 +113,11 @@ import { OCPPIncomingRequestService } from '../OCPPIncomingRequestService.js'
 const moduleName = 'OCPP16IncomingRequestService'
 
 export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
-  protected jsonSchemas: Map<OCPP16IncomingRequestCommand, JSONSchemaType<JsonType>>
+  protected jsonSchemasValidateFunction: Map<
+  OCPP16IncomingRequestCommand,
+  ValidateFunction<JsonType>
+  >
+
   private readonly incomingRequestHandlers: Map<
   OCPP16IncomingRequestCommand,
   IncomingRequestHandler
@@ -194,142 +198,213 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
         this.handleRequestCancelReservation.bind(this) as unknown as IncomingRequestHandler
       ]
     ])
-    this.jsonSchemas = new Map<OCPP16IncomingRequestCommand, JSONSchemaType<JsonType>>([
+    this.jsonSchemasValidateFunction = new Map<
+    OCPP16IncomingRequestCommand,
+    ValidateFunction<JsonType>
+    >([
       [
         OCPP16IncomingRequestCommand.RESET,
-        OCPP16ServiceUtils.parseJsonSchemaFile<ResetRequest>(
-          'assets/json-schemas/ocpp/1.6/Reset.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<ResetRequest>(
+              'assets/json-schemas/ocpp/1.6/Reset.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.CLEAR_CACHE,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ClearCacheRequest>(
-          'assets/json-schemas/ocpp/1.6/ClearCache.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ClearCacheRequest>(
+              'assets/json-schemas/ocpp/1.6/ClearCache.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.UNLOCK_CONNECTOR,
-        OCPP16ServiceUtils.parseJsonSchemaFile<UnlockConnectorRequest>(
-          'assets/json-schemas/ocpp/1.6/UnlockConnector.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<UnlockConnectorRequest>(
+              'assets/json-schemas/ocpp/1.6/UnlockConnector.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.GET_CONFIGURATION,
-        OCPP16ServiceUtils.parseJsonSchemaFile<GetConfigurationRequest>(
-          'assets/json-schemas/ocpp/1.6/GetConfiguration.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<GetConfigurationRequest>(
+              'assets/json-schemas/ocpp/1.6/GetConfiguration.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION,
-        OCPP16ServiceUtils.parseJsonSchemaFile<ChangeConfigurationRequest>(
-          'assets/json-schemas/ocpp/1.6/ChangeConfiguration.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<ChangeConfigurationRequest>(
+              'assets/json-schemas/ocpp/1.6/ChangeConfiguration.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.GET_DIAGNOSTICS,
-        OCPP16ServiceUtils.parseJsonSchemaFile<GetDiagnosticsRequest>(
-          'assets/json-schemas/ocpp/1.6/GetDiagnostics.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<GetDiagnosticsRequest>(
+              'assets/json-schemas/ocpp/1.6/GetDiagnostics.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.GET_COMPOSITE_SCHEDULE,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16GetCompositeScheduleRequest>(
-          'assets/json-schemas/ocpp/1.6/GetCompositeSchedule.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16GetCompositeScheduleRequest>(
+              'assets/json-schemas/ocpp/1.6/GetCompositeSchedule.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE,
-        OCPP16ServiceUtils.parseJsonSchemaFile<SetChargingProfileRequest>(
-          'assets/json-schemas/ocpp/1.6/SetChargingProfile.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<SetChargingProfileRequest>(
+              'assets/json-schemas/ocpp/1.6/SetChargingProfile.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ClearChargingProfileRequest>(
-          'assets/json-schemas/ocpp/1.6/ClearChargingProfile.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ClearChargingProfileRequest>(
+              'assets/json-schemas/ocpp/1.6/ClearChargingProfile.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.CHANGE_AVAILABILITY,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ChangeAvailabilityRequest>(
-          'assets/json-schemas/ocpp/1.6/ChangeAvailability.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ChangeAvailabilityRequest>(
+              'assets/json-schemas/ocpp/1.6/ChangeAvailability.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION,
-        OCPP16ServiceUtils.parseJsonSchemaFile<RemoteStartTransactionRequest>(
-          'assets/json-schemas/ocpp/1.6/RemoteStartTransaction.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<RemoteStartTransactionRequest>(
+              'assets/json-schemas/ocpp/1.6/RemoteStartTransaction.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION,
-        OCPP16ServiceUtils.parseJsonSchemaFile<RemoteStopTransactionRequest>(
-          'assets/json-schemas/ocpp/1.6/RemoteStopTransaction.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<RemoteStopTransactionRequest>(
+              'assets/json-schemas/ocpp/1.6/RemoteStopTransaction.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.TRIGGER_MESSAGE,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16TriggerMessageRequest>(
-          'assets/json-schemas/ocpp/1.6/TriggerMessage.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16TriggerMessageRequest>(
+              'assets/json-schemas/ocpp/1.6/TriggerMessage.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.DATA_TRANSFER,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DataTransferRequest>(
-          'assets/json-schemas/ocpp/1.6/DataTransfer.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DataTransferRequest>(
+              'assets/json-schemas/ocpp/1.6/DataTransfer.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.UPDATE_FIRMWARE,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16UpdateFirmwareRequest>(
-          'assets/json-schemas/ocpp/1.6/UpdateFirmware.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16UpdateFirmwareRequest>(
+              'assets/json-schemas/ocpp/1.6/UpdateFirmware.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.RESERVE_NOW,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ReserveNowRequest>(
-          'assets/json-schemas/ocpp/1.6/ReserveNow.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ReserveNowRequest>(
+              'assets/json-schemas/ocpp/1.6/ReserveNow.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.CANCEL_RESERVATION,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16CancelReservationRequest>(
-          'assets/json-schemas/ocpp/1.6/CancelReservation.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16CancelReservationRequest>(
+              'assets/json-schemas/ocpp/1.6/CancelReservation.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ]
     ])
     this.validatePayload = this.validatePayload.bind(this)
@@ -423,17 +498,11 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
     commandName: OCPP16IncomingRequestCommand,
     commandPayload: JsonType
   ): boolean {
-    if (this.jsonSchemas.has(commandName)) {
-      return this.validateIncomingRequestPayload(
-        chargingStation,
-        commandName,
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        this.jsonSchemas.get(commandName)!,
-        commandPayload
-      )
+    if (this.jsonSchemasValidateFunction.has(commandName)) {
+      return this.validateIncomingRequestPayload(chargingStation, commandName, commandPayload)
     }
     logger.warn(
-      `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command '${commandName}' PDU validation`
+      `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema validation function found for command '${commandName}' PDU validation`
     )
     return false
   }
index 37a5b2ba2811c36610fa1b8002e89ab5c64b3081..a7bacae9b2814fd5cc813fcb77d43db2964125b8 100644 (file)
@@ -1,6 +1,6 @@
 // Partial Copyright Jerome Benoit. 2021-2024. All Rights Reserved.
 
-import type { JSONSchemaType } from 'ajv'
+import type { ValidateFunction } from 'ajv'
 
 import { OCPP16Constants } from './OCPP16Constants.js'
 import { OCPP16ServiceUtils } from './OCPP16ServiceUtils.js'
@@ -32,93 +32,133 @@ import type { OCPPResponseService } from '../OCPPResponseService.js'
 const moduleName = 'OCPP16RequestService'
 
 export class OCPP16RequestService extends OCPPRequestService {
-  protected jsonSchemas: Map<OCPP16RequestCommand, JSONSchemaType<JsonType>>
+  protected jsonSchemasValidateFunction: Map<OCPP16RequestCommand, ValidateFunction<JsonType>>
 
   public constructor (ocppResponseService: OCPPResponseService) {
     // if (new.target.name === moduleName) {
     //   throw new TypeError(`Cannot construct ${new.target.name} instances directly`)
     // }
     super(OCPPVersion.VERSION_16, ocppResponseService)
-    this.jsonSchemas = new Map<OCPP16RequestCommand, JSONSchemaType<JsonType>>([
+    this.jsonSchemasValidateFunction = new Map<OCPP16RequestCommand, ValidateFunction<JsonType>>([
       [
         OCPP16RequestCommand.AUTHORIZE,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16AuthorizeRequest>(
-          'assets/json-schemas/ocpp/1.6/Authorize.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16AuthorizeRequest>(
+              'assets/json-schemas/ocpp/1.6/Authorize.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16RequestCommand.BOOT_NOTIFICATION,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16BootNotificationRequest>(
-          'assets/json-schemas/ocpp/1.6/BootNotification.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16BootNotificationRequest>(
+              'assets/json-schemas/ocpp/1.6/BootNotification.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DiagnosticsStatusNotificationRequest>(
-          'assets/json-schemas/ocpp/1.6/DiagnosticsStatusNotification.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DiagnosticsStatusNotificationRequest>(
+              'assets/json-schemas/ocpp/1.6/DiagnosticsStatusNotification.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16RequestCommand.HEARTBEAT,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16HeartbeatRequest>(
-          'assets/json-schemas/ocpp/1.6/Heartbeat.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16HeartbeatRequest>(
+              'assets/json-schemas/ocpp/1.6/Heartbeat.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16RequestCommand.METER_VALUES,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16MeterValuesRequest>(
-          'assets/json-schemas/ocpp/1.6/MeterValues.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16MeterValuesRequest>(
+              'assets/json-schemas/ocpp/1.6/MeterValues.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16RequestCommand.STATUS_NOTIFICATION,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StatusNotificationRequest>(
-          'assets/json-schemas/ocpp/1.6/StatusNotification.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StatusNotificationRequest>(
+              'assets/json-schemas/ocpp/1.6/StatusNotification.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16RequestCommand.START_TRANSACTION,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StartTransactionRequest>(
-          'assets/json-schemas/ocpp/1.6/StartTransaction.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StartTransactionRequest>(
+              'assets/json-schemas/ocpp/1.6/StartTransaction.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16RequestCommand.STOP_TRANSACTION,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StopTransactionRequest>(
-          'assets/json-schemas/ocpp/1.6/StopTransaction.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StopTransactionRequest>(
+              'assets/json-schemas/ocpp/1.6/StopTransaction.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16RequestCommand.DATA_TRANSFER,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DataTransferRequest>(
-          'assets/json-schemas/ocpp/1.6/DataTransfer.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DataTransferRequest>(
+              'assets/json-schemas/ocpp/1.6/DataTransfer.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16FirmwareStatusNotificationRequest>(
-          'assets/json-schemas/ocpp/1.6/FirmwareStatusNotification.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16FirmwareStatusNotificationRequest>(
+              'assets/json-schemas/ocpp/1.6/FirmwareStatusNotification.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ]
     ])
     this.buildRequestPayload = this.buildRequestPayload.bind(this)
index c47d2630fc41a2d948048e2f61648b33dc255f9a..e65f8a8cb3f7316a6415d8697e1bb527d1a5c20e 100644 (file)
@@ -1,6 +1,6 @@
 // Partial Copyright Jerome Benoit. 2021-2024. All Rights Reserved.
 
-import type { JSONSchemaType } from 'ajv'
+import type { ValidateFunction } from 'ajv'
 import { secondsToMilliseconds } from 'date-fns'
 
 import { OCPP16ServiceUtils } from './OCPP16ServiceUtils.js'
@@ -57,13 +57,13 @@ import { OCPPResponseService } from '../OCPPResponseService.js'
 const moduleName = 'OCPP16ResponseService'
 
 export class OCPP16ResponseService extends OCPPResponseService {
-  public jsonIncomingRequestResponseSchemas: Map<
+  public jsonSchemasIncomingRequestResponseValidateFunction: Map<
   OCPP16IncomingRequestCommand,
-  JSONSchemaType<JsonType>
+  ValidateFunction<JsonType>
   >
 
+  protected jsonSchemasValidateFunction: Map<OCPP16RequestCommand, ValidateFunction<JsonType>>
   private readonly responseHandlers: Map<OCPP16RequestCommand, ResponseHandler>
-  private readonly jsonSchemas: Map<OCPP16RequestCommand, JSONSchemaType<JsonType>>
 
   public constructor () {
     // if (new.target.name === moduleName) {
@@ -97,224 +97,335 @@ export class OCPP16ResponseService extends OCPPResponseService {
       [OCPP16RequestCommand.DATA_TRANSFER, this.emptyResponseHandler],
       [OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION, this.emptyResponseHandler]
     ])
-    this.jsonSchemas = new Map<OCPP16RequestCommand, JSONSchemaType<JsonType>>([
+    this.jsonSchemasValidateFunction = new Map<OCPP16RequestCommand, ValidateFunction<JsonType>>([
       [
         OCPP16RequestCommand.BOOT_NOTIFICATION,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16BootNotificationResponse>(
-          'assets/json-schemas/ocpp/1.6/BootNotificationResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16BootNotificationResponse>(
+              'assets/json-schemas/ocpp/1.6/BootNotificationResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16RequestCommand.HEARTBEAT,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16HeartbeatResponse>(
-          'assets/json-schemas/ocpp/1.6/HeartbeatResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16HeartbeatResponse>(
+              'assets/json-schemas/ocpp/1.6/HeartbeatResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16RequestCommand.AUTHORIZE,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16AuthorizeResponse>(
-          'assets/json-schemas/ocpp/1.6/AuthorizeResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16AuthorizeResponse>(
+              'assets/json-schemas/ocpp/1.6/AuthorizeResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16RequestCommand.START_TRANSACTION,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StartTransactionResponse>(
-          'assets/json-schemas/ocpp/1.6/StartTransactionResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StartTransactionResponse>(
+              'assets/json-schemas/ocpp/1.6/StartTransactionResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16RequestCommand.STOP_TRANSACTION,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StopTransactionResponse>(
-          'assets/json-schemas/ocpp/1.6/StopTransactionResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StopTransactionResponse>(
+              'assets/json-schemas/ocpp/1.6/StopTransactionResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16RequestCommand.STATUS_NOTIFICATION,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StatusNotificationResponse>(
-          'assets/json-schemas/ocpp/1.6/StatusNotificationResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StatusNotificationResponse>(
+              'assets/json-schemas/ocpp/1.6/StatusNotificationResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16RequestCommand.METER_VALUES,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16MeterValuesResponse>(
-          'assets/json-schemas/ocpp/1.6/MeterValuesResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16MeterValuesResponse>(
+              'assets/json-schemas/ocpp/1.6/MeterValuesResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DiagnosticsStatusNotificationResponse>(
-          'assets/json-schemas/ocpp/1.6/DiagnosticsStatusNotificationResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DiagnosticsStatusNotificationResponse>(
+              'assets/json-schemas/ocpp/1.6/DiagnosticsStatusNotificationResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16RequestCommand.DATA_TRANSFER,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DataTransferResponse>(
-          'assets/json-schemas/ocpp/1.6/DataTransferResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DataTransferResponse>(
+              'assets/json-schemas/ocpp/1.6/DataTransferResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16FirmwareStatusNotificationResponse>(
-          'assets/json-schemas/ocpp/1.6/FirmwareStatusNotificationResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16FirmwareStatusNotificationResponse>(
+              'assets/json-schemas/ocpp/1.6/FirmwareStatusNotificationResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ]
     ])
-    this.jsonIncomingRequestResponseSchemas = new Map([
+    this.jsonSchemasIncomingRequestResponseValidateFunction = new Map<
+    OCPP16IncomingRequestCommand,
+    ValidateFunction<JsonType>
+    >([
       [
         OCPP16IncomingRequestCommand.RESET,
-        OCPP16ServiceUtils.parseJsonSchemaFile<GenericResponse>(
-          'assets/json-schemas/ocpp/1.6/ResetResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<GenericResponse>(
+              'assets/json-schemas/ocpp/1.6/ResetResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.CLEAR_CACHE,
-        OCPP16ServiceUtils.parseJsonSchemaFile<GenericResponse>(
-          'assets/json-schemas/ocpp/1.6/ClearCacheResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<GenericResponse>(
+              'assets/json-schemas/ocpp/1.6/ClearCacheResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.CHANGE_AVAILABILITY,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ChangeAvailabilityResponse>(
-          'assets/json-schemas/ocpp/1.6/ChangeAvailabilityResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ChangeAvailabilityResponse>(
+              'assets/json-schemas/ocpp/1.6/ChangeAvailabilityResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.UNLOCK_CONNECTOR,
-        OCPP16ServiceUtils.parseJsonSchemaFile<UnlockConnectorResponse>(
-          'assets/json-schemas/ocpp/1.6/UnlockConnectorResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<UnlockConnectorResponse>(
+              'assets/json-schemas/ocpp/1.6/UnlockConnectorResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.GET_CONFIGURATION,
-        OCPP16ServiceUtils.parseJsonSchemaFile<GetConfigurationResponse>(
-          'assets/json-schemas/ocpp/1.6/GetConfigurationResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<GetConfigurationResponse>(
+              'assets/json-schemas/ocpp/1.6/GetConfigurationResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION,
-        OCPP16ServiceUtils.parseJsonSchemaFile<ChangeConfigurationResponse>(
-          'assets/json-schemas/ocpp/1.6/ChangeConfigurationResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<ChangeConfigurationResponse>(
+              'assets/json-schemas/ocpp/1.6/ChangeConfigurationResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.GET_COMPOSITE_SCHEDULE,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16GetCompositeScheduleResponse>(
-          'assets/json-schemas/ocpp/1.6/GetCompositeScheduleResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16GetCompositeScheduleResponse>(
+              'assets/json-schemas/ocpp/1.6/GetCompositeScheduleResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE,
-        OCPP16ServiceUtils.parseJsonSchemaFile<SetChargingProfileResponse>(
-          'assets/json-schemas/ocpp/1.6/SetChargingProfileResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<SetChargingProfileResponse>(
+              'assets/json-schemas/ocpp/1.6/SetChargingProfileResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ClearChargingProfileResponse>(
-          'assets/json-schemas/ocpp/1.6/ClearChargingProfileResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ClearChargingProfileResponse>(
+              'assets/json-schemas/ocpp/1.6/ClearChargingProfileResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION,
-        OCPP16ServiceUtils.parseJsonSchemaFile<GenericResponse>(
-          'assets/json-schemas/ocpp/1.6/RemoteStartTransactionResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<GenericResponse>(
+              'assets/json-schemas/ocpp/1.6/RemoteStartTransactionResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION,
-        OCPP16ServiceUtils.parseJsonSchemaFile<GenericResponse>(
-          'assets/json-schemas/ocpp/1.6/RemoteStopTransactionResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<GenericResponse>(
+              'assets/json-schemas/ocpp/1.6/RemoteStopTransactionResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.GET_DIAGNOSTICS,
-        OCPP16ServiceUtils.parseJsonSchemaFile<GetDiagnosticsResponse>(
-          'assets/json-schemas/ocpp/1.6/GetDiagnosticsResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<GetDiagnosticsResponse>(
+              'assets/json-schemas/ocpp/1.6/GetDiagnosticsResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.TRIGGER_MESSAGE,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16TriggerMessageResponse>(
-          'assets/json-schemas/ocpp/1.6/TriggerMessageResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16TriggerMessageResponse>(
+              'assets/json-schemas/ocpp/1.6/TriggerMessageResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.DATA_TRANSFER,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DataTransferResponse>(
-          'assets/json-schemas/ocpp/1.6/DataTransferResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DataTransferResponse>(
+              'assets/json-schemas/ocpp/1.6/DataTransferResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.UPDATE_FIRMWARE,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16UpdateFirmwareResponse>(
-          'assets/json-schemas/ocpp/1.6/UpdateFirmwareResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16UpdateFirmwareResponse>(
+              'assets/json-schemas/ocpp/1.6/UpdateFirmwareResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.RESERVE_NOW,
-        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ReserveNowResponse>(
-          'assets/json-schemas/ocpp/1.6/ReserveNowResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ReserveNowResponse>(
+              'assets/json-schemas/ocpp/1.6/ReserveNowResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP16IncomingRequestCommand.CANCEL_RESERVATION,
-        OCPP16ServiceUtils.parseJsonSchemaFile<GenericResponse>(
-          'assets/json-schemas/ocpp/1.6/CancelReservationResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP16ServiceUtils.parseJsonSchemaFile<GenericResponse>(
+              'assets/json-schemas/ocpp/1.6/CancelReservationResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ]
     ])
     this.validatePayload = this.validatePayload.bind(this)
@@ -374,17 +485,11 @@ export class OCPP16ResponseService extends OCPPResponseService {
     commandName: OCPP16RequestCommand,
     payload: JsonType
   ): boolean {
-    if (this.jsonSchemas.has(commandName)) {
-      return this.validateResponsePayload(
-        chargingStation,
-        commandName,
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        this.jsonSchemas.get(commandName)!,
-        payload
-      )
+    if (this.jsonSchemasValidateFunction.has(commandName)) {
+      return this.validateResponsePayload(chargingStation, commandName, payload)
     }
     logger.warn(
-      `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command '${commandName}' PDU validation`
+      `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema validation function found for command '${commandName}' PDU validation`
     )
     return false
   }
index 664189815103d2eb13580db72a568060f90dd924..cfc58323ed8ad4cf597c1a2b3b9227b86f8ba2cd 100644 (file)
@@ -1,6 +1,6 @@
 // Partial Copyright Jerome Benoit. 2021-2024. All Rights Reserved.
 
-import type { JSONSchemaType } from 'ajv'
+import type { ValidateFunction } from 'ajv'
 
 import { OCPP20ServiceUtils } from './OCPP20ServiceUtils.js'
 import type { ChargingStation } from '../../../charging-station/index.js'
@@ -19,7 +19,11 @@ import { OCPPIncomingRequestService } from '../OCPPIncomingRequestService.js'
 const moduleName = 'OCPP20IncomingRequestService'
 
 export class OCPP20IncomingRequestService extends OCPPIncomingRequestService {
-  protected jsonSchemas: Map<OCPP20IncomingRequestCommand, JSONSchemaType<JsonType>>
+  protected jsonSchemasValidateFunction: Map<
+  OCPP20IncomingRequestCommand,
+  ValidateFunction<JsonType>
+  >
+
   private readonly incomingRequestHandlers: Map<
   OCPP20IncomingRequestCommand,
   IncomingRequestHandler
@@ -33,14 +37,21 @@ export class OCPP20IncomingRequestService extends OCPPIncomingRequestService {
     this.incomingRequestHandlers = new Map<OCPP20IncomingRequestCommand, IncomingRequestHandler>([
       [OCPP20IncomingRequestCommand.CLEAR_CACHE, this.handleRequestClearCache.bind(this)]
     ])
-    this.jsonSchemas = new Map<OCPP20IncomingRequestCommand, JSONSchemaType<JsonType>>([
+    this.jsonSchemasValidateFunction = new Map<
+    OCPP20IncomingRequestCommand,
+    ValidateFunction<JsonType>
+    >([
       [
         OCPP20IncomingRequestCommand.CLEAR_CACHE,
-        OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20ClearCacheRequest>(
-          'assets/json-schemas/ocpp/2.0/ClearCacheRequest.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20ClearCacheRequest>(
+              'assets/json-schemas/ocpp/2.0/ClearCacheRequest.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ]
     ])
     this.validatePayload = this.validatePayload.bind(this)
@@ -134,17 +145,11 @@ export class OCPP20IncomingRequestService extends OCPPIncomingRequestService {
     commandName: OCPP20IncomingRequestCommand,
     commandPayload: JsonType
   ): boolean {
-    if (this.jsonSchemas.has(commandName)) {
-      return this.validateIncomingRequestPayload(
-        chargingStation,
-        commandName,
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        this.jsonSchemas.get(commandName)!,
-        commandPayload
-      )
+    if (this.jsonSchemasValidateFunction.has(commandName)) {
+      return this.validateIncomingRequestPayload(chargingStation, commandName, commandPayload)
     }
     logger.warn(
-      `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command '${commandName}' PDU validation`
+      `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema validation function found for command '${commandName}' PDU validation`
     )
     return false
   }
index e73b33ccb019cd92858fc5e15ad0aa59d1bd8b85..20bd333f69f466959c4c62f78b09ee4fc44dad69 100644 (file)
@@ -1,6 +1,6 @@
 // Partial Copyright Jerome Benoit. 2021-2024. All Rights Reserved.
 
-import type { JSONSchemaType } from 'ajv'
+import type { ValidateFunction } from 'ajv'
 
 import { OCPP20Constants } from './OCPP20Constants.js'
 import { OCPP20ServiceUtils } from './OCPP20ServiceUtils.js'
@@ -24,37 +24,49 @@ import type { OCPPResponseService } from '../OCPPResponseService.js'
 const moduleName = 'OCPP20RequestService'
 
 export class OCPP20RequestService extends OCPPRequestService {
-  protected jsonSchemas: Map<OCPP20RequestCommand, JSONSchemaType<JsonType>>
+  protected jsonSchemasValidateFunction: Map<OCPP20RequestCommand, ValidateFunction<JsonType>>
 
   public constructor (ocppResponseService: OCPPResponseService) {
     // if (new.target.name === moduleName) {
     //   throw new TypeError(`Cannot construct ${new.target.name} instances directly`)
     // }
     super(OCPPVersion.VERSION_20, ocppResponseService)
-    this.jsonSchemas = new Map<OCPP20RequestCommand, JSONSchemaType<JsonType>>([
+    this.jsonSchemasValidateFunction = new Map<OCPP20RequestCommand, ValidateFunction<JsonType>>([
       [
         OCPP20RequestCommand.BOOT_NOTIFICATION,
-        OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20BootNotificationRequest>(
-          'assets/json-schemas/ocpp/2.0/BootNotificationRequest.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20BootNotificationRequest>(
+              'assets/json-schemas/ocpp/2.0/BootNotificationRequest.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP20RequestCommand.HEARTBEAT,
-        OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20HeartbeatRequest>(
-          'assets/json-schemas/ocpp/2.0/HeartbeatRequest.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20HeartbeatRequest>(
+              'assets/json-schemas/ocpp/2.0/HeartbeatRequest.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP20RequestCommand.STATUS_NOTIFICATION,
-        OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20StatusNotificationRequest>(
-          'assets/json-schemas/ocpp/2.0/StatusNotificationRequest.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20StatusNotificationRequest>(
+              'assets/json-schemas/ocpp/2.0/StatusNotificationRequest.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ]
     ])
     this.buildRequestPayload = this.buildRequestPayload.bind(this)
index f35a8898eccec37284ea44b769af257ff8ccf300..99ca656614c452073bca6732fa3c4ba17fc509e1 100644 (file)
@@ -1,6 +1,6 @@
 // Partial Copyright Jerome Benoit. 2021-2024. All Rights Reserved.
 
-import type { JSONSchemaType } from 'ajv'
+import type { ValidateFunction } from 'ajv'
 
 import { OCPP20ServiceUtils } from './OCPP20ServiceUtils.js'
 import { type ChargingStation, addConfigurationKey } from '../../../charging-station/index.js'
@@ -25,13 +25,13 @@ import { OCPPResponseService } from '../OCPPResponseService.js'
 const moduleName = 'OCPP20ResponseService'
 
 export class OCPP20ResponseService extends OCPPResponseService {
-  public jsonIncomingRequestResponseSchemas: Map<
+  public jsonSchemasIncomingRequestResponseValidateFunction: Map<
   OCPP20IncomingRequestCommand,
-  JSONSchemaType<JsonType>
+  ValidateFunction<JsonType>
   >
 
+  protected jsonSchemasValidateFunction: Map<OCPP20RequestCommand, ValidateFunction<JsonType>>
   private readonly responseHandlers: Map<OCPP20RequestCommand, ResponseHandler>
-  private readonly jsonSchemas: Map<OCPP20RequestCommand, JSONSchemaType<JsonType>>
 
   public constructor () {
     // if (new.target.name === moduleName) {
@@ -46,40 +46,59 @@ export class OCPP20ResponseService extends OCPPResponseService {
       [OCPP20RequestCommand.HEARTBEAT, this.emptyResponseHandler],
       [OCPP20RequestCommand.STATUS_NOTIFICATION, this.emptyResponseHandler]
     ])
-    this.jsonSchemas = new Map<OCPP20RequestCommand, JSONSchemaType<JsonType>>([
+    this.jsonSchemasValidateFunction = new Map<OCPP20RequestCommand, ValidateFunction<JsonType>>([
       [
         OCPP20RequestCommand.BOOT_NOTIFICATION,
-        OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20BootNotificationResponse>(
-          'assets/json-schemas/ocpp/2.0/BootNotificationResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20BootNotificationResponse>(
+              'assets/json-schemas/ocpp/2.0/BootNotificationResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP20RequestCommand.HEARTBEAT,
-        OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20HeartbeatResponse>(
-          'assets/json-schemas/ocpp/2.0/HeartbeatResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20HeartbeatResponse>(
+              'assets/json-schemas/ocpp/2.0/HeartbeatResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ],
       [
         OCPP20RequestCommand.STATUS_NOTIFICATION,
-        OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20StatusNotificationResponse>(
-          'assets/json-schemas/ocpp/2.0/StatusNotificationResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20StatusNotificationResponse>(
+              'assets/json-schemas/ocpp/2.0/StatusNotificationResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ]
     ])
-    this.jsonIncomingRequestResponseSchemas = new Map([
+    this.jsonSchemasIncomingRequestResponseValidateFunction = new Map<
+    OCPP20IncomingRequestCommand,
+    ValidateFunction<JsonType>
+    >([
       [
         OCPP20IncomingRequestCommand.CLEAR_CACHE,
-        OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20ClearCacheResponse>(
-          'assets/json-schemas/ocpp/2.0/ClearCacheResponse.json',
-          moduleName,
-          'constructor'
-        )
+        this.ajv
+          .compile(
+            OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20ClearCacheResponse>(
+              'assets/json-schemas/ocpp/2.0/ClearCacheResponse.json',
+              moduleName,
+              'constructor'
+            )
+          )
+          .bind(this)
       ]
     ])
     this.validatePayload = this.validatePayload.bind(this)
@@ -139,17 +158,11 @@ export class OCPP20ResponseService extends OCPPResponseService {
     commandName: OCPP20RequestCommand,
     payload: JsonType
   ): boolean {
-    if (this.jsonSchemas.has(commandName)) {
-      return this.validateResponsePayload(
-        chargingStation,
-        commandName,
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        this.jsonSchemas.get(commandName)!,
-        payload
-      )
+    if (this.jsonSchemasValidateFunction.has(commandName)) {
+      return this.validateResponsePayload(chargingStation, commandName, payload)
     }
     logger.warn(
-      `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command '${commandName}' PDU validation`
+      `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema validation function found for command '${commandName}' PDU validation`
     )
     return false
   }
index 4285e585ac7b3aaa5fa9b530c3109350b11558eb..d0ff0229350ea4b03c20ea4d5dabd6becaa6f533 100644 (file)
@@ -1,4 +1,4 @@
-import _Ajv, { type JSONSchemaType, type ValidateFunction } from 'ajv'
+import _Ajv, { type ValidateFunction } from 'ajv'
 import _ajvFormats from 'ajv-formats'
 
 import { OCPPConstants } from './OCPPConstants.js'
@@ -23,9 +23,11 @@ const moduleName = 'OCPPIncomingRequestService'
 export abstract class OCPPIncomingRequestService {
   private static instance: OCPPIncomingRequestService | null = null
   private readonly version: OCPPVersion
-  private readonly ajv: Ajv
-  private readonly jsonValidateFunctions: Map<IncomingRequestCommand, ValidateFunction<JsonType>>
-  protected abstract jsonSchemas: Map<IncomingRequestCommand, JSONSchemaType<JsonType>>
+  protected readonly ajv: Ajv
+  protected abstract jsonSchemasValidateFunction: Map<
+  IncomingRequestCommand,
+  ValidateFunction<JsonType>
+  >
 
   protected constructor (version: OCPPVersion) {
     this.version = version
@@ -34,7 +36,6 @@ export abstract class OCPPIncomingRequestService {
       multipleOfPrecision: 2
     })
     ajvFormats(this.ajv)
-    this.jsonValidateFunctions = new Map<IncomingRequestCommand, ValidateFunction<JsonType>>()
     this.incomingRequestHandler = this.incomingRequestHandler.bind(this)
     this.validateIncomingRequestPayload = this.validateIncomingRequestPayload.bind(this)
   }
@@ -71,25 +72,24 @@ export abstract class OCPPIncomingRequestService {
   protected validateIncomingRequestPayload<T extends JsonType>(
     chargingStation: ChargingStation,
     commandName: IncomingRequestCommand,
-    schema: JSONSchemaType<T>,
     payload: T
   ): boolean {
     if (chargingStation.stationInfo?.ocppStrictCompliance === false) {
       return true
     }
-    const validate = this.getJsonIncomingRequestValidateFunction<T>(commandName, schema)
-    if (validate(payload)) {
+    const validate = this.jsonSchemasValidateFunction.get(commandName)
+    if (validate?.(payload) === true) {
       return true
     }
     logger.error(
       `${chargingStation.logPrefix()} ${moduleName}.validateIncomingRequestPayload: Command '${commandName}' incoming request PDU is invalid: %j`,
-      validate.errors
+      validate?.errors
     )
     throw new OCPPError(
-      OCPPServiceUtils.ajvErrorsToErrorType(validate.errors),
+      OCPPServiceUtils.ajvErrorsToErrorType(validate?.errors),
       'Incoming request PDU is invalid',
       commandName,
-      JSON.stringify(validate.errors, undefined, 2)
+      JSON.stringify(validate?.errors, undefined, 2)
     )
   }
 
@@ -101,17 +101,6 @@ export abstract class OCPPIncomingRequestService {
     return OCPPConstants.OCPP_RESPONSE_REJECTED
   }
 
-  private getJsonIncomingRequestValidateFunction<T extends JsonType>(
-    commandName: IncomingRequestCommand,
-    schema: JSONSchemaType<T>
-  ): ValidateFunction<JsonType> {
-    if (!this.jsonValidateFunctions.has(commandName)) {
-      this.jsonValidateFunctions.set(commandName, this.ajv.compile<T>(schema).bind(this))
-    }
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    return this.jsonValidateFunctions.get(commandName)!
-  }
-
   // eslint-disable-next-line @typescript-eslint/no-unused-vars
   public abstract incomingRequestHandler<ReqType extends JsonType, ResType extends JsonType>(
     chargingStation: ChargingStation,
index c20a1d381ece3c210ce52048e56f618594cf81ed..f956d381b30109d14c708b06fae9c7637830d7f5 100644 (file)
@@ -1,4 +1,4 @@
-import _Ajv, { type JSONSchemaType, type ValidateFunction } from 'ajv'
+import _Ajv, { type ValidateFunction } from 'ajv'
 import _ajvFormats from 'ajv-formats'
 
 import { OCPPConstants } from './OCPPConstants.js'
@@ -45,10 +45,9 @@ const defaultRequestParams: RequestParams = {
 export abstract class OCPPRequestService {
   private static instance: OCPPRequestService | null = null
   private readonly version: OCPPVersion
-  private readonly ajv: Ajv
   private readonly ocppResponseService: OCPPResponseService
-  private readonly jsonValidateFunctions: Map<RequestCommand, ValidateFunction<JsonType>>
-  protected abstract jsonSchemas: Map<RequestCommand, JSONSchemaType<JsonType>>
+  protected readonly ajv: Ajv
+  protected abstract jsonSchemasValidateFunction: Map<RequestCommand, ValidateFunction<JsonType>>
 
   protected constructor (version: OCPPVersion, ocppResponseService: OCPPResponseService) {
     this.version = version
@@ -57,7 +56,6 @@ export abstract class OCPPRequestService {
       multipleOfPrecision: 2
     })
     ajvFormats(this.ajv)
-    this.jsonValidateFunctions = new Map<RequestCommand, ValidateFunction<JsonType>>()
     this.ocppResponseService = ocppResponseService
     this.requestHandler = this.requestHandler.bind(this)
     this.sendMessage = this.sendMessage.bind(this)
@@ -160,45 +158,31 @@ export abstract class OCPPRequestService {
     if (chargingStation.stationInfo?.ocppStrictCompliance === false) {
       return true
     }
-    if (!this.jsonSchemas.has(commandName as RequestCommand)) {
+    if (!this.jsonSchemasValidateFunction.has(commandName as RequestCommand)) {
       logger.warn(
         `${chargingStation.logPrefix()} ${moduleName}.validateRequestPayload: No JSON schema found for command '${commandName}' PDU validation`
       )
       return true
     }
-    const validate = this.getJsonRequestValidateFunction<T>(commandName as RequestCommand)
+    const validate = this.jsonSchemasValidateFunction.get(commandName as RequestCommand)
     payload = clone<T>(payload)
     OCPPServiceUtils.convertDateToISOString<T>(payload)
-    if (validate(payload)) {
+    if (validate?.(payload) === true) {
       return true
     }
     logger.error(
       `${chargingStation.logPrefix()} ${moduleName}.validateRequestPayload: Command '${commandName}' request PDU is invalid: %j`,
-      validate.errors
+      validate?.errors
     )
     // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
     throw new OCPPError(
-      OCPPServiceUtils.ajvErrorsToErrorType(validate.errors),
+      OCPPServiceUtils.ajvErrorsToErrorType(validate?.errors),
       'Request PDU is invalid',
       commandName,
-      JSON.stringify(validate.errors, undefined, 2)
+      JSON.stringify(validate?.errors, undefined, 2)
     )
   }
 
-  private getJsonRequestValidateFunction<T extends JsonType>(
-    commandName: RequestCommand
-  ): ValidateFunction<JsonType> {
-    if (!this.jsonValidateFunctions.has(commandName)) {
-      this.jsonValidateFunctions.set(
-        commandName,
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        this.ajv.compile<T>(this.jsonSchemas.get(commandName)!).bind(this)
-      )
-    }
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    return this.jsonValidateFunctions.get(commandName)!
-  }
-
   private validateIncomingRequestResponsePayload<T extends JsonType>(
     chargingStation: ChargingStation,
     commandName: RequestCommand | IncomingRequestCommand,
@@ -208,52 +192,37 @@ export abstract class OCPPRequestService {
       return true
     }
     if (
-      !this.ocppResponseService.jsonIncomingRequestResponseSchemas.has(
+      !this.ocppResponseService.jsonSchemasIncomingRequestResponseValidateFunction.has(
         commandName as IncomingRequestCommand
       )
     ) {
       logger.warn(
-        `${chargingStation.logPrefix()} ${moduleName}.validateIncomingRequestResponsePayload: No JSON schema found for command '${commandName}' PDU validation`
+        `${chargingStation.logPrefix()} ${moduleName}.validateIncomingRequestResponsePayload: No JSON schema validation function found for command '${commandName}' PDU validation`
       )
       return true
     }
-    const validate = this.getJsonRequestResponseValidateFunction<T>(
-      commandName as IncomingRequestCommand
-    )
+    const validate =
+      this.ocppResponseService.jsonSchemasIncomingRequestResponseValidateFunction.get(
+        commandName as IncomingRequestCommand
+      )
     payload = clone<T>(payload)
     OCPPServiceUtils.convertDateToISOString<T>(payload)
-    if (validate(payload)) {
+    if (validate?.(payload) === true) {
       return true
     }
     logger.error(
-      `${chargingStation.logPrefix()} ${moduleName}.validateIncomingRequestResponsePayload: Command '${commandName}' reponse PDU is invalid: %j`,
-      validate.errors
+      `${chargingStation.logPrefix()} ${moduleName}.validateIncomingRequestResponsePayload: Command '${commandName}' response PDU is invalid: %j`,
+      validate?.errors
     )
     // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
     throw new OCPPError(
-      OCPPServiceUtils.ajvErrorsToErrorType(validate.errors),
+      OCPPServiceUtils.ajvErrorsToErrorType(validate?.errors),
       'Response PDU is invalid',
       commandName,
-      JSON.stringify(validate.errors, undefined, 2)
+      JSON.stringify(validate?.errors, undefined, 2)
     )
   }
 
-  private getJsonRequestResponseValidateFunction<T extends JsonType>(
-    commandName: IncomingRequestCommand
-  ): ValidateFunction<JsonType> {
-    if (!this.ocppResponseService.jsonIncomingRequestResponseValidateFunctions.has(commandName)) {
-      this.ocppResponseService.jsonIncomingRequestResponseValidateFunctions.set(
-        commandName,
-        this.ajv
-          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-          .compile<T>(this.ocppResponseService.jsonIncomingRequestResponseSchemas.get(commandName)!)
-          .bind(this)
-      )
-    }
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    return this.ocppResponseService.jsonIncomingRequestResponseValidateFunctions.get(commandName)!
-  }
-
   private async internalSendMessage (
     chargingStation: ChargingStation,
     messageId: string,
index e47450890076f3b200420bd014718e2c7b88f9af..5ee6e2d09058e9199dffc8015ab28298ef434155 100644 (file)
@@ -1,4 +1,4 @@
-import _Ajv, { type JSONSchemaType, type ValidateFunction } from 'ajv'
+import _Ajv, { type ValidateFunction } from 'ajv'
 import _ajvFormats from 'ajv-formats'
 
 import { OCPPServiceUtils } from './OCPPServiceUtils.js'
@@ -20,19 +20,12 @@ const moduleName = 'OCPPResponseService'
 
 export abstract class OCPPResponseService {
   private static instance: OCPPResponseService | null = null
-
-  public jsonIncomingRequestResponseValidateFunctions: Map<
-  IncomingRequestCommand,
-  ValidateFunction<JsonType>
-  >
-
   private readonly version: OCPPVersion
-  private readonly ajv: Ajv
-  private readonly jsonRequestValidateFunctions: Map<RequestCommand, ValidateFunction<JsonType>>
-
-  public abstract jsonIncomingRequestResponseSchemas: Map<
+  protected readonly ajv: Ajv
+  protected abstract jsonSchemasValidateFunction: Map<RequestCommand, ValidateFunction<JsonType>>
+  public abstract jsonSchemasIncomingRequestResponseValidateFunction: Map<
   IncomingRequestCommand,
-  JSONSchemaType<JsonType>
+  ValidateFunction<JsonType>
   >
 
   protected constructor (version: OCPPVersion) {
@@ -42,11 +35,6 @@ export abstract class OCPPResponseService {
       multipleOfPrecision: 2
     })
     ajvFormats(this.ajv)
-    this.jsonRequestValidateFunctions = new Map<RequestCommand, ValidateFunction<JsonType>>()
-    this.jsonIncomingRequestResponseValidateFunctions = new Map<
-    IncomingRequestCommand,
-    ValidateFunction<JsonType>
-    >()
     this.responseHandler = this.responseHandler.bind(this)
     this.validateResponsePayload = this.validateResponsePayload.bind(this)
   }
@@ -61,41 +49,29 @@ export abstract class OCPPResponseService {
   protected validateResponsePayload<T extends JsonType>(
     chargingStation: ChargingStation,
     commandName: RequestCommand,
-    schema: JSONSchemaType<T>,
     payload: T
   ): boolean {
     if (chargingStation.stationInfo?.ocppStrictCompliance === false) {
       return true
     }
-    const validate = this.getJsonRequestValidateFunction<T>(commandName, schema)
-    if (validate(payload)) {
+    const validate = this.jsonSchemasValidateFunction.get(commandName)
+    if (validate?.(payload) === true) {
       return true
     }
     logger.error(
       `${chargingStation.logPrefix()} ${moduleName}.validateResponsePayload: Command '${commandName}' response PDU is invalid: %j`,
-      validate.errors
+      validate?.errors
     )
     throw new OCPPError(
-      OCPPServiceUtils.ajvErrorsToErrorType(validate.errors),
+      OCPPServiceUtils.ajvErrorsToErrorType(validate?.errors),
       'Response PDU is invalid',
       commandName,
-      JSON.stringify(validate.errors, undefined, 2)
+      JSON.stringify(validate?.errors, undefined, 2)
     )
   }
 
   protected emptyResponseHandler = Constants.EMPTY_FUNCTION
 
-  private getJsonRequestValidateFunction<T extends JsonType>(
-    commandName: RequestCommand,
-    schema: JSONSchemaType<T>
-  ): ValidateFunction<JsonType> {
-    if (!this.jsonRequestValidateFunctions.has(commandName)) {
-      this.jsonRequestValidateFunctions.set(commandName, this.ajv.compile<T>(schema).bind(this))
-    }
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    return this.jsonRequestValidateFunctions.get(commandName)!
-  }
-
   public abstract responseHandler<ReqType extends JsonType, ResType extends JsonType>(
     chargingStation: ChargingStation,
     commandName: RequestCommand,