X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Fcharging-station%2Focpp%2FOCPPRequestService.ts;h=3ac768c2052c9468fae03c2a30a4cb8fea0e99b8;hb=8f46463be058ed68cc4cc962c51722f7e3b55c54;hp=1d698bd894fcaa6dd2d6194f77f0e036b8a19856;hpb=68220b423c52da387fdf41967dd8c738da0ff52e;p=e-mobility-charging-stations-simulator.git diff --git a/src/charging-station/ocpp/OCPPRequestService.ts b/src/charging-station/ocpp/OCPPRequestService.ts index 1d698bd8..3ac768c2 100644 --- a/src/charging-station/ocpp/OCPPRequestService.ts +++ b/src/charging-station/ocpp/OCPPRequestService.ts @@ -1,9 +1,6 @@ -import _Ajv, { type JSONSchemaType, type ValidateFunction } from 'ajv' +import _Ajv, { type ValidateFunction } from 'ajv' import _ajvFormats from 'ajv-formats' -import { OCPPConstants } from './OCPPConstants.js' -import type { OCPPResponseService } from './OCPPResponseService.js' -import { OCPPServiceUtils } from './OCPPServiceUtils.js' import type { ChargingStation } from '../../charging-station/index.js' import { OCPPError } from '../../exception/index.js' import { PerformanceStatistics } from '../../performance/index.js' @@ -24,11 +21,14 @@ import { type ResponseType } from '../../types/index.js' import { - cloneObject, + clone, formatDurationMilliSeconds, handleSendMessageError, logger } from '../../utils/index.js' +import { OCPPConstants } from './OCPPConstants.js' +import type { OCPPResponseService } from './OCPPResponseService.js' +import { OCPPServiceUtils } from './OCPPServiceUtils.js' type Ajv = _Ajv.default // eslint-disable-next-line @typescript-eslint/no-redeclare const Ajv = _Ajv.default @@ -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> - protected abstract jsonSchemas: Map> + protected readonly ajv: Ajv + protected abstract payloadValidateFunctions: Map> protected constructor (version: OCPPVersion, ocppResponseService: OCPPResponseService) { this.version = version @@ -57,64 +56,16 @@ 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 - ReqType extends JsonType, - ResType extends JsonType, - >( - chargingStation: ChargingStation, - commandName: RequestCommand, - commandParams?: JsonType, - params?: RequestParams - ) => Promise - this.sendMessage = this.sendMessage.bind(this) as ( - chargingStation: ChargingStation, - messageId: string, - messagePayload: JsonType, - commandName: RequestCommand, - params?: RequestParams - ) => Promise - this.sendResponse = this.sendResponse.bind(this) as ( - chargingStation: ChargingStation, - messageId: string, - messagePayload: JsonType, - commandName: IncomingRequestCommand - ) => Promise - this.sendError = this.sendError.bind(this) as ( - chargingStation: ChargingStation, - messageId: string, - ocppError: OCPPError, - commandName: RequestCommand | IncomingRequestCommand - ) => Promise - this.internalSendMessage = this.internalSendMessage.bind(this) as ( - chargingStation: ChargingStation, - messageId: string, - messagePayload: JsonType | OCPPError, - messageType: MessageType, - commandName: RequestCommand | IncomingRequestCommand, - params?: RequestParams - ) => Promise - this.buildMessageToSend = this.buildMessageToSend.bind(this) as ( - chargingStation: ChargingStation, - messageId: string, - messagePayload: JsonType | OCPPError, - messageType: MessageType, - commandName: RequestCommand | IncomingRequestCommand - ) => string - this.validateRequestPayload = this.validateRequestPayload.bind(this) as ( - chargingStation: ChargingStation, - commandName: RequestCommand | IncomingRequestCommand, - payload: T - ) => boolean - this.validateIncomingRequestResponsePayload = this.validateIncomingRequestResponsePayload.bind( - this - ) as ( - chargingStation: ChargingStation, - commandName: RequestCommand | IncomingRequestCommand, - payload: T - ) => boolean + this.requestHandler = this.requestHandler.bind(this) + this.sendMessage = this.sendMessage.bind(this) + this.sendResponse = this.sendResponse.bind(this) + this.sendError = this.sendError.bind(this) + this.internalSendMessage = this.internalSendMessage.bind(this) + this.buildMessageToSend = this.buildMessageToSend.bind(this) + this.validateRequestPayload = this.validateRequestPayload.bind(this) + this.validateIncomingRequestResponsePayload = + this.validateIncomingRequestResponsePayload.bind(this) } public static getInstance( @@ -207,45 +158,31 @@ export abstract class OCPPRequestService { if (chargingStation.stationInfo?.ocppStrictCompliance === false) { return true } - if (!this.jsonSchemas.has(commandName as RequestCommand)) { + if (!this.payloadValidateFunctions.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(commandName as RequestCommand) - payload = cloneObject(payload) + const validate = this.payloadValidateFunctions.get(commandName as RequestCommand) + payload = clone(payload) OCPPServiceUtils.convertDateToISOString(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( - commandName: RequestCommand - ): ValidateFunction { - if (!this.jsonValidateFunctions.has(commandName)) { - this.jsonValidateFunctions.set( - commandName, - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - this.ajv.compile(this.jsonSchemas.get(commandName)!).bind(this) - ) - } - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - return this.jsonValidateFunctions.get(commandName)! - } - private validateIncomingRequestResponsePayload( chargingStation: ChargingStation, commandName: RequestCommand | IncomingRequestCommand, @@ -255,52 +192,36 @@ export abstract class OCPPRequestService { return true } if ( - !this.ocppResponseService.jsonIncomingRequestResponseSchemas.has( + !this.ocppResponseService.incomingRequestResponsePayloadValidateFunctions.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( + const validate = this.ocppResponseService.incomingRequestResponsePayloadValidateFunctions.get( commandName as IncomingRequestCommand ) - payload = cloneObject(payload) + payload = clone(payload) OCPPServiceUtils.convertDateToISOString(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( - commandName: IncomingRequestCommand - ): ValidateFunction { - if (!this.ocppResponseService.jsonIncomingRequestResponseValidateFunctions.has(commandName)) { - this.ocppResponseService.jsonIncomingRequestResponseValidateFunctions.set( - commandName, - this.ajv - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - .compile(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, @@ -324,7 +245,7 @@ export abstract class OCPPRequestService { // eslint-disable-next-line @typescript-eslint/no-this-alias const self = this // Send a message through wsConnection - return await new Promise((resolve, reject) => { + return await new Promise((resolve, reject: (reason?: unknown) => void) => { /** * Function that will receive the request's response * @@ -382,11 +303,11 @@ export abstract class OCPPRequestService { } const handleSendError = (ocppError: OCPPError): void => { - if (params?.skipBufferingOnError === false) { + if (params.skipBufferingOnError === false) { // Buffer chargingStation.bufferMessage(messageToSend) if (messageType === MessageType.CALL_MESSAGE) { - this.cacheRequestPromise( + this.setCachedRequest( chargingStation, messageId, messagePayload as JsonType, @@ -396,7 +317,7 @@ export abstract class OCPPRequestService { ) } } else if ( - params?.skipBufferingOnError === true && + params.skipBufferingOnError === true && messageType === MessageType.CALL_MESSAGE ) { // Remove request from the cache @@ -425,7 +346,7 @@ export abstract class OCPPRequestService { `Timeout ${formatDurationMilliSeconds( OCPPConstants.OCPP_WEBSOCKET_TIMEOUT )} reached for ${ - params?.skipBufferingOnError === false ? '' : 'non ' + params.skipBufferingOnError === false ? '' : 'non ' }buffered message id '${messageId}' with content '${messageToSend}'`, commandName, (messagePayload as OCPPError).details @@ -442,7 +363,7 @@ export abstract class OCPPRequestService { )} payload: ${messageToSend}` ) if (messageType === MessageType.CALL_MESSAGE) { - this.cacheRequestPromise( + this.setCachedRequest( chargingStation, messageId, messagePayload as JsonType, @@ -459,7 +380,7 @@ export abstract class OCPPRequestService { new OCPPError( ErrorType.GENERIC_ERROR, `WebSocket errored for ${ - params?.skipBufferingOnError === false ? '' : 'non ' + params.skipBufferingOnError === false ? '' : 'non ' }buffered message id '${messageId}' with content '${messageToSend}'`, commandName, { name: error.name, message: error.message, stack: error.stack } @@ -472,7 +393,7 @@ export abstract class OCPPRequestService { new OCPPError( ErrorType.GENERIC_ERROR, `WebSocket closed for ${ - params?.skipBufferingOnError === false ? '' : 'non ' + params.skipBufferingOnError === false ? '' : 'non ' }buffered message id '${messageId}' with content '${messageToSend}'`, commandName, (messagePayload as OCPPError).details @@ -505,9 +426,9 @@ export abstract class OCPPRequestService { messageToSend = JSON.stringify([ messageType, messageId, - commandName, - messagePayload - ] as OutgoingRequest) + commandName as RequestCommand, + messagePayload as JsonType + ] satisfies OutgoingRequest) break // Response case MessageType.CALL_RESULT_MESSAGE: @@ -517,7 +438,11 @@ export abstract class OCPPRequestService { commandName, messagePayload as JsonType ) - messageToSend = JSON.stringify([messageType, messageId, messagePayload] as Response) + messageToSend = JSON.stringify([ + messageType, + messageId, + messagePayload as JsonType + ] satisfies Response) break // Error Message case MessageType.CALL_ERROR_MESSAGE: @@ -528,15 +453,15 @@ export abstract class OCPPRequestService { (messagePayload as OCPPError).code, (messagePayload as OCPPError).message, (messagePayload as OCPPError).details ?? { - command: (messagePayload as OCPPError).command ?? commandName + command: (messagePayload as OCPPError).command } - ] as ErrorResponse) + ] satisfies ErrorResponse) break } return messageToSend } - private cacheRequestPromise ( + private setCachedRequest ( chargingStation: ChargingStation, messageId: string, messagePayload: JsonType, @@ -556,8 +481,7 @@ export abstract class OCPPRequestService { public abstract requestHandler( chargingStation: ChargingStation, commandName: RequestCommand, - // FIXME: should be ReqType - commandParams?: JsonType, + commandParams?: ReqType, params?: RequestParams ): Promise }