9daa991c952c30ff184748099dfbe158544ed8c1
[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 ReqType extends JsonType,
36 ResType extends JsonType,
37 >(
38 chargingStation: ChargingStation,
39 commandName: RequestCommand,
40 payload: ResType,
41 requestPayload: ReqType,
42 ) => Promise<void>;
43 this.validateResponsePayload = this.validateResponsePayload.bind(this) as <T extends JsonType>(
44 chargingStation: ChargingStation,
45 commandName: RequestCommand,
46 schema: JSONSchemaType<T>,
47 payload: T,
48 ) => boolean;
49 }
50
51 public static getInstance<T extends OCPPResponseService>(this: new () => T): T {
52 if (OCPPResponseService.instance === null) {
53 OCPPResponseService.instance = new this();
54 }
55 return OCPPResponseService.instance as T;
56 }
57
58 protected validateResponsePayload<T extends JsonType>(
59 chargingStation: ChargingStation,
60 commandName: RequestCommand,
61 schema: JSONSchemaType<T>,
62 payload: T,
63 ): boolean {
64 if (chargingStation.getOcppStrictCompliance() === false) {
65 return true;
66 }
67 const validate = this.ajv.compile(schema);
68 if (validate(payload)) {
69 return true;
70 }
71 logger.error(
72 `${chargingStation.logPrefix()} ${moduleName}.validateResponsePayload: Command '${commandName}' response PDU is invalid: %j`,
73 validate.errors,
74 );
75 throw new OCPPError(
76 OCPPServiceUtils.ajvErrorsToErrorType(validate.errors!),
77 'Response PDU is invalid',
78 commandName,
79 JSON.stringify(validate.errors, undefined, 2),
80 );
81 }
82
83 protected emptyResponseHandler() {
84 /* This is intentional */
85 }
86
87 public abstract responseHandler<ReqType extends JsonType, ResType extends JsonType>(
88 chargingStation: ChargingStation,
89 commandName: RequestCommand,
90 payload: ResType,
91 requestPayload: ReqType,
92 ): Promise<void>;
93 }