X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fcharging-station%2Focpp%2FOCPPRequestService.ts;h=98c3081155bd2f350fe3a686c7909cd524166b52;hb=1a6188b2fcd2bf644e6fea0c697a095228c1aed0;hp=4e094a21bcf58db12067cff530563ac6ec05d12f;hpb=e1d9a0f4d6ff1a90048e9a694fd12b7031cc6961;p=e-mobility-charging-stations-simulator.git diff --git a/src/charging-station/ocpp/OCPPRequestService.ts b/src/charging-station/ocpp/OCPPRequestService.ts index 4e094a21..98c30811 100644 --- a/src/charging-station/ocpp/OCPPRequestService.ts +++ b/src/charging-station/ocpp/OCPPRequestService.ts @@ -1,4 +1,4 @@ -import Ajv, { type JSONSchemaType } from 'ajv'; +import Ajv, { type JSONSchemaType, type ValidateFunction } from 'ajv'; import ajvFormats from 'ajv-formats'; import { OCPPConstants } from './OCPPConstants'; @@ -44,7 +44,8 @@ export abstract class OCPPRequestService { private readonly version: OCPPVersion; private readonly ajv: Ajv; private readonly ocppResponseService: OCPPResponseService; - protected abstract jsonSchemas: Map>; + private readonly jsonValidateFunctions: Map>; + protected abstract jsonSchemas: Map>; protected constructor(version: OCPPVersion, ocppResponseService: OCPPResponseService) { this.version = version; @@ -53,6 +54,7 @@ export abstract class OCPPRequestService { multipleOfPrecision: 2, }); ajvFormats(this.ajv); + this.jsonValidateFunctions = new Map>(); this.ocppResponseService = ocppResponseService; this.requestHandler = this.requestHandler.bind(this) as < // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -100,14 +102,14 @@ export abstract class OCPPRequestService { responseCallback: ResponseCallback, errorCallback: ErrorCallback, ) => string; - this.validateRequestPayload = this.validateRequestPayload.bind(this) as ( + this.validateRequestPayload = this.validateRequestPayload.bind(this) as ( chargingStation: ChargingStation, commandName: RequestCommand | IncomingRequestCommand, payload: T, ) => boolean; this.validateIncomingRequestResponsePayload = this.validateIncomingRequestResponsePayload.bind( this, - ) as ( + ) as ( chargingStation: ChargingStation, commandName: RequestCommand | IncomingRequestCommand, payload: T, @@ -173,7 +175,7 @@ export abstract class OCPPRequestService { messageId: string, messagePayload: JsonType, commandName: RequestCommand, - params: RequestParams = defaultRequestParams, + params?: RequestParams, ): Promise { params = { ...defaultRequestParams, @@ -196,12 +198,12 @@ export abstract class OCPPRequestService { } } - private validateRequestPayload( + private validateRequestPayload( chargingStation: ChargingStation, commandName: RequestCommand | IncomingRequestCommand, payload: T, ): boolean { - if (chargingStation.getOcppStrictCompliance() === false) { + if (chargingStation.stationInfo?.ocppStrictCompliance === false) { return true; } if (this.jsonSchemas.has(commandName as RequestCommand) === false) { @@ -210,7 +212,13 @@ export abstract class OCPPRequestService { ); return true; } - const validate = this.ajv.compile(this.jsonSchemas.get(commandName as RequestCommand)!); + if (this.jsonValidateFunctions.has(commandName as RequestCommand) === false) { + this.jsonValidateFunctions.set( + commandName as RequestCommand, + this.ajv.compile(this.jsonSchemas.get(commandName as RequestCommand)!).bind(this), + ); + } + const validate = this.jsonValidateFunctions.get(commandName as RequestCommand)!; payload = cloneObject(payload); OCPPServiceUtils.convertDateToISOString(payload); if (validate(payload)) { @@ -222,19 +230,19 @@ export abstract class OCPPRequestService { ); // 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, null, 2), + JSON.stringify(validate.errors, undefined, 2), ); } - private validateIncomingRequestResponsePayload( + private validateIncomingRequestResponsePayload( chargingStation: ChargingStation, commandName: RequestCommand | IncomingRequestCommand, payload: T, ): boolean { - if (chargingStation.getOcppStrictCompliance() === false) { + if (chargingStation.stationInfo?.ocppStrictCompliance === false) { return true; } if ( @@ -247,11 +255,25 @@ export abstract class OCPPRequestService { ); return true; } - const validate = this.ajv.compile( - this.ocppResponseService.jsonIncomingRequestResponseSchemas.get( + if ( + this.ocppResponseService.jsonIncomingRequestResponseValidateFunctions.has( commandName as IncomingRequestCommand, - )!, - ); + ) === false + ) { + this.ocppResponseService.jsonIncomingRequestResponseValidateFunctions.set( + commandName as IncomingRequestCommand, + this.ajv + .compile( + this.ocppResponseService.jsonIncomingRequestResponseSchemas.get( + commandName as IncomingRequestCommand, + )!, + ) + .bind(this), + ); + } + const validate = this.ocppResponseService.jsonIncomingRequestResponseValidateFunctions.get( + commandName as IncomingRequestCommand, + )!; payload = cloneObject(payload); OCPPServiceUtils.convertDateToISOString(payload); if (validate(payload)) { @@ -263,10 +285,10 @@ export abstract class OCPPRequestService { ); // 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, null, 2), + JSON.stringify(validate.errors, undefined, 2), ); } @@ -276,7 +298,7 @@ export abstract class OCPPRequestService { messagePayload: JsonType | OCPPError, messageType: MessageType, commandName: RequestCommand | IncomingRequestCommand, - params: RequestParams = defaultRequestParams, + params?: RequestParams, ): Promise { params = { ...defaultRequestParams, @@ -285,7 +307,7 @@ export abstract class OCPPRequestService { if ( (chargingStation.inUnknownState() === true && commandName === RequestCommand.BOOT_NOTIFICATION) || - (chargingStation.getOcppStrictCompliance() === false && + (chargingStation.stationInfo?.ocppStrictCompliance === false && chargingStation.inUnknownState() === true) || chargingStation.inAcceptedState() === true || (chargingStation.inPendingState() === true && @@ -295,7 +317,7 @@ export abstract class OCPPRequestService { const self = this; // Send a message through wsConnection return promiseWithTimeout( - new Promise((resolve, reject) => { + new Promise((resolve, reject) => { /** * Function that will receive the request's response * @@ -303,7 +325,7 @@ export abstract class OCPPRequestService { * @param requestPayload - */ const responseCallback = (payload: JsonType, requestPayload: JsonType): void => { - if (chargingStation.getEnableStatistics() === true) { + if (chargingStation.stationInfo?.enableStatistics === true) { chargingStation.performanceStatistics?.addRequestStatistic( commandName, MessageType.CALL_RESULT_MESSAGE, @@ -335,7 +357,10 @@ export abstract class OCPPRequestService { * @param requestStatistic - */ const errorCallback = (error: OCPPError, requestStatistic = true): void => { - if (requestStatistic === true && chargingStation.getEnableStatistics() === true) { + if ( + requestStatistic === true && + chargingStation.stationInfo?.enableStatistics === true + ) { chargingStation.performanceStatistics?.addRequestStatistic( commandName, MessageType.CALL_ERROR_MESSAGE, @@ -352,7 +377,7 @@ export abstract class OCPPRequestService { reject(error); }; - if (chargingStation.getEnableStatistics() === true) { + if (chargingStation.stationInfo?.enableStatistics === true) { chargingStation.performanceStatistics?.addRequestStatistic(commandName, messageType); } const messageToSend = this.buildMessageToSend( @@ -388,7 +413,7 @@ export abstract class OCPPRequestService { PerformanceStatistics.endMeasure(commandName, beginId); } const wsClosedOrErrored = !wsOpened || sendError === true; - if (wsClosedOrErrored && params.skipBufferingOnError === false) { + if (wsClosedOrErrored && params?.skipBufferingOnError === false) { // Buffer chargingStation.bufferMessage(messageToSend); // Reject and keep request in the cache @@ -397,7 +422,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 ?? Constants.EMPTY_FREEZED_OBJECT, + (messagePayload as JsonObject)?.details ?? Constants.EMPTY_FROZEN_OBJECT, ), ); } else if (wsClosedOrErrored) { @@ -405,7 +430,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 ?? Constants.EMPTY_FREEZED_OBJECT, + (messagePayload as JsonObject)?.details ?? Constants.EMPTY_FROZEN_OBJECT, ); // Reject response if (messageType !== MessageType.CALL_MESSAGE) { @@ -424,7 +449,7 @@ export abstract class OCPPRequestService { ErrorType.GENERIC_ERROR, `Timeout for message id '${messageId}'`, commandName, - (messagePayload as JsonObject)?.details ?? Constants.EMPTY_FREEZED_OBJECT, + (messagePayload as JsonObject)?.details ?? Constants.EMPTY_FROZEN_OBJECT, ), () => { messageType === MessageType.CALL_MESSAGE && chargingStation.requests.delete(messageId); @@ -453,7 +478,7 @@ export abstract class OCPPRequestService { // Request case MessageType.CALL_MESSAGE: // Build request - this.validateRequestPayload(chargingStation, commandName, messagePayload as JsonObject); + this.validateRequestPayload(chargingStation, commandName, messagePayload as JsonType); chargingStation.requests.set(messageId, [ responseCallback, errorCallback, @@ -473,7 +498,7 @@ export abstract class OCPPRequestService { this.validateIncomingRequestResponsePayload( chargingStation, commandName, - messagePayload as JsonObject, + messagePayload as JsonType, ); messageToSend = JSON.stringify([messageType, messageId, messagePayload] as Response); break;