7203569749e04d8ee88a238e4ac2f0ea754382da
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / OCPPIncomingRequestService.ts
1 import _Ajv, { type ValidateFunction } from 'ajv'
2 import _ajvFormats from 'ajv-formats'
3
4 import { OCPPConstants } from './OCPPConstants.js'
5 import { OCPPServiceUtils } from './OCPPServiceUtils.js'
6 import { type ChargingStation, getIdTagsFile } from '../../charging-station/index.js'
7 import { OCPPError } from '../../exception/index.js'
8 import type {
9 ClearCacheResponse,
10 HandleErrorParams,
11 IncomingRequestCommand,
12 JsonType,
13 OCPPVersion
14 } from '../../types/index.js'
15 import { logger, setDefaultErrorParams } from '../../utils/index.js'
16 type Ajv = _Ajv.default
17 // eslint-disable-next-line @typescript-eslint/no-redeclare
18 const Ajv = _Ajv.default
19 const ajvFormats = _ajvFormats.default
20
21 const moduleName = 'OCPPIncomingRequestService'
22
23 export abstract class OCPPIncomingRequestService {
24 private static instance: OCPPIncomingRequestService | null = null
25 private readonly version: OCPPVersion
26 protected readonly ajv: Ajv
27 protected abstract payloadValidateFunctions: Map<
28 IncomingRequestCommand,
29 ValidateFunction<JsonType>
30 >
31
32 protected constructor (version: OCPPVersion) {
33 this.version = version
34 this.ajv = new Ajv({
35 keywords: ['javaType'],
36 multipleOfPrecision: 2
37 })
38 ajvFormats(this.ajv)
39 this.incomingRequestHandler = this.incomingRequestHandler.bind(this)
40 this.validateIncomingRequestPayload = this.validateIncomingRequestPayload.bind(this)
41 }
42
43 public static getInstance<T extends OCPPIncomingRequestService>(this: new () => T): T {
44 if (OCPPIncomingRequestService.instance === null) {
45 OCPPIncomingRequestService.instance = new this()
46 }
47 return OCPPIncomingRequestService.instance as T
48 }
49
50 protected handleIncomingRequestError<T extends JsonType>(
51 chargingStation: ChargingStation,
52 commandName: IncomingRequestCommand,
53 error: Error,
54 params: HandleErrorParams<T> = { throwError: true, consoleOut: false }
55 ): T | undefined {
56 setDefaultErrorParams(params)
57 logger.error(
58 `${chargingStation.logPrefix()} ${moduleName}.handleIncomingRequestError: Incoming request command '${commandName}' error:`,
59 error
60 )
61 if (params.throwError === false && params.errorResponse != null) {
62 return params.errorResponse
63 }
64 if (params.throwError === true && params.errorResponse == null) {
65 throw error
66 }
67 if (params.throwError === true && params.errorResponse != null) {
68 return params.errorResponse
69 }
70 }
71
72 protected validateIncomingRequestPayload<T extends JsonType>(
73 chargingStation: ChargingStation,
74 commandName: IncomingRequestCommand,
75 payload: T
76 ): boolean {
77 if (chargingStation.stationInfo?.ocppStrictCompliance === false) {
78 return true
79 }
80 const validate = this.payloadValidateFunctions.get(commandName)
81 if (validate?.(payload) === true) {
82 return true
83 }
84 logger.error(
85 `${chargingStation.logPrefix()} ${moduleName}.validateIncomingRequestPayload: Command '${commandName}' incoming request PDU is invalid: %j`,
86 validate?.errors
87 )
88 throw new OCPPError(
89 OCPPServiceUtils.ajvErrorsToErrorType(validate?.errors),
90 'Incoming request PDU is invalid',
91 commandName,
92 JSON.stringify(validate?.errors, undefined, 2)
93 )
94 }
95
96 protected handleRequestClearCache (chargingStation: ChargingStation): ClearCacheResponse {
97 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
98 if (chargingStation.idTagsCache.deleteIdTags(getIdTagsFile(chargingStation.stationInfo!)!)) {
99 return OCPPConstants.OCPP_RESPONSE_ACCEPTED
100 }
101 return OCPPConstants.OCPP_RESPONSE_REJECTED
102 }
103
104 // eslint-disable-next-line @typescript-eslint/no-unused-vars
105 public abstract incomingRequestHandler<ReqType extends JsonType, ResType extends JsonType>(
106 chargingStation: ChargingStation,
107 messageId: string,
108 commandName: IncomingRequestCommand,
109 commandPayload: ReqType
110 ): Promise<void>
111 }