-// Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
+// Partial Copyright Jerome Benoit. 2021-2024. All Rights Reserved.
-import type { JSONSchemaType } from 'ajv';
+import type { ValidateFunction } from 'ajv'
-import { OCPP20ServiceUtils } from './OCPP20ServiceUtils';
-import type { ChargingStation } from '../../../charging-station';
-import { OCPPError } from '../../../exception';
+import type { ChargingStation } from '../../../charging-station/index.js'
+import { OCPPError } from '../../../exception/index.js'
import {
ErrorType,
type IncomingRequestHandler,
- type JsonObject,
type JsonType,
type OCPP20ClearCacheRequest,
OCPP20IncomingRequestCommand,
- OCPPVersion,
-} from '../../../types';
-import { logger } from '../../../utils';
-import { OCPPIncomingRequestService } from '../OCPPIncomingRequestService';
+ OCPPVersion
+} from '../../../types/index.js'
+import { isAsyncFunction, logger } from '../../../utils/index.js'
+import { OCPPIncomingRequestService } from '../OCPPIncomingRequestService.js'
+import { OCPP20ServiceUtils } from './OCPP20ServiceUtils.js'
-const moduleName = 'OCPP20IncomingRequestService';
+const moduleName = 'OCPP20IncomingRequestService'
export class OCPP20IncomingRequestService extends OCPPIncomingRequestService {
- protected jsonSchemas: Map<OCPP20IncomingRequestCommand, JSONSchemaType<JsonObject>>;
- private incomingRequestHandlers: Map<OCPP20IncomingRequestCommand, IncomingRequestHandler>;
+ protected payloadValidateFunctions: Map<OCPP20IncomingRequestCommand, ValidateFunction<JsonType>>
- public constructor() {
- // if (new.target?.name === moduleName) {
- // throw new TypeError(`Cannot construct ${new.target?.name} instances directly`);
+ private readonly incomingRequestHandlers: Map<
+ OCPP20IncomingRequestCommand,
+ IncomingRequestHandler
+ >
+
+ public constructor () {
+ // if (new.target.name === moduleName) {
+ // throw new TypeError(`Cannot construct ${new.target.name} instances directly`)
// }
- super(OCPPVersion.VERSION_20);
+ super(OCPPVersion.VERSION_201)
this.incomingRequestHandlers = new Map<OCPP20IncomingRequestCommand, IncomingRequestHandler>([
- [OCPP20IncomingRequestCommand.CLEAR_CACHE, this.handleRequestClearCache.bind(this)],
- ]);
- this.jsonSchemas = new Map<OCPP20IncomingRequestCommand, JSONSchemaType<JsonObject>>([
+ [OCPP20IncomingRequestCommand.CLEAR_CACHE, this.handleRequestClearCache.bind(this)]
+ ])
+ this.payloadValidateFunctions = new Map<
+ OCPP20IncomingRequestCommand,
+ ValidateFunction<JsonType>
+ >([
[
OCPP20IncomingRequestCommand.CLEAR_CACHE,
- OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20ClearCacheRequest>(
- 'assets/json-schemas/ocpp/2.0/ClearCacheRequest.json',
- moduleName,
- 'constructor',
- ),
- ],
- ]);
- this.validatePayload = this.validatePayload.bind(this) as (
- chargingStation: ChargingStation,
- commandName: OCPP20IncomingRequestCommand,
- commandPayload: JsonType,
- ) => boolean;
+ this.ajv
+ .compile(
+ OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20ClearCacheRequest>(
+ 'assets/json-schemas/ocpp/2.0/ClearCacheRequest.json',
+ moduleName,
+ 'constructor'
+ )
+ )
+ .bind(this)
+ ]
+ ])
+ this.validatePayload = this.validatePayload.bind(this)
}
public async incomingRequestHandler<ReqType extends JsonType, ResType extends JsonType>(
chargingStation: ChargingStation,
messageId: string,
commandName: OCPP20IncomingRequestCommand,
- commandPayload: ReqType,
+ commandPayload: ReqType
): Promise<void> {
- let response: ResType;
+ let response: ResType
if (
- chargingStation.getOcppStrictCompliance() === true &&
- chargingStation.inPendingState() === true &&
+ chargingStation.stationInfo?.ocppStrictCompliance === true &&
+ chargingStation.inPendingState() &&
(commandName === OCPP20IncomingRequestCommand.REQUEST_START_TRANSACTION ||
commandName === OCPP20IncomingRequestCommand.REQUEST_STOP_TRANSACTION)
) {
ErrorType.SECURITY_ERROR,
`${commandName} cannot be issued to handle request PDU ${JSON.stringify(
commandPayload,
- null,
- 2,
+ undefined,
+ 2
)} while the charging station is in pending state on the central server`,
commandName,
- commandPayload,
- );
+ commandPayload
+ )
}
if (
- chargingStation.isRegistered() === true ||
- (chargingStation.getOcppStrictCompliance() === false &&
- chargingStation.inUnknownState() === true)
+ chargingStation.isRegistered() ||
+ (chargingStation.stationInfo?.ocppStrictCompliance === false &&
+ chargingStation.inUnknownState())
) {
if (
- this.incomingRequestHandlers.has(commandName) === true &&
- OCPP20ServiceUtils.isIncomingRequestCommandSupported(chargingStation, commandName) === true
+ this.incomingRequestHandlers.has(commandName) &&
+ OCPP20ServiceUtils.isIncomingRequestCommandSupported(chargingStation, commandName)
) {
try {
- this.validatePayload(chargingStation, commandName, commandPayload);
+ this.validatePayload(chargingStation, commandName, commandPayload)
// Call the method to build the response
- response = (await this.incomingRequestHandlers.get(commandName)!(
- chargingStation,
- commandPayload,
- )) as ResType;
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ const incomingRequestHandler = this.incomingRequestHandlers.get(commandName)!
+ if (isAsyncFunction(incomingRequestHandler)) {
+ response = (await incomingRequestHandler(chargingStation, commandPayload)) as ResType
+ } else {
+ response = incomingRequestHandler(chargingStation, commandPayload) as ResType
+ }
} catch (error) {
// Log
logger.error(
`${chargingStation.logPrefix()} ${moduleName}.incomingRequestHandler: Handle incoming request error:`,
- error,
- );
- throw error;
+ error
+ )
+ throw error
}
} else {
// Throw exception
throw new OCPPError(
ErrorType.NOT_IMPLEMENTED,
- `${commandName} is not implemented to handle request PDU ${JSON.stringify(
+ `'${commandName}' is not implemented to handle request PDU ${JSON.stringify(
commandPayload,
- null,
- 2,
+ undefined,
+ 2
)}`,
commandName,
- commandPayload,
- );
+ commandPayload
+ )
}
} else {
throw new OCPPError(
ErrorType.SECURITY_ERROR,
`${commandName} cannot be issued to handle request PDU ${JSON.stringify(
commandPayload,
- null,
- 2,
- )} while the charging station is not registered on the central server.`,
+ undefined,
+ 2
+ )} while the charging station is not registered on the central server`,
commandName,
- commandPayload,
- );
+ commandPayload
+ )
}
// Send the built response
await chargingStation.ocppRequestService.sendResponse(
chargingStation,
messageId,
response,
- commandName,
- );
+ commandName
+ )
+ // Emit command name event to allow delayed handling
+ this.emit(commandName, chargingStation, commandPayload, response)
}
- private validatePayload(
+ private validatePayload (
chargingStation: ChargingStation,
commandName: OCPP20IncomingRequestCommand,
- commandPayload: JsonType,
+ commandPayload: JsonType
): boolean {
- if (this.jsonSchemas.has(commandName) === true) {
- return this.validateIncomingRequestPayload(
- chargingStation,
- commandName,
- this.jsonSchemas.get(commandName)!,
- commandPayload,
- );
+ if (this.payloadValidateFunctions.has(commandName)) {
+ return this.validateIncomingRequestPayload(chargingStation, commandName, commandPayload)
}
logger.warn(
- `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command '${commandName}' PDU validation`,
- );
- return false;
+ `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema validation function found for command '${commandName}' PDU validation`
+ )
+ return false
}
}