type OCPPVersion,
} from '../../types/index.js'
import { isAsyncFunction, logger } from '../../utils/index.js'
-import { type Ajv, ajvErrorsToErrorType, createAjv } from './OCPPServiceUtils.js'
-
-const moduleName = 'OCPPIncomingRequestService'
+import { type Ajv, createAjv, validatePayload } from './OCPPServiceUtils.js'
export abstract class OCPPIncomingRequestService extends EventEmitter {
private static readonly instances = new Map<
commandName: IncomingRequestCommand,
payload: T
): boolean {
- if (chargingStation.stationInfo?.ocppStrictCompliance === false) {
- return true
- }
- const validate = this.payloadValidatorFunctions.get(commandName)
- if (validate == null) {
- logger.warn(
- `${chargingStation.logPrefix()} ${moduleName}.validateIncomingRequestPayload: No JSON schema validation function found for command '${commandName}' PDU validation`
- )
- return false
- }
- if (validate(payload)) {
- return true
- }
- logger.error(
- `${chargingStation.logPrefix()} ${moduleName}.validateIncomingRequestPayload: Command '${commandName}' incoming request PDU is invalid: %j`,
- validate.errors
- )
- throw new OCPPError(
- ajvErrorsToErrorType(validate.errors),
- 'Incoming request PDU is invalid',
+ return validatePayload(
+ chargingStation,
commandName,
- JSON.stringify(validate.errors, undefined, 2)
+ payload,
+ this.payloadValidatorFunctions.get(commandName),
+ 'incoming request'
)
}
}
type ResponseType,
} from '../../types/index.js'
import {
- clone,
ensureError,
formatDurationMilliSeconds,
getErrorMessage,
logger,
} from '../../utils/index.js'
import { OCPPConstants } from './OCPPConstants.js'
-import {
- type Ajv,
- ajvErrorsToErrorType,
- convertDateToISOString,
- createAjv,
-} from './OCPPServiceUtils.js'
-
-const moduleName = 'OCPPRequestService'
+import { type Ajv, createAjv, validatePayload } from './OCPPServiceUtils.js'
const defaultRequestParams: RequestParams = {
skipBufferingOnError: false,
commandName: IncomingRequestCommand | RequestCommand,
payload: T
): boolean {
- if (chargingStation.stationInfo?.ocppStrictCompliance === false) {
- return true
- }
- const validate = this.ocppResponseService.incomingRequestResponsePayloadValidateFunctions.get(
- commandName as IncomingRequestCommand
- )
- if (validate == null) {
- logger.warn(
- `${chargingStation.logPrefix()} ${moduleName}.validateIncomingRequestResponsePayload: No JSON schema validation function found for command '${commandName}' PDU validation`
- )
- return false
- }
- payload = clone(payload)
- convertDateToISOString(payload)
- if (validate(payload)) {
- return true
- }
- logger.error(
- `${chargingStation.logPrefix()} ${moduleName}.validateIncomingRequestResponsePayload: Command '${commandName}' incoming request 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(
- ajvErrorsToErrorType(validate.errors),
- 'Incoming request response PDU is invalid',
+ return validatePayload(
+ chargingStation,
commandName,
- JSON.stringify(validate.errors, undefined, 2)
+ payload,
+ this.ocppResponseService.incomingRequestResponsePayloadValidateFunctions.get(
+ commandName as IncomingRequestCommand
+ ),
+ 'incoming request response',
+ true
)
}
commandName: IncomingRequestCommand | RequestCommand,
payload: T
): boolean {
- if (chargingStation.stationInfo?.ocppStrictCompliance === false) {
- return true
- }
- const validate = this.payloadValidatorFunctions.get(commandName as RequestCommand)
- if (validate == null) {
- logger.warn(
- `${chargingStation.logPrefix()} ${moduleName}.validateRequestPayload: No JSON schema validation function found for command '${commandName}' PDU validation`
- )
- return false
- }
- payload = clone(payload)
- convertDateToISOString(payload)
- if (validate(payload)) {
- return true
- }
- logger.error(
- `${chargingStation.logPrefix()} ${moduleName}.validateRequestPayload: Command '${commandName}' request 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(
- ajvErrorsToErrorType(validate.errors),
- 'Request PDU is invalid',
+ return validatePayload(
+ chargingStation,
commandName,
- JSON.stringify(validate.errors, undefined, 2)
+ payload,
+ this.payloadValidatorFunctions.get(commandName as RequestCommand),
+ 'request',
+ true
)
}
type ResponseHandler,
} from '../../types/index.js'
import { Constants, isAsyncFunction, logger } from '../../utils/index.js'
-import { type Ajv, ajvErrorsToErrorType, createAjv } from './OCPPServiceUtils.js'
-
-const moduleName = 'OCPPResponseService'
+import { type Ajv, createAjv, validatePayload } from './OCPPServiceUtils.js'
export abstract class OCPPResponseService {
private static readonly instances = new Map<new () => OCPPResponseService, OCPPResponseService>()
commandName: RequestCommand,
payload: T
): boolean {
- if (chargingStation.stationInfo?.ocppStrictCompliance === false) {
- return true
- }
- const validate = this.payloadValidatorFunctions.get(commandName)
- if (validate == null) {
- logger.warn(
- `${chargingStation.logPrefix()} ${moduleName}.validateResponsePayload: No JSON schema validation function found for command '${commandName}' PDU validation`
- )
- return false
- }
- if (validate(payload)) {
- return true
- }
- logger.error(
- `${chargingStation.logPrefix()} ${moduleName}.validateResponsePayload: Command '${commandName}' response PDU is invalid: %j`,
- validate.errors
- )
- throw new OCPPError(
- ajvErrorsToErrorType(validate.errors),
- 'Response PDU is invalid',
+ return validatePayload(
+ chargingStation,
commandName,
- JSON.stringify(validate.errors, undefined, 2)
+ payload,
+ this.payloadValidatorFunctions.get(commandName),
+ 'response'
)
}
}
} from '../../types/index.js'
import {
ACElectricUtils,
+ clone,
Constants,
convertToFloat,
convertToInt,
return ErrorType.FORMAT_VIOLATION
}
+/**
+ * Validates an OCPP payload against a JSON schema validation function.
+ * Shared implementation used by request, response, and incoming request validation.
+ * @param chargingStation - The charging station instance
+ * @param commandName - OCPP command name to validate against
+ * @param payload - JSON payload to validate
+ * @param validate - Ajv validation function for the command
+ * @param context - Description of the validation context (e.g. 'request', 'response')
+ * @param clonePayload - Whether to clone payload and convert dates before validation
+ * @returns True if payload validation succeeds, false otherwise
+ */
+// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
+export const validatePayload = <T extends JsonType>(
+ chargingStation: ChargingStation,
+ commandName: IncomingRequestCommand | RequestCommand,
+ payload: T,
+ validate: undefined | ValidateFunction<JsonType>,
+ context: string,
+ clonePayload = false
+): boolean => {
+ if (chargingStation.stationInfo?.ocppStrictCompliance === false) {
+ return true
+ }
+ if (validate == null) {
+ logger.warn(
+ `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema validation function found for command '${commandName}' ${context} PDU validation`
+ )
+ return false
+ }
+ let payloadToValidate = payload
+ if (clonePayload) {
+ payloadToValidate = clone(payload)
+ convertDateToISOString(payloadToValidate)
+ }
+ if (validate(payloadToValidate)) {
+ return true
+ }
+ logger.error(
+ `${chargingStation.logPrefix()} ${moduleName}.validatePayload: Command '${commandName}' ${context} PDU is invalid: %j`,
+ validate.errors
+ )
+ throw new OCPPError(
+ ajvErrorsToErrorType(validate.errors),
+ `${context.charAt(0).toUpperCase()}${context.slice(1)} PDU is invalid`,
+ commandName,
+ JSON.stringify(validate.errors, undefined, 2)
+ )
+}
+
/**
* Recursively converts Date values to ISO 8601 strings within a JSON-compatible object.
* @param object - Object whose Date properties will be converted in-place