From ec0eebcce06f18b41e6639b72728110bda55c250 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Tue, 7 Nov 2023 19:48:46 +0100 Subject: [PATCH] perf(simulator): compile payload validation JSON schema only once MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- .../ocpp/OCPPIncomingRequestService.ts | 9 +++-- .../ocpp/OCPPRequestService.ts | 34 +++++++++++++++---- .../ocpp/OCPPResponseService.ts | 23 +++++++++++-- 3 files changed, 56 insertions(+), 10 deletions(-) diff --git a/src/charging-station/ocpp/OCPPIncomingRequestService.ts b/src/charging-station/ocpp/OCPPIncomingRequestService.ts index 85fd88e7..0c5b5c61 100644 --- a/src/charging-station/ocpp/OCPPIncomingRequestService.ts +++ b/src/charging-station/ocpp/OCPPIncomingRequestService.ts @@ -1,6 +1,6 @@ import { AsyncResource } from 'node:async_hooks'; -import Ajv, { type JSONSchemaType } from 'ajv'; +import Ajv, { type JSONSchemaType, type ValidateFunction } from 'ajv'; import ajvFormats from 'ajv-formats'; import { OCPPConstants } from './OCPPConstants'; @@ -23,6 +23,7 @@ export abstract class OCPPIncomingRequestService extends AsyncResource { private static instance: OCPPIncomingRequestService | null = null; private readonly version: OCPPVersion; private readonly ajv: Ajv; + private jsonValidateFunctions: Map>; protected abstract jsonSchemas: Map>; protected constructor(version: OCPPVersion) { @@ -33,6 +34,7 @@ export abstract class OCPPIncomingRequestService extends AsyncResource { multipleOfPrecision: 2, }); ajvFormats(this.ajv); + this.jsonValidateFunctions = new Map>(); this.incomingRequestHandler = this.incomingRequestHandler.bind(this) as < ReqType extends JsonType, // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -91,7 +93,10 @@ export abstract class OCPPIncomingRequestService extends AsyncResource { if (chargingStation.getOcppStrictCompliance() === false) { return true; } - const validate = this.ajv.compile(schema); + if (this.jsonValidateFunctions.has(commandName) === false) { + this.jsonValidateFunctions.set(commandName, this.ajv.compile(schema).bind(this)); + } + const validate = this.jsonValidateFunctions.get(commandName)!; if (validate(payload)) { return true; } diff --git a/src/charging-station/ocpp/OCPPRequestService.ts b/src/charging-station/ocpp/OCPPRequestService.ts index 18aa5ffd..52a8a6e5 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,6 +44,7 @@ export abstract class OCPPRequestService { private readonly version: OCPPVersion; private readonly ajv: Ajv; private readonly ocppResponseService: OCPPResponseService; + private readonly jsonValidateFunctions: Map>; protected abstract jsonSchemas: Map>; protected constructor(version: OCPPVersion, ocppResponseService: OCPPResponseService) { @@ -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 @@ -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)) { @@ -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)) { diff --git a/src/charging-station/ocpp/OCPPResponseService.ts b/src/charging-station/ocpp/OCPPResponseService.ts index 9daa991c..46d12fb0 100644 --- a/src/charging-station/ocpp/OCPPResponseService.ts +++ b/src/charging-station/ocpp/OCPPResponseService.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 { OCPPServiceUtils } from './OCPPServiceUtils'; @@ -17,8 +17,16 @@ const moduleName = 'OCPPResponseService'; export abstract class OCPPResponseService { private static instance: OCPPResponseService | null = null; + + public jsonIncomingRequestResponseValidateFunctions: Map< + IncomingRequestCommand, + ValidateFunction + >; + private readonly version: OCPPVersion; private readonly ajv: Ajv; + private jsonRequestValidateFunctions: Map>; + public abstract jsonIncomingRequestResponseSchemas: Map< IncomingRequestCommand, JSONSchemaType @@ -31,6 +39,11 @@ export abstract class OCPPResponseService { multipleOfPrecision: 2, }); ajvFormats(this.ajv); + this.jsonRequestValidateFunctions = new Map>(); + this.jsonIncomingRequestResponseValidateFunctions = new Map< + IncomingRequestCommand, + ValidateFunction + >(); this.responseHandler = this.responseHandler.bind(this) as < ReqType extends JsonType, ResType extends JsonType, @@ -64,7 +77,13 @@ export abstract class OCPPResponseService { if (chargingStation.getOcppStrictCompliance() === false) { return true; } - const validate = this.ajv.compile(schema); + if (this.jsonRequestValidateFunctions.has(commandName) === false) { + this.jsonRequestValidateFunctions.set( + commandName, + this.ajv.compile(schema).bind(this), + ); + } + const validate = this.jsonRequestValidateFunctions.get(commandName)!; if (validate(payload)) { return true; } -- 2.34.1