+// Partial Copyright Jerome Benoit. 2021. All Rights Reserved.
+
+import type { JSONSchemaType } from 'ajv';
+
+import OCPPError from '../../../exception/OCPPError';
+import type { JsonObject, JsonType } from '../../../types/JsonType';
+import type { OCPP20IncomingRequestCommand } from '../../../types/ocpp/2.0/Requests';
+import { ErrorType } from '../../../types/ocpp/ErrorType';
+import type { IncomingRequestHandler } from '../../../types/ocpp/Requests';
+import logger from '../../../utils/Logger';
+import type ChargingStation from '../../ChargingStation';
+import OCPPIncomingRequestService from '../OCPPIncomingRequestService';
+import { OCPP20ServiceUtils } from './OCPP20ServiceUtils';
+
+const moduleName = 'OCPP20IncomingRequestService';
+
+export default class OCPP20IncomingRequestService extends OCPPIncomingRequestService {
+ private incomingRequestHandlers: Map<OCPP20IncomingRequestCommand, IncomingRequestHandler>;
+ private jsonSchemas: Map<OCPP20IncomingRequestCommand, JSONSchemaType<JsonObject>>;
+
+ public constructor() {
+ if (new.target?.name === moduleName) {
+ throw new TypeError(`Cannot construct ${new.target?.name} instances directly`);
+ }
+ super();
+ this.incomingRequestHandlers = new Map<OCPP20IncomingRequestCommand, IncomingRequestHandler>();
+ this.jsonSchemas = new Map<OCPP20IncomingRequestCommand, JSONSchemaType<JsonObject>>();
+ this.validatePayload.bind(this);
+ }
+
+ public async incomingRequestHandler(
+ chargingStation: ChargingStation,
+ messageId: string,
+ commandName: OCPP20IncomingRequestCommand,
+ commandPayload: JsonType
+ ): Promise<void> {
+ let response: JsonType;
+ if (
+ chargingStation.getOcppStrictCompliance() === true &&
+ chargingStation.isInPendingState() === true /* &&
+ (commandName === OCPP20IncomingRequestCommand.REMOTE_START_TRANSACTION ||
+ commandName === OCPP20IncomingRequestCommand.REMOTE_STOP_TRANSACTION ) */
+ ) {
+ throw new OCPPError(
+ ErrorType.SECURITY_ERROR,
+ `${commandName} cannot be issued to handle request PDU ${JSON.stringify(
+ commandPayload,
+ null,
+ 2
+ )} while the charging station is in pending state on the central server`,
+ commandName,
+ commandPayload
+ );
+ }
+ if (
+ chargingStation.isRegistered() === true ||
+ (chargingStation.getOcppStrictCompliance() === false &&
+ chargingStation.isInUnknownState() === true)
+ ) {
+ if (
+ this.incomingRequestHandlers.has(commandName) === true &&
+ OCPP20ServiceUtils.isIncomingRequestCommandSupported(chargingStation, commandName) === true
+ ) {
+ try {
+ this.validatePayload(chargingStation, commandName, commandPayload);
+ // Call the method to build the response
+ response = await this.incomingRequestHandlers.get(commandName)(
+ chargingStation,
+ commandPayload
+ );
+ } catch (error) {
+ // Log
+ logger.error(
+ `${chargingStation.logPrefix()} ${moduleName}.incomingRequestHandler: Handle incoming request error:`,
+ error
+ );
+ throw error;
+ }
+ } else {
+ // Throw exception
+ throw new OCPPError(
+ ErrorType.NOT_IMPLEMENTED,
+ `${commandName} is not implemented to handle request PDU ${JSON.stringify(
+ commandPayload,
+ null,
+ 2
+ )}`,
+ commandName,
+ 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.`,
+ commandName,
+ commandPayload
+ );
+ }
+ // Send the built response
+ await chargingStation.ocppRequestService.sendResponse(
+ chargingStation,
+ messageId,
+ response,
+ commandName
+ );
+ }
+
+ private validatePayload(
+ chargingStation: ChargingStation,
+ commandName: OCPP20IncomingRequestCommand,
+ commandPayload: JsonType
+ ): boolean {
+ if (this.jsonSchemas.has(commandName)) {
+ return this.validateIncomingRequestPayload(
+ chargingStation,
+ commandName,
+ this.jsonSchemas.get(commandName),
+ commandPayload
+ );
+ }
+ logger.warn(
+ `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command ${commandName} PDU validation`
+ );
+ return false;
+ }
+}