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