-import Ajv, { type JSONSchemaType } from 'ajv';
+import Ajv, { type JSONSchemaType, type ValidateFunction } from 'ajv';
import ajvFormats from 'ajv-formats';
import { OCPPConstants } from './OCPPConstants';
private readonly version: OCPPVersion;
private readonly ajv: Ajv;
private readonly ocppResponseService: OCPPResponseService;
- protected abstract jsonSchemas: Map<RequestCommand, JSONSchemaType<JsonObject>>;
+ private readonly jsonValidateFunctions: Map<RequestCommand, ValidateFunction<JsonType>>;
+ protected abstract jsonSchemas: Map<RequestCommand, JSONSchemaType<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
responseCallback: ResponseCallback,
errorCallback: ErrorCallback,
) => string;
- this.validateRequestPayload = this.validateRequestPayload.bind(this) as <T extends JsonObject>(
+ 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 JsonObject>(
+ ) as <T extends JsonType>(
chargingStation: ChargingStation,
commandName: RequestCommand | IncomingRequestCommand,
payload: T,
}
}
- private validateRequestPayload<T extends JsonObject>(
+ private validateRequestPayload<T extends JsonType>(
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) {
);
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<T>(this.jsonSchemas.get(commandName as RequestCommand)!).bind(this),
+ );
+ }
+ const validate = this.jsonValidateFunctions.get(commandName as RequestCommand)!;
payload = cloneObject<T>(payload);
OCPPServiceUtils.convertDateToISOString<T>(payload);
if (validate(payload)) {
);
// 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<T extends JsonObject>(
+ private validateIncomingRequestResponsePayload<T extends JsonType>(
chargingStation: ChargingStation,
commandName: RequestCommand | IncomingRequestCommand,
payload: T,
): boolean {
- if (chargingStation.getOcppStrictCompliance() === false) {
+ if (chargingStation.stationInfo?.ocppStrictCompliance === false) {
return true;
}
if (
);
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<T>(
+ this.ocppResponseService.jsonIncomingRequestResponseSchemas.get(
+ commandName as IncomingRequestCommand,
+ )!,
+ )
+ .bind(this),
+ );
+ }
+ const validate = this.ocppResponseService.jsonIncomingRequestResponseValidateFunctions.get(
+ commandName as IncomingRequestCommand,
+ )!;
payload = cloneObject<T>(payload);
OCPPServiceUtils.convertDateToISOString<T>(payload);
if (validate(payload)) {
);
// 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),
);
}
if (
(chargingStation.inUnknownState() === true &&
commandName === RequestCommand.BOOT_NOTIFICATION) ||
- (chargingStation.getOcppStrictCompliance() === false &&
+ (chargingStation.stationInfo?.ocppStrictCompliance === false &&
chargingStation.inUnknownState() === true) ||
chargingStation.inAcceptedState() === true ||
(chargingStation.inPendingState() === true &&
* @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,
* @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,
reject(error);
};
- if (chargingStation.getEnableStatistics() === true) {
+ if (chargingStation.stationInfo?.enableStatistics === true) {
chargingStation.performanceStatistics?.addRequestStatistic(commandName, messageType);
}
const messageToSend = this.buildMessageToSend(
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) {
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) {
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);
// 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,
this.validateIncomingRequestResponsePayload(
chargingStation,
commandName,
- messagePayload as JsonObject,
+ messagePayload as JsonType,
);
messageToSend = JSON.stringify([messageType, messageId, messagePayload] as Response);
break;