-import _Ajv, { type JSONSchemaType, type ValidateFunction } from 'ajv'
+import _Ajv, { type ValidateFunction } from 'ajv'
import _ajvFormats from 'ajv-formats'
import { OCPPConstants } from './OCPPConstants.js'
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 payloadValidateFunctions: Map<RequestCommand, ValidateFunction<JsonType>>
protected constructor (version: OCPPVersion, ocppResponseService: OCPPResponseService) {
this.version = version
multipleOfPrecision: 2
})
ajvFormats(this.ajv)
- this.jsonValidateFunctions = new Map<RequestCommand, ValidateFunction<JsonType>>()
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<ResType>
- this.sendMessage = this.sendMessage.bind(this) as (
- chargingStation: ChargingStation,
- messageId: string,
- messagePayload: JsonType,
- commandName: RequestCommand,
- params?: RequestParams
- ) => Promise<ResponseType>
- this.sendResponse = this.sendResponse.bind(this) as (
- chargingStation: ChargingStation,
- messageId: string,
- messagePayload: JsonType,
- commandName: IncomingRequestCommand
- ) => Promise<ResponseType>
- this.sendError = this.sendError.bind(this) as (
- chargingStation: ChargingStation,
- messageId: string,
- ocppError: OCPPError,
- commandName: RequestCommand | IncomingRequestCommand
- ) => Promise<ResponseType>
- this.internalSendMessage = this.internalSendMessage.bind(this) as (
- chargingStation: ChargingStation,
- messageId: string,
- messagePayload: JsonType | OCPPError,
- messageType: MessageType,
- commandName: RequestCommand | IncomingRequestCommand,
- params?: RequestParams
- ) => Promise<ResponseType>
- 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 <T extends JsonType>(
- chargingStation: ChargingStation,
- commandName: RequestCommand | IncomingRequestCommand,
- payload: T
- ) => boolean
- this.validateIncomingRequestResponsePayload = this.validateIncomingRequestResponsePayload.bind(
- this
- ) as <T extends JsonType>(
- 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<T extends 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<T>(commandName as RequestCommand)
+ const validate = this.payloadValidateFunctions.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,
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<T>(
+ const validate = this.ocppResponseService.incomingRequestResponsePayloadValidateFunctions.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,
messageToSend = JSON.stringify([
messageType,
messageId,
- commandName,
- messagePayload
- ] as OutgoingRequest)
+ commandName as RequestCommand,
+ messagePayload as JsonType
+ ] satisfies OutgoingRequest)
break
// Response
case MessageType.CALL_RESULT_MESSAGE:
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:
(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