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