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