Commit | Line | Data |
---|---|---|
66a7748d JB |
1 | import _Ajv, { type JSONSchemaType, type ValidateFunction } from 'ajv' |
2 | import _ajvFormats from 'ajv-formats' | |
b52c969d | 3 | |
66a7748d JB |
4 | import { OCPPConstants } from './OCPPConstants.js' |
5 | import type { OCPPResponseService } from './OCPPResponseService.js' | |
6 | import { OCPPServiceUtils } from './OCPPServiceUtils.js' | |
7 | import type { ChargingStation } from '../../charging-station/index.js' | |
8 | import { OCPPError } from '../../exception/index.js' | |
9 | import { PerformanceStatistics } from '../../performance/index.js' | |
e7aeea18 | 10 | import { |
8baae8ee | 11 | ChargingStationEvents, |
27782dbc | 12 | type ErrorCallback, |
268a74bb JB |
13 | type ErrorResponse, |
14 | ErrorType, | |
27782dbc | 15 | type IncomingRequestCommand, |
268a74bb JB |
16 | type JsonType, |
17 | MessageType, | |
18 | type OCPPVersion, | |
27782dbc | 19 | type OutgoingRequest, |
e7aeea18 | 20 | RequestCommand, |
27782dbc | 21 | type RequestParams, |
268a74bb | 22 | type Response, |
27782dbc | 23 | type ResponseCallback, |
66a7748d JB |
24 | type ResponseType |
25 | } from '../../types/index.js' | |
2b94ad12 | 26 | import { |
40615072 | 27 | clone, |
2b94ad12 JB |
28 | formatDurationMilliSeconds, |
29 | handleSendMessageError, | |
66a7748d JB |
30 | logger |
31 | } from '../../utils/index.js' | |
32 | type Ajv = _Ajv.default | |
33 | // eslint-disable-next-line @typescript-eslint/no-redeclare | |
34 | const Ajv = _Ajv.default | |
35 | const ajvFormats = _ajvFormats.default | |
c0560973 | 36 | |
66a7748d | 37 | const moduleName = 'OCPPRequestService' |
e3018bc4 | 38 | |
b9da1bc2 JB |
39 | const defaultRequestParams: RequestParams = { |
40 | skipBufferingOnError: false, | |
41 | triggerMessage: false, | |
66a7748d JB |
42 | throwError: false |
43 | } | |
b9da1bc2 | 44 | |
268a74bb | 45 | export abstract class OCPPRequestService { |
66a7748d JB |
46 | private static instance: OCPPRequestService | null = null |
47 | private readonly version: OCPPVersion | |
48 | private readonly ajv: Ajv | |
49 | private readonly ocppResponseService: OCPPResponseService | |
50 | private readonly jsonValidateFunctions: Map<RequestCommand, ValidateFunction<JsonType>> | |
51 | protected abstract jsonSchemas: Map<RequestCommand, JSONSchemaType<JsonType>> | |
c0560973 | 52 | |
66a7748d JB |
53 | protected constructor (version: OCPPVersion, ocppResponseService: OCPPResponseService) { |
54 | this.version = version | |
45988780 | 55 | this.ajv = new Ajv({ |
98fc1389 | 56 | keywords: ['javaType'], |
66a7748d JB |
57 | multipleOfPrecision: 2 |
58 | }) | |
59 | ajvFormats(this.ajv) | |
60 | this.jsonValidateFunctions = new Map<RequestCommand, ValidateFunction<JsonType>>() | |
61 | this.ocppResponseService = ocppResponseService | |
ba9a56a6 JB |
62 | this.requestHandler = this.requestHandler.bind(this) |
63 | this.sendMessage = this.sendMessage.bind(this) | |
64 | this.sendResponse = this.sendResponse.bind(this) | |
65 | this.sendError = this.sendError.bind(this) | |
66 | this.internalSendMessage = this.internalSendMessage.bind(this) | |
67 | this.buildMessageToSend = this.buildMessageToSend.bind(this) | |
68 | this.validateRequestPayload = this.validateRequestPayload.bind(this) | |
69 | this.validateIncomingRequestResponsePayload = | |
70 | this.validateIncomingRequestResponsePayload.bind(this) | |
c0560973 JB |
71 | } |
72 | ||
e7aeea18 | 73 | public static getInstance<T extends OCPPRequestService>( |
08f130a0 | 74 | this: new (ocppResponseService: OCPPResponseService) => T, |
66a7748d | 75 | ocppResponseService: OCPPResponseService |
e7aeea18 | 76 | ): T { |
1ca780f9 | 77 | if (OCPPRequestService.instance === null) { |
66a7748d | 78 | OCPPRequestService.instance = new this(ocppResponseService) |
9f2e3130 | 79 | } |
66a7748d | 80 | return OCPPRequestService.instance as T |
9f2e3130 JB |
81 | } |
82 | ||
66a7748d | 83 | public async sendResponse ( |
08f130a0 | 84 | chargingStation: ChargingStation, |
e7aeea18 | 85 | messageId: string, |
5cc4b63b | 86 | messagePayload: JsonType, |
66a7748d | 87 | commandName: IncomingRequestCommand |
5eaabe90 | 88 | ): Promise<ResponseType> { |
5e0c67e8 | 89 | try { |
c75a6675 | 90 | // Send response message |
e7aeea18 | 91 | return await this.internalSendMessage( |
08f130a0 | 92 | chargingStation, |
e7aeea18 JB |
93 | messageId, |
94 | messagePayload, | |
95 | MessageType.CALL_RESULT_MESSAGE, | |
66a7748d JB |
96 | commandName |
97 | ) | |
5e0c67e8 | 98 | } catch (error) { |
fa5995d6 | 99 | handleSendMessageError(chargingStation, commandName, error as Error, { |
66a7748d JB |
100 | throwError: true |
101 | }) | |
102 | return null | |
5e0c67e8 JB |
103 | } |
104 | } | |
105 | ||
66a7748d | 106 | public async sendError ( |
08f130a0 | 107 | chargingStation: ChargingStation, |
e7aeea18 JB |
108 | messageId: string, |
109 | ocppError: OCPPError, | |
66a7748d | 110 | commandName: RequestCommand | IncomingRequestCommand |
e7aeea18 | 111 | ): Promise<ResponseType> { |
5e0c67e8 JB |
112 | try { |
113 | // Send error message | |
e7aeea18 | 114 | return await this.internalSendMessage( |
08f130a0 | 115 | chargingStation, |
e7aeea18 JB |
116 | messageId, |
117 | ocppError, | |
118 | MessageType.CALL_ERROR_MESSAGE, | |
66a7748d JB |
119 | commandName |
120 | ) | |
5e0c67e8 | 121 | } catch (error) { |
66a7748d JB |
122 | handleSendMessageError(chargingStation, commandName, error as Error) |
123 | return null | |
5e0c67e8 JB |
124 | } |
125 | } | |
126 | ||
66a7748d | 127 | protected async sendMessage ( |
08f130a0 | 128 | chargingStation: ChargingStation, |
e7aeea18 | 129 | messageId: string, |
5cc4b63b | 130 | messagePayload: JsonType, |
e7aeea18 | 131 | commandName: RequestCommand, |
66a7748d | 132 | params?: RequestParams |
e7aeea18 | 133 | ): Promise<ResponseType> { |
7b5dbe91 | 134 | params = { |
b9da1bc2 | 135 | ...defaultRequestParams, |
66a7748d JB |
136 | ...params |
137 | } | |
5e0c67e8 | 138 | try { |
e7aeea18 | 139 | return await this.internalSendMessage( |
08f130a0 | 140 | chargingStation, |
e7aeea18 JB |
141 | messageId, |
142 | messagePayload, | |
143 | MessageType.CALL_MESSAGE, | |
144 | commandName, | |
66a7748d JB |
145 | params |
146 | ) | |
5e0c67e8 | 147 | } catch (error) { |
fa5995d6 | 148 | handleSendMessageError(chargingStation, commandName, error as Error, { |
66a7748d JB |
149 | throwError: params.throwError |
150 | }) | |
151 | return null | |
5e0c67e8 JB |
152 | } |
153 | } | |
154 | ||
291b5ec8 | 155 | private validateRequestPayload<T extends JsonType>( |
b52c969d | 156 | chargingStation: ChargingStation, |
45988780 | 157 | commandName: RequestCommand | IncomingRequestCommand, |
66a7748d | 158 | payload: T |
b52c969d | 159 | ): boolean { |
5398cecf | 160 | if (chargingStation.stationInfo?.ocppStrictCompliance === false) { |
66a7748d | 161 | return true |
b52c969d | 162 | } |
66a7748d | 163 | if (!this.jsonSchemas.has(commandName as RequestCommand)) { |
b3fc3ff5 | 164 | logger.warn( |
66a7748d JB |
165 | `${chargingStation.logPrefix()} ${moduleName}.validateRequestPayload: No JSON schema found for command '${commandName}' PDU validation` |
166 | ) | |
167 | return true | |
45988780 | 168 | } |
66a7748d | 169 | const validate = this.getJsonRequestValidateFunction<T>(commandName as RequestCommand) |
40615072 | 170 | payload = clone<T>(payload) |
66a7748d | 171 | OCPPServiceUtils.convertDateToISOString<T>(payload) |
b52c969d | 172 | if (validate(payload)) { |
66a7748d | 173 | return true |
b52c969d JB |
174 | } |
175 | logger.error( | |
45988780 | 176 | `${chargingStation.logPrefix()} ${moduleName}.validateRequestPayload: Command '${commandName}' request PDU is invalid: %j`, |
66a7748d JB |
177 | validate.errors |
178 | ) | |
e909d2a7 | 179 | // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError(). |
b52c969d | 180 | throw new OCPPError( |
9ff486f4 | 181 | OCPPServiceUtils.ajvErrorsToErrorType(validate.errors), |
b52c969d JB |
182 | 'Request PDU is invalid', |
183 | commandName, | |
66a7748d JB |
184 | JSON.stringify(validate.errors, undefined, 2) |
185 | ) | |
b52c969d JB |
186 | } |
187 | ||
66a7748d JB |
188 | private getJsonRequestValidateFunction<T extends JsonType>( |
189 | commandName: RequestCommand | |
190 | ): ValidateFunction<JsonType> { | |
191 | if (!this.jsonValidateFunctions.has(commandName)) { | |
0b0ca54f JB |
192 | this.jsonValidateFunctions.set( |
193 | commandName, | |
66a7748d JB |
194 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion |
195 | this.ajv.compile<T>(this.jsonSchemas.get(commandName)!).bind(this) | |
196 | ) | |
0b0ca54f | 197 | } |
66a7748d JB |
198 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion |
199 | return this.jsonValidateFunctions.get(commandName)! | |
0b0ca54f JB |
200 | } |
201 | ||
291b5ec8 | 202 | private validateIncomingRequestResponsePayload<T extends JsonType>( |
b3fc3ff5 JB |
203 | chargingStation: ChargingStation, |
204 | commandName: RequestCommand | IncomingRequestCommand, | |
66a7748d | 205 | payload: T |
b3fc3ff5 | 206 | ): boolean { |
5398cecf | 207 | if (chargingStation.stationInfo?.ocppStrictCompliance === false) { |
66a7748d | 208 | return true |
b3fc3ff5 JB |
209 | } |
210 | if ( | |
66a7748d JB |
211 | !this.ocppResponseService.jsonIncomingRequestResponseSchemas.has( |
212 | commandName as IncomingRequestCommand | |
213 | ) | |
b3fc3ff5 JB |
214 | ) { |
215 | logger.warn( | |
66a7748d JB |
216 | `${chargingStation.logPrefix()} ${moduleName}.validateIncomingRequestResponsePayload: No JSON schema found for command '${commandName}' PDU validation` |
217 | ) | |
218 | return true | |
b3fc3ff5 | 219 | } |
0b0ca54f | 220 | const validate = this.getJsonRequestResponseValidateFunction<T>( |
66a7748d JB |
221 | commandName as IncomingRequestCommand |
222 | ) | |
40615072 | 223 | payload = clone<T>(payload) |
66a7748d | 224 | OCPPServiceUtils.convertDateToISOString<T>(payload) |
b3fc3ff5 | 225 | if (validate(payload)) { |
66a7748d | 226 | return true |
b3fc3ff5 JB |
227 | } |
228 | logger.error( | |
02887891 | 229 | `${chargingStation.logPrefix()} ${moduleName}.validateIncomingRequestResponsePayload: Command '${commandName}' reponse PDU is invalid: %j`, |
66a7748d JB |
230 | validate.errors |
231 | ) | |
b3fc3ff5 JB |
232 | // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError(). |
233 | throw new OCPPError( | |
9ff486f4 | 234 | OCPPServiceUtils.ajvErrorsToErrorType(validate.errors), |
b3fc3ff5 JB |
235 | 'Response PDU is invalid', |
236 | commandName, | |
66a7748d JB |
237 | JSON.stringify(validate.errors, undefined, 2) |
238 | ) | |
b3fc3ff5 JB |
239 | } |
240 | ||
0b0ca54f | 241 | private getJsonRequestResponseValidateFunction<T extends JsonType>( |
66a7748d JB |
242 | commandName: IncomingRequestCommand |
243 | ): ValidateFunction<JsonType> { | |
244 | if (!this.ocppResponseService.jsonIncomingRequestResponseValidateFunctions.has(commandName)) { | |
0b0ca54f JB |
245 | this.ocppResponseService.jsonIncomingRequestResponseValidateFunctions.set( |
246 | commandName, | |
247 | this.ajv | |
66a7748d | 248 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion |
0b0ca54f | 249 | .compile<T>(this.ocppResponseService.jsonIncomingRequestResponseSchemas.get(commandName)!) |
66a7748d JB |
250 | .bind(this) |
251 | ) | |
0b0ca54f | 252 | } |
66a7748d JB |
253 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion |
254 | return this.ocppResponseService.jsonIncomingRequestResponseValidateFunctions.get(commandName)! | |
0b0ca54f JB |
255 | } |
256 | ||
66a7748d | 257 | private async internalSendMessage ( |
08f130a0 | 258 | chargingStation: ChargingStation, |
e7aeea18 | 259 | messageId: string, |
5cc4b63b | 260 | messagePayload: JsonType | OCPPError, |
e7aeea18 | 261 | messageType: MessageType, |
72092cfc | 262 | commandName: RequestCommand | IncomingRequestCommand, |
66a7748d | 263 | params?: RequestParams |
e7aeea18 | 264 | ): Promise<ResponseType> { |
7b5dbe91 | 265 | params = { |
b9da1bc2 | 266 | ...defaultRequestParams, |
66a7748d JB |
267 | ...params |
268 | } | |
e7aeea18 | 269 | if ( |
66a7748d | 270 | (chargingStation.inUnknownState() && commandName === RequestCommand.BOOT_NOTIFICATION) || |
5398cecf | 271 | (chargingStation.stationInfo?.ocppStrictCompliance === false && |
66a7748d JB |
272 | chargingStation.inUnknownState()) || |
273 | chargingStation.inAcceptedState() || | |
274 | (chargingStation.inPendingState() && | |
3a13fc92 | 275 | (params.triggerMessage === true || messageType === MessageType.CALL_RESULT_MESSAGE)) |
e7aeea18 | 276 | ) { |
caad9d6b | 277 | // eslint-disable-next-line @typescript-eslint/no-this-alias |
66a7748d | 278 | const self = this |
caad9d6b | 279 | // Send a message through wsConnection |
66a7748d | 280 | return await new Promise<ResponseType>((resolve, reject) => { |
1b2acf4e JB |
281 | /** |
282 | * Function that will receive the request's response | |
283 | * | |
284 | * @param payload - | |
285 | * @param requestPayload - | |
286 | */ | |
287 | const responseCallback = (payload: JsonType, requestPayload: JsonType): void => { | |
288 | if (chargingStation.stationInfo?.enableStatistics === true) { | |
289 | chargingStation.performanceStatistics?.addRequestStatistic( | |
290 | commandName, | |
66a7748d JB |
291 | MessageType.CALL_RESULT_MESSAGE |
292 | ) | |
1b2acf4e JB |
293 | } |
294 | // Handle the request's response | |
295 | self.ocppResponseService | |
296 | .responseHandler( | |
297 | chargingStation, | |
298 | commandName as RequestCommand, | |
299 | payload, | |
66a7748d | 300 | requestPayload |
1b2acf4e JB |
301 | ) |
302 | .then(() => { | |
66a7748d | 303 | resolve(payload) |
1b2acf4e | 304 | }) |
b7ee97c1 | 305 | .catch(reject) |
1b2acf4e | 306 | .finally(() => { |
66a7748d JB |
307 | chargingStation.requests.delete(messageId) |
308 | chargingStation.emit(ChargingStationEvents.updated) | |
309 | }) | |
310 | } | |
e8a92d57 | 311 | |
1b2acf4e JB |
312 | /** |
313 | * Function that will receive the request's error response | |
314 | * | |
9d7b5fa3 | 315 | * @param ocppError - |
1b2acf4e JB |
316 | * @param requestStatistic - |
317 | */ | |
9d7b5fa3 | 318 | const errorCallback = (ocppError: OCPPError, requestStatistic = true): void => { |
66a7748d | 319 | if (requestStatistic && chargingStation.stationInfo?.enableStatistics === true) { |
1b2acf4e JB |
320 | chargingStation.performanceStatistics?.addRequestStatistic( |
321 | commandName, | |
66a7748d JB |
322 | MessageType.CALL_ERROR_MESSAGE |
323 | ) | |
764d2c91 | 324 | } |
1b2acf4e JB |
325 | logger.error( |
326 | `${chargingStation.logPrefix()} Error occurred at ${OCPPServiceUtils.getMessageTypeString( | |
66a7748d | 327 | messageType |
1b2acf4e | 328 | )} command ${commandName} with PDU %j:`, |
e7aeea18 | 329 | messagePayload, |
66a7748d JB |
330 | ocppError |
331 | ) | |
332 | chargingStation.requests.delete(messageId) | |
333 | chargingStation.emit(ChargingStationEvents.updated) | |
334 | reject(ocppError) | |
335 | } | |
9d7b5fa3 | 336 | |
3c80de96 JB |
337 | const handleSendError = (ocppError: OCPPError): void => { |
338 | if (params?.skipBufferingOnError === false) { | |
339 | // Buffer | |
66a7748d | 340 | chargingStation.bufferMessage(messageToSend) |
3c80de96 JB |
341 | if (messageType === MessageType.CALL_MESSAGE) { |
342 | this.cacheRequestPromise( | |
343 | chargingStation, | |
344 | messageId, | |
345 | messagePayload as JsonType, | |
346 | commandName, | |
347 | responseCallback, | |
66a7748d JB |
348 | errorCallback |
349 | ) | |
3c80de96 | 350 | } |
9aa1a33f JB |
351 | } else if ( |
352 | params?.skipBufferingOnError === true && | |
353 | messageType === MessageType.CALL_MESSAGE | |
354 | ) { | |
2b94ad12 | 355 | // Remove request from the cache |
66a7748d | 356 | chargingStation.requests.delete(messageId) |
d42379d8 | 357 | } |
66a7748d JB |
358 | reject(ocppError) |
359 | } | |
d42379d8 | 360 | |
1b2acf4e | 361 | if (chargingStation.stationInfo?.enableStatistics === true) { |
66a7748d | 362 | chargingStation.performanceStatistics?.addRequestStatistic(commandName, messageType) |
1b2acf4e JB |
363 | } |
364 | const messageToSend = this.buildMessageToSend( | |
365 | chargingStation, | |
366 | messageId, | |
367 | messagePayload, | |
368 | messageType, | |
66a7748d JB |
369 | commandName |
370 | ) | |
1b2acf4e | 371 | // Check if wsConnection opened |
66a7748d JB |
372 | if (chargingStation.isWebSocketConnectionOpened()) { |
373 | const beginId = PerformanceStatistics.beginMeasure(commandName) | |
1a32c36b | 374 | const sendTimeout = setTimeout(() => { |
66a7748d | 375 | handleSendError( |
1a32c36b JB |
376 | new OCPPError( |
377 | ErrorType.GENERIC_ERROR, | |
2b94ad12 | 378 | `Timeout ${formatDurationMilliSeconds( |
66a7748d | 379 | OCPPConstants.OCPP_WEBSOCKET_TIMEOUT |
2b94ad12 JB |
380 | )} reached for ${ |
381 | params?.skipBufferingOnError === false ? '' : 'non ' | |
42b8cf5c | 382 | }buffered message id '${messageId}' with content '${messageToSend}'`, |
1a32c36b | 383 | commandName, |
66a7748d JB |
384 | (messagePayload as OCPPError).details |
385 | ) | |
386 | ) | |
387 | }, OCPPConstants.OCPP_WEBSOCKET_TIMEOUT) | |
1a32c36b | 388 | chargingStation.wsConnection?.send(messageToSend, (error?: Error) => { |
66a7748d JB |
389 | PerformanceStatistics.endMeasure(commandName, beginId) |
390 | clearTimeout(sendTimeout) | |
aa63c9b7 | 391 | if (error == null) { |
d42379d8 JB |
392 | logger.debug( |
393 | `${chargingStation.logPrefix()} >> Command '${commandName}' sent ${OCPPServiceUtils.getMessageTypeString( | |
66a7748d JB |
394 | messageType |
395 | )} payload: ${messageToSend}` | |
396 | ) | |
d42379d8 JB |
397 | if (messageType === MessageType.CALL_MESSAGE) { |
398 | this.cacheRequestPromise( | |
399 | chargingStation, | |
400 | messageId, | |
401 | messagePayload as JsonType, | |
402 | commandName, | |
403 | responseCallback, | |
66a7748d JB |
404 | errorCallback |
405 | ) | |
69dae411 JB |
406 | } else { |
407 | // Resolve response | |
66a7748d | 408 | resolve(messagePayload) |
d42379d8 | 409 | } |
5199f9fd | 410 | } else { |
66a7748d | 411 | handleSendError( |
3c80de96 JB |
412 | new OCPPError( |
413 | ErrorType.GENERIC_ERROR, | |
414 | `WebSocket errored for ${ | |
415 | params?.skipBufferingOnError === false ? '' : 'non ' | |
416 | }buffered message id '${messageId}' with content '${messageToSend}'`, | |
417 | commandName, | |
66a7748d JB |
418 | { name: error.name, message: error.message, stack: error.stack } |
419 | ) | |
420 | ) | |
1a32c36b | 421 | } |
66a7748d | 422 | }) |
82fa1110 | 423 | } else { |
66a7748d | 424 | handleSendError( |
3c80de96 JB |
425 | new OCPPError( |
426 | ErrorType.GENERIC_ERROR, | |
427 | `WebSocket closed for ${ | |
428 | params?.skipBufferingOnError === false ? '' : 'non ' | |
429 | }buffered message id '${messageId}' with content '${messageToSend}'`, | |
430 | commandName, | |
66a7748d JB |
431 | (messagePayload as OCPPError).details |
432 | ) | |
433 | ) | |
1b2acf4e | 434 | } |
66a7748d | 435 | }) |
caad9d6b | 436 | } |
e7aeea18 JB |
437 | throw new OCPPError( |
438 | ErrorType.SECURITY_ERROR, | |
5199f9fd | 439 | `Cannot send command ${commandName} PDU when the charging station is in ${chargingStation.bootNotificationResponse?.status} state on the central server`, |
66a7748d JB |
440 | commandName |
441 | ) | |
c0560973 JB |
442 | } |
443 | ||
66a7748d | 444 | private buildMessageToSend ( |
08f130a0 | 445 | chargingStation: ChargingStation, |
e7aeea18 | 446 | messageId: string, |
5cc4b63b | 447 | messagePayload: JsonType | OCPPError, |
e7aeea18 | 448 | messageType: MessageType, |
66a7748d | 449 | commandName: RequestCommand | IncomingRequestCommand |
e7aeea18 | 450 | ): string { |
66a7748d | 451 | let messageToSend: string |
e7accadb JB |
452 | // Type of message |
453 | switch (messageType) { | |
454 | // Request | |
455 | case MessageType.CALL_MESSAGE: | |
456 | // Build request | |
66a7748d | 457 | this.validateRequestPayload(chargingStation, commandName, messagePayload as JsonType) |
b3ec7bc1 JB |
458 | messageToSend = JSON.stringify([ |
459 | messageType, | |
460 | messageId, | |
461 | commandName, | |
66a7748d JB |
462 | messagePayload |
463 | ] as OutgoingRequest) | |
464 | break | |
e7accadb JB |
465 | // Response |
466 | case MessageType.CALL_RESULT_MESSAGE: | |
467 | // Build response | |
02887891 JB |
468 | this.validateIncomingRequestResponsePayload( |
469 | chargingStation, | |
470 | commandName, | |
66a7748d JB |
471 | messagePayload as JsonType |
472 | ) | |
473 | messageToSend = JSON.stringify([messageType, messageId, messagePayload] as Response) | |
474 | break | |
e7accadb JB |
475 | // Error Message |
476 | case MessageType.CALL_ERROR_MESSAGE: | |
477 | // Build Error Message | |
e7aeea18 JB |
478 | messageToSend = JSON.stringify([ |
479 | messageType, | |
480 | messageId, | |
7375968c JB |
481 | (messagePayload as OCPPError).code, |
482 | (messagePayload as OCPPError).message, | |
483 | (messagePayload as OCPPError).details ?? { | |
66a7748d JB |
484 | command: (messagePayload as OCPPError).command ?? commandName |
485 | } | |
486 | ] as ErrorResponse) | |
487 | break | |
e7accadb | 488 | } |
66a7748d | 489 | return messageToSend |
e7accadb JB |
490 | } |
491 | ||
66a7748d | 492 | private cacheRequestPromise ( |
82fa1110 | 493 | chargingStation: ChargingStation, |
82fa1110 JB |
494 | messageId: string, |
495 | messagePayload: JsonType, | |
496 | commandName: RequestCommand | IncomingRequestCommand, | |
54a8fbc7 | 497 | responseCallback: ResponseCallback, |
66a7748d | 498 | errorCallback: ErrorCallback |
82fa1110 JB |
499 | ): void { |
500 | chargingStation.requests.set(messageId, [ | |
501 | responseCallback, | |
502 | errorCallback, | |
503 | commandName, | |
66a7748d JB |
504 | messagePayload |
505 | ]) | |
82fa1110 JB |
506 | } |
507 | ||
ef6fa3fb | 508 | // eslint-disable-next-line @typescript-eslint/no-unused-vars |
e0b0ee21 | 509 | public abstract requestHandler<ReqType extends JsonType, ResType extends JsonType>( |
08f130a0 | 510 | chargingStation: ChargingStation, |
94a464f9 | 511 | commandName: RequestCommand, |
e1d9a0f4 | 512 | // FIXME: should be ReqType |
5cc4b63b | 513 | commandParams?: JsonType, |
66a7748d JB |
514 | params?: RequestParams |
515 | ): Promise<ResType> | |
c0560973 | 516 | } |