refactor: cleanup unneeded type casting
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / OCPPIncomingRequestService.ts
1 import _Ajv, { type JSONSchemaType, 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 private readonly ajv: Ajv
27 private readonly jsonValidateFunctions: Map<IncomingRequestCommand, ValidateFunction<JsonType>>
28 protected abstract jsonSchemas: Map<IncomingRequestCommand, JSONSchemaType<JsonType>>
29
30 protected constructor (version: OCPPVersion) {
31 this.version = version
32 this.ajv = new Ajv({
33 keywords: ['javaType'],
34 multipleOfPrecision: 2
35 })
36 ajvFormats(this.ajv)
37 this.jsonValidateFunctions = new Map<IncomingRequestCommand, ValidateFunction<JsonType>>()
38 this.incomingRequestHandler = this.incomingRequestHandler.bind(this)
39 this.validateIncomingRequestPayload = this.validateIncomingRequestPayload.bind(this)
40 }
41
42 public static getInstance<T extends OCPPIncomingRequestService>(this: new () => T): T {
43 if (OCPPIncomingRequestService.instance === null) {
44 OCPPIncomingRequestService.instance = new this()
45 }
46 return OCPPIncomingRequestService.instance as T
47 }
48
49 protected handleIncomingRequestError<T extends JsonType>(
50 chargingStation: ChargingStation,
51 commandName: IncomingRequestCommand,
52 error: Error,
53 params: HandleErrorParams<T> = { throwError: true, consoleOut: false }
54 ): T | undefined {
55 setDefaultErrorParams(params)
56 logger.error(
57 `${chargingStation.logPrefix()} ${moduleName}.handleIncomingRequestError: Incoming request command '${commandName}' error:`,
58 error
59 )
60 if (params.throwError === false && params.errorResponse != null) {
61 return params.errorResponse
62 }
63 if (params.throwError === true && params.errorResponse == null) {
64 throw error
65 }
66 if (params.throwError === true && params.errorResponse != null) {
67 return params.errorResponse
68 }
69 }
70
71 protected validateIncomingRequestPayload<T extends JsonType>(
72 chargingStation: ChargingStation,
73 commandName: IncomingRequestCommand,
74 schema: JSONSchemaType<T>,
75 payload: T
76 ): boolean {
77 if (chargingStation.stationInfo?.ocppStrictCompliance === false) {
78 return true
79 }
80 const validate = this.getJsonIncomingRequestValidateFunction<T>(commandName, schema)
81 if (validate(payload)) {
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 private getJsonIncomingRequestValidateFunction<T extends JsonType>(
105 commandName: IncomingRequestCommand,
106 schema: JSONSchemaType<T>
107 ): ValidateFunction<JsonType> {
108 if (!this.jsonValidateFunctions.has(commandName)) {
109 this.jsonValidateFunctions.set(commandName, this.ajv.compile<T>(schema).bind(this))
110 }
111 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
112 return this.jsonValidateFunctions.get(commandName)!
113 }
114
115 // eslint-disable-next-line @typescript-eslint/no-unused-vars
116 public abstract incomingRequestHandler<ReqType extends JsonType, ResType extends JsonType>(
117 chargingStation: ChargingStation,
118 messageId: string,
119 commandName: IncomingRequestCommand,
120 commandPayload: ReqType
121 ): Promise<void>
122 }