Apply dependencies update
[e-mobility-charging-stations-simulator.git] / src / charging-station / ChargingStationWorkerBroadcastChannel.ts
CommitLineData
6c8f5d90 1import BaseError from '../exception/BaseError';
89b7a234
JB
2import { RequestCommand } from '../types/ocpp/Requests';
3import {
6c8f5d90 4 AuthorizationStatus,
89b7a234
JB
5 StartTransactionRequest,
6 StartTransactionResponse,
7 StopTransactionReason,
8 StopTransactionRequest,
9 StopTransactionResponse,
10} from '../types/ocpp/Transaction';
11import {
12 BroadcastChannelProcedureName,
13 BroadcastChannelRequest,
6c8f5d90
JB
14 BroadcastChannelRequestPayload,
15 BroadcastChannelResponsePayload,
16 MessageEvent,
89b7a234 17} from '../types/WorkerBroadcastChannel';
6c8f5d90
JB
18import { ResponseStatus } from '../ui/web/src/type/UIProtocol';
19import logger from '../utils/Logger';
db2336d9 20import type ChargingStation from './ChargingStation';
1598b27c 21import WorkerBroadcastChannel from './WorkerBroadcastChannel';
89b7a234 22
4e3ff94d
JB
23const moduleName = 'ChargingStationWorkerBroadcastChannel';
24
6c8f5d90 25type CommandResponse = StartTransactionResponse | StopTransactionResponse;
89b7a234 26
1598b27c 27export default class ChargingStationWorkerBroadcastChannel extends WorkerBroadcastChannel {
89b7a234
JB
28 private readonly chargingStation: ChargingStation;
29
30 constructor(chargingStation: ChargingStation) {
1598b27c 31 super();
89b7a234 32 this.chargingStation = chargingStation;
02a6943a 33 this.onmessage = this.requestHandler.bind(this) as (message: MessageEvent) => void;
6c8f5d90 34 this.onmessageerror = this.messageErrorHandler.bind(this) as (message: MessageEvent) => void;
89b7a234
JB
35 }
36
02a6943a 37 private async requestHandler(messageEvent: MessageEvent): Promise<void> {
6c8f5d90
JB
38 if (this.isResponse(messageEvent.data)) {
39 return;
40 }
53e5fd67
JB
41 if (Array.isArray(messageEvent.data) === false) {
42 throw new BaseError('Worker broadcast channel protocol request is not an array');
43 }
89b7a234 44
6c8f5d90
JB
45 const [uuid, command, requestPayload] = messageEvent.data as BroadcastChannelRequest;
46
47 if (requestPayload?.hashId !== this.chargingStation.hashId) {
89b7a234
JB
48 return;
49 }
50
6c8f5d90
JB
51 let responsePayload: BroadcastChannelResponsePayload;
52 let commandResponse: CommandResponse;
53 try {
54 commandResponse = await this.commandHandler(command, requestPayload);
55 if (commandResponse === undefined) {
56 responsePayload = { status: ResponseStatus.SUCCESS };
57 } else {
58 responsePayload = { status: this.commandResponseToResponseStatus(commandResponse) };
59 }
60 } catch (error) {
61 logger.error(
62 `${this.chargingStation.logPrefix()} ${moduleName}.requestHandler: Handle request error:`,
63 error
64 );
65 responsePayload = {
66 status: ResponseStatus.FAILURE,
67 command,
68 requestPayload,
69 commandResponse,
70 errorMessage: (error as Error).message,
71 errorStack: (error as Error).stack,
72 };
73 }
74 this.sendResponse([uuid, responsePayload]);
75 }
76
77 private messageErrorHandler(messageEvent: MessageEvent): void {
78 logger.error(
79 `${this.chargingStation.logPrefix()} ${moduleName}.messageErrorHandler: Error at handling message:`,
80 { messageEvent, messageEventData: messageEvent.data }
81 );
82 }
83
84 private async commandHandler(
85 command: BroadcastChannelProcedureName,
86 requestPayload: BroadcastChannelRequestPayload
87 ): Promise<CommandResponse | undefined> {
89b7a234
JB
88 switch (command) {
89 case BroadcastChannelProcedureName.START_TRANSACTION:
6c8f5d90 90 return this.chargingStation.ocppRequestService.requestHandler<
89b7a234
JB
91 StartTransactionRequest,
92 StartTransactionResponse
93 >(this.chargingStation, RequestCommand.START_TRANSACTION, {
6c8f5d90
JB
94 connectorId: requestPayload.connectorId,
95 idTag: requestPayload.idTag,
89b7a234 96 });
89b7a234 97 case BroadcastChannelProcedureName.STOP_TRANSACTION:
6c8f5d90 98 return this.chargingStation.ocppRequestService.requestHandler<
89b7a234
JB
99 StopTransactionRequest,
100 StopTransactionResponse
101 >(this.chargingStation, RequestCommand.STOP_TRANSACTION, {
6c8f5d90 102 transactionId: requestPayload.transactionId,
89b7a234 103 meterStop: this.chargingStation.getEnergyActiveImportRegisterByTransactionId(
6c8f5d90 104 requestPayload.transactionId
89b7a234 105 ),
6c8f5d90 106 idTag: this.chargingStation.getTransactionIdTag(requestPayload.transactionId),
89b7a234
JB
107 reason: StopTransactionReason.NONE,
108 });
89b7a234
JB
109 case BroadcastChannelProcedureName.START_CHARGING_STATION:
110 this.chargingStation.start();
111 break;
112 case BroadcastChannelProcedureName.STOP_CHARGING_STATION:
113 await this.chargingStation.stop();
114 break;
db2336d9
JB
115 case BroadcastChannelProcedureName.OPEN_CONNECTION:
116 this.chargingStation.openWSConnection();
117 break;
118 case BroadcastChannelProcedureName.CLOSE_CONNECTION:
119 this.chargingStation.closeWSConnection();
120 break;
6c8f5d90
JB
121 default:
122 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
ce7a4fc3 123 throw new BaseError(`Unknown worker broadcast channel command: ${command}`);
6c8f5d90
JB
124 }
125 }
126
127 private commandResponseToResponseStatus(commandResponse: CommandResponse): ResponseStatus {
128 if (commandResponse?.idTagInfo?.status === AuthorizationStatus.ACCEPTED) {
129 return ResponseStatus.SUCCESS;
89b7a234 130 }
6c8f5d90 131 return ResponseStatus.FAILURE;
89b7a234
JB
132 }
133}