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