refactor: cleanup unneeded type casting
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / 2.0 / OCPP20IncomingRequestService.ts
CommitLineData
a19b897d 1// Partial Copyright Jerome Benoit. 2021-2024. All Rights Reserved.
953d6b02 2
66a7748d 3import type { JSONSchemaType } from 'ajv'
953d6b02 4
66a7748d
JB
5import { OCPP20ServiceUtils } from './OCPP20ServiceUtils.js'
6import type { ChargingStation } from '../../../charging-station/index.js'
7import { OCPPError } from '../../../exception/index.js'
d270cc87 8import {
268a74bb
JB
9 ErrorType,
10 type IncomingRequestHandler,
268a74bb 11 type JsonType,
81533a20 12 type OCPP20ClearCacheRequest,
d270cc87 13 OCPP20IncomingRequestCommand,
66a7748d
JB
14 OCPPVersion
15} from '../../../types/index.js'
16import { logger } from '../../../utils/index.js'
17import { OCPPIncomingRequestService } from '../OCPPIncomingRequestService.js'
953d6b02 18
66a7748d 19const moduleName = 'OCPP20IncomingRequestService'
953d6b02 20
268a74bb 21export class OCPP20IncomingRequestService extends OCPPIncomingRequestService {
66a7748d
JB
22 protected jsonSchemas: Map<OCPP20IncomingRequestCommand, JSONSchemaType<JsonType>>
23 private readonly incomingRequestHandlers: Map<
24 OCPP20IncomingRequestCommand,
25 IncomingRequestHandler
26 >
953d6b02 27
66a7748d 28 public constructor () {
5199f9fd
JB
29 // if (new.target.name === moduleName) {
30 // throw new TypeError(`Cannot construct ${new.target.name} instances directly`)
b768993d 31 // }
66a7748d 32 super(OCPPVersion.VERSION_20)
d270cc87 33 this.incomingRequestHandlers = new Map<OCPP20IncomingRequestCommand, IncomingRequestHandler>([
66a7748d
JB
34 [OCPP20IncomingRequestCommand.CLEAR_CACHE, this.handleRequestClearCache.bind(this)]
35 ])
291b5ec8 36 this.jsonSchemas = new Map<OCPP20IncomingRequestCommand, JSONSchemaType<JsonType>>([
d270cc87
JB
37 [
38 OCPP20IncomingRequestCommand.CLEAR_CACHE,
130783a7 39 OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20ClearCacheRequest>(
51022aa0 40 'assets/json-schemas/ocpp/2.0/ClearCacheRequest.json',
1b271a54 41 moduleName,
66a7748d
JB
42 'constructor'
43 )
44 ]
45 ])
ba9a56a6 46 this.validatePayload = this.validatePayload.bind(this)
953d6b02
JB
47 }
48
9429aa42 49 public async incomingRequestHandler<ReqType extends JsonType, ResType extends JsonType>(
953d6b02
JB
50 chargingStation: ChargingStation,
51 messageId: string,
52 commandName: OCPP20IncomingRequestCommand,
66a7748d 53 commandPayload: ReqType
953d6b02 54 ): Promise<void> {
66a7748d 55 let response: ResType
953d6b02 56 if (
5398cecf 57 chargingStation.stationInfo?.ocppStrictCompliance === true &&
66a7748d 58 chargingStation.inPendingState() &&
81533a20
JB
59 (commandName === OCPP20IncomingRequestCommand.REQUEST_START_TRANSACTION ||
60 commandName === OCPP20IncomingRequestCommand.REQUEST_STOP_TRANSACTION)
953d6b02
JB
61 ) {
62 throw new OCPPError(
63 ErrorType.SECURITY_ERROR,
64 `${commandName} cannot be issued to handle request PDU ${JSON.stringify(
65 commandPayload,
4ed03b6e 66 undefined,
66a7748d 67 2
953d6b02
JB
68 )} while the charging station is in pending state on the central server`,
69 commandName,
66a7748d
JB
70 commandPayload
71 )
953d6b02
JB
72 }
73 if (
66a7748d 74 chargingStation.isRegistered() ||
5398cecf 75 (chargingStation.stationInfo?.ocppStrictCompliance === false &&
66a7748d 76 chargingStation.inUnknownState())
953d6b02
JB
77 ) {
78 if (
66a7748d
JB
79 this.incomingRequestHandlers.has(commandName) &&
80 OCPP20ServiceUtils.isIncomingRequestCommandSupported(chargingStation, commandName)
953d6b02
JB
81 ) {
82 try {
66a7748d 83 this.validatePayload(chargingStation, commandName, commandPayload)
953d6b02 84 // Call the method to build the response
66a7748d 85 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
9429aa42 86 response = (await this.incomingRequestHandlers.get(commandName)!(
953d6b02 87 chargingStation,
66a7748d
JB
88 commandPayload
89 )) as ResType
953d6b02
JB
90 } catch (error) {
91 // Log
92 logger.error(
93 `${chargingStation.logPrefix()} ${moduleName}.incomingRequestHandler: Handle incoming request error:`,
66a7748d
JB
94 error
95 )
96 throw error
953d6b02
JB
97 }
98 } else {
99 // Throw exception
100 throw new OCPPError(
101 ErrorType.NOT_IMPLEMENTED,
102 `${commandName} is not implemented to handle request PDU ${JSON.stringify(
103 commandPayload,
4ed03b6e 104 undefined,
66a7748d 105 2
953d6b02
JB
106 )}`,
107 commandName,
66a7748d
JB
108 commandPayload
109 )
953d6b02
JB
110 }
111 } else {
112 throw new OCPPError(
113 ErrorType.SECURITY_ERROR,
114 `${commandName} cannot be issued to handle request PDU ${JSON.stringify(
115 commandPayload,
4ed03b6e 116 undefined,
66a7748d 117 2
953d6b02
JB
118 )} while the charging station is not registered on the central server.`,
119 commandName,
66a7748d
JB
120 commandPayload
121 )
953d6b02
JB
122 }
123 // Send the built response
124 await chargingStation.ocppRequestService.sendResponse(
125 chargingStation,
126 messageId,
127 response,
66a7748d
JB
128 commandName
129 )
953d6b02
JB
130 }
131
66a7748d 132 private validatePayload (
953d6b02
JB
133 chargingStation: ChargingStation,
134 commandName: OCPP20IncomingRequestCommand,
66a7748d 135 commandPayload: JsonType
953d6b02 136 ): boolean {
66a7748d 137 if (this.jsonSchemas.has(commandName)) {
953d6b02
JB
138 return this.validateIncomingRequestPayload(
139 chargingStation,
140 commandName,
66a7748d 141 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
e1d9a0f4 142 this.jsonSchemas.get(commandName)!,
66a7748d
JB
143 commandPayload
144 )
953d6b02
JB
145 }
146 logger.warn(
66a7748d
JB
147 `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command '${commandName}' PDU validation`
148 )
149 return false
953d6b02
JB
150 }
151}