refactor: remove payloadSchemaValidation from template in favor of ocppStrictCompliance
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / OCPPResponseService.ts
1 import Ajv, { type JSONSchemaType } from 'ajv';
2 import ajvFormats from 'ajv-formats';
3
4 import { OCPPServiceUtils } from './OCPPServiceUtils';
5 import type { ChargingStation } from '../../charging-station';
6 import { OCPPError } from '../../exception';
7 import type {
8 IncomingRequestCommand,
9 JsonObject,
10 JsonType,
11 OCPPVersion,
12 RequestCommand,
13 } from '../../types';
14 import { logger } from '../../utils';
15
16 const moduleName = 'OCPPResponseService';
17
18 export abstract class OCPPResponseService {
19 private static instance: OCPPResponseService | null = null;
20 private readonly version: OCPPVersion;
21 private readonly ajv: Ajv;
22 public abstract jsonIncomingRequestResponseSchemas: Map<
23 IncomingRequestCommand,
24 JSONSchemaType<JsonObject>
25 >;
26
27 protected constructor(version: OCPPVersion) {
28 this.version = version;
29 this.ajv = new Ajv({
30 keywords: ['javaType'],
31 multipleOfPrecision: 2,
32 });
33 ajvFormats(this.ajv);
34 this.responseHandler = this.responseHandler.bind(this) as (
35 chargingStation: ChargingStation,
36 commandName: RequestCommand,
37 payload: JsonType,
38 requestPayload: JsonType
39 ) => Promise<void>;
40 this.validateResponsePayload = this.validateResponsePayload.bind(this) as <T extends JsonType>(
41 chargingStation: ChargingStation,
42 commandName: RequestCommand,
43 schema: JSONSchemaType<T>,
44 payload: T
45 ) => boolean;
46 }
47
48 public static getInstance<T extends OCPPResponseService>(this: new () => T): T {
49 if (OCPPResponseService.instance === null) {
50 OCPPResponseService.instance = new this();
51 }
52 return OCPPResponseService.instance as T;
53 }
54
55 protected validateResponsePayload<T extends JsonType>(
56 chargingStation: ChargingStation,
57 commandName: RequestCommand,
58 schema: JSONSchemaType<T>,
59 payload: T
60 ): boolean {
61 if (chargingStation.getOcppStrictCompliance() === false) {
62 return true;
63 }
64 const validate = this.ajv.compile(schema);
65 if (validate(payload)) {
66 return true;
67 }
68 logger.error(
69 `${chargingStation.logPrefix()} ${moduleName}.validateResponsePayload: Command '${commandName}' response PDU is invalid: %j`,
70 validate.errors
71 );
72 throw new OCPPError(
73 OCPPServiceUtils.ajvErrorsToErrorType(validate.errors),
74 'Response PDU is invalid',
75 commandName,
76 JSON.stringify(validate.errors, null, 2)
77 );
78 }
79
80 protected emptyResponseHandler() {
81 /* This is intentional */
82 }
83
84 public abstract responseHandler(
85 chargingStation: ChargingStation,
86 commandName: RequestCommand,
87 payload: JsonType,
88 requestPayload: JsonType
89 ): Promise<void>;
90 }