Commit | Line | Data |
---|---|---|
6c8f5d90 | 1 | import BaseError from '../exception/BaseError'; |
89b7a234 JB |
2 | import { RequestCommand } from '../types/ocpp/Requests'; |
3 | import { | |
6c8f5d90 | 4 | AuthorizationStatus, |
89b7a234 JB |
5 | StartTransactionRequest, |
6 | StartTransactionResponse, | |
7 | StopTransactionReason, | |
8 | StopTransactionRequest, | |
9 | StopTransactionResponse, | |
10 | } from '../types/ocpp/Transaction'; | |
11 | import { | |
12 | BroadcastChannelProcedureName, | |
13 | BroadcastChannelRequest, | |
6c8f5d90 JB |
14 | BroadcastChannelRequestPayload, |
15 | BroadcastChannelResponsePayload, | |
16 | MessageEvent, | |
89b7a234 | 17 | } from '../types/WorkerBroadcastChannel'; |
6c8f5d90 JB |
18 | import { ResponseStatus } from '../ui/web/src/type/UIProtocol'; |
19 | import logger from '../utils/Logger'; | |
db2336d9 | 20 | import type ChargingStation from './ChargingStation'; |
1598b27c | 21 | import WorkerBroadcastChannel from './WorkerBroadcastChannel'; |
89b7a234 | 22 | |
4e3ff94d JB |
23 | const moduleName = 'ChargingStationWorkerBroadcastChannel'; |
24 | ||
6c8f5d90 | 25 | type CommandResponse = StartTransactionResponse | StopTransactionResponse; |
89b7a234 | 26 | |
1598b27c | 27 | export 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 | ||
4eca248c JB |
47 | if ( |
48 | requestPayload?.hashId === undefined && | |
49 | (requestPayload?.hashIds as string[])?.includes(this.chargingStation.hashId) === false | |
50 | ) { | |
89b7a234 JB |
51 | return; |
52 | } | |
4eca248c JB |
53 | if ( |
54 | requestPayload?.hashIds === undefined && | |
55 | requestPayload?.hashId !== this.chargingStation.hashId | |
56 | ) { | |
57 | return; | |
58 | } | |
59 | if (requestPayload?.hashId !== undefined) { | |
60 | logger.warn( | |
61 | `${this.chargingStation.logPrefix()} ${moduleName}.requestHandler: 'hashId' field usage in PDU is deprecated, use 'hashIds' instead` | |
62 | ); | |
63 | } | |
89b7a234 | 64 | |
6c8f5d90 JB |
65 | let responsePayload: BroadcastChannelResponsePayload; |
66 | let commandResponse: CommandResponse; | |
67 | try { | |
68 | commandResponse = await this.commandHandler(command, requestPayload); | |
69 | if (commandResponse === undefined) { | |
70 | responsePayload = { status: ResponseStatus.SUCCESS }; | |
71 | } else { | |
72 | responsePayload = { status: this.commandResponseToResponseStatus(commandResponse) }; | |
73 | } | |
74 | } catch (error) { | |
75 | logger.error( | |
76 | `${this.chargingStation.logPrefix()} ${moduleName}.requestHandler: Handle request error:`, | |
77 | error | |
78 | ); | |
79 | responsePayload = { | |
80 | status: ResponseStatus.FAILURE, | |
81 | command, | |
82 | requestPayload, | |
83 | commandResponse, | |
84 | errorMessage: (error as Error).message, | |
85 | errorStack: (error as Error).stack, | |
86 | }; | |
87 | } | |
88 | this.sendResponse([uuid, responsePayload]); | |
89 | } | |
90 | ||
91 | private messageErrorHandler(messageEvent: MessageEvent): void { | |
92 | logger.error( | |
93 | `${this.chargingStation.logPrefix()} ${moduleName}.messageErrorHandler: Error at handling message:`, | |
94 | { messageEvent, messageEventData: messageEvent.data } | |
95 | ); | |
96 | } | |
97 | ||
98 | private async commandHandler( | |
99 | command: BroadcastChannelProcedureName, | |
100 | requestPayload: BroadcastChannelRequestPayload | |
101 | ): Promise<CommandResponse | undefined> { | |
89b7a234 JB |
102 | switch (command) { |
103 | case BroadcastChannelProcedureName.START_TRANSACTION: | |
6c8f5d90 | 104 | return this.chargingStation.ocppRequestService.requestHandler< |
89b7a234 JB |
105 | StartTransactionRequest, |
106 | StartTransactionResponse | |
107 | >(this.chargingStation, RequestCommand.START_TRANSACTION, { | |
6c8f5d90 JB |
108 | connectorId: requestPayload.connectorId, |
109 | idTag: requestPayload.idTag, | |
89b7a234 | 110 | }); |
89b7a234 | 111 | case BroadcastChannelProcedureName.STOP_TRANSACTION: |
6c8f5d90 | 112 | return this.chargingStation.ocppRequestService.requestHandler< |
89b7a234 JB |
113 | StopTransactionRequest, |
114 | StopTransactionResponse | |
115 | >(this.chargingStation, RequestCommand.STOP_TRANSACTION, { | |
6c8f5d90 | 116 | transactionId: requestPayload.transactionId, |
89b7a234 | 117 | meterStop: this.chargingStation.getEnergyActiveImportRegisterByTransactionId( |
6c8f5d90 | 118 | requestPayload.transactionId |
89b7a234 | 119 | ), |
6c8f5d90 | 120 | idTag: this.chargingStation.getTransactionIdTag(requestPayload.transactionId), |
89b7a234 JB |
121 | reason: StopTransactionReason.NONE, |
122 | }); | |
89b7a234 JB |
123 | case BroadcastChannelProcedureName.START_CHARGING_STATION: |
124 | this.chargingStation.start(); | |
125 | break; | |
126 | case BroadcastChannelProcedureName.STOP_CHARGING_STATION: | |
127 | await this.chargingStation.stop(); | |
128 | break; | |
db2336d9 JB |
129 | case BroadcastChannelProcedureName.OPEN_CONNECTION: |
130 | this.chargingStation.openWSConnection(); | |
131 | break; | |
132 | case BroadcastChannelProcedureName.CLOSE_CONNECTION: | |
133 | this.chargingStation.closeWSConnection(); | |
134 | break; | |
6c8f5d90 JB |
135 | default: |
136 | // eslint-disable-next-line @typescript-eslint/restrict-template-expressions | |
ce7a4fc3 | 137 | throw new BaseError(`Unknown worker broadcast channel command: ${command}`); |
6c8f5d90 JB |
138 | } |
139 | } | |
140 | ||
141 | private commandResponseToResponseStatus(commandResponse: CommandResponse): ResponseStatus { | |
142 | if (commandResponse?.idTagInfo?.status === AuthorizationStatus.ACCEPTED) { | |
143 | return ResponseStatus.SUCCESS; | |
89b7a234 | 144 | } |
6c8f5d90 | 145 | return ResponseStatus.FAILURE; |
89b7a234 JB |
146 | } |
147 | } |