import { secondsToMilliseconds } from 'date-fns'
+import { isEmpty } from 'rambda'
-import { WorkerBroadcastChannel } from './WorkerBroadcastChannel.js'
import { BaseError, type OCPPError } from '../../exception/index.js'
import {
AuthorizationStatus,
type StopTransactionRequest,
type StopTransactionResponse
} from '../../types/index.js'
-import { Constants, convertToInt, isEmptyObject, logger } from '../../utils/index.js'
+import { Constants, convertToInt, isAsyncFunction, logger } from '../../utils/index.js'
import type { ChargingStation } from '../ChargingStation.js'
import { getConfigurationKey } from '../ConfigurationKeyUtils.js'
import { buildMeterValue } from '../ocpp/index.js'
+import { WorkerBroadcastChannel } from './WorkerBroadcastChannel.js'
const moduleName = 'ChargingStationWorkerBroadcastChannel'
type CommandHandler = (
requestPayload?: BroadcastChannelRequestPayload
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type
-) => Promise<CommandResponse | void> | void
+) => Promise<CommandResponse | void> | CommandResponse | void
export class ChargingStationWorkerBroadcastChannel extends WorkerBroadcastChannel {
private readonly commandHandlers: Map<BroadcastChannelProcedureName, CommandHandler>
await this.chargingStation.stop()
}
],
+ [
+ BroadcastChannelProcedureName.DELETE_CHARGING_STATIONS,
+ async (requestPayload?: BroadcastChannelRequestPayload) => {
+ await this.chargingStation.delete(requestPayload?.deleteConfiguration as boolean)
+ }
+ ],
[
BroadcastChannelProcedureName.OPEN_CONNECTION,
() => {
[
BroadcastChannelProcedureName.BOOT_NOTIFICATION,
async (requestPayload?: BroadcastChannelRequestPayload) => {
- this.chargingStation.bootNotificationResponse =
- await this.chargingStation.ocppRequestService.requestHandler<
- BootNotificationRequest,
- BootNotificationResponse
- >(
- this.chargingStation,
- RequestCommand.BOOT_NOTIFICATION,
- {
- ...this.chargingStation.bootNotificationRequest,
- ...requestPayload
- },
- {
- skipBufferingOnError: true,
- throwError: true
- }
- )
- return this.chargingStation.bootNotificationResponse
+ return await this.chargingStation.ocppRequestService.requestHandler<
+ BootNotificationRequest,
+ BootNotificationResponse
+ >(
+ this.chargingStation,
+ RequestCommand.BOOT_NOTIFICATION,
+ {
+ ...this.chargingStation.bootNotificationRequest,
+ ...requestPayload
+ },
+ {
+ skipBufferingOnError: true,
+ throwError: true
+ }
+ )
}
],
[
this.onmessageerror = this.messageErrorHandler.bind(this) as (message: unknown) => void
}
- private async requestHandler (messageEvent: MessageEvent): Promise<void> {
+ private requestHandler (messageEvent: MessageEvent): void {
const validatedMessageEvent = this.validateMessageEvent(messageEvent)
if (validatedMessageEvent === false) {
return
return
}
let responsePayload: BroadcastChannelResponsePayload | undefined
- // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
- let commandResponse: CommandResponse | void
- try {
- commandResponse = await this.commandHandler(command, requestPayload)
- if (commandResponse == null || isEmptyObject(commandResponse)) {
+ this.commandHandler(command, requestPayload)
+ .then(commandResponse => {
+ if (commandResponse == null || isEmpty(commandResponse)) {
+ responsePayload = {
+ hashId: this.chargingStation.stationInfo?.hashId,
+ status: ResponseStatus.SUCCESS
+ }
+ } else {
+ responsePayload = this.commandResponseToResponsePayload(
+ command,
+ requestPayload,
+ commandResponse
+ )
+ }
+ })
+ .catch((error: unknown) => {
+ logger.error(
+ `${this.chargingStation.logPrefix()} ${moduleName}.requestHandler: Handle request error:`,
+ error
+ )
responsePayload = {
hashId: this.chargingStation.stationInfo?.hashId,
- status: ResponseStatus.SUCCESS
- }
- } else {
- responsePayload = this.commandResponseToResponsePayload(
+ status: ResponseStatus.FAILURE,
command,
requestPayload,
- commandResponse
- )
- }
- } catch (error) {
- logger.error(
- `${this.chargingStation.logPrefix()} ${moduleName}.requestHandler: Handle request error:`,
- error
- )
- responsePayload = {
- hashId: this.chargingStation.stationInfo?.hashId,
- status: ResponseStatus.FAILURE,
- command,
- requestPayload,
+ errorMessage: (error as OCPPError).message,
+ errorStack: (error as OCPPError).stack,
+ errorDetails: (error as OCPPError).details
+ } satisfies BroadcastChannelResponsePayload
+ })
+ .finally(() => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- commandResponse: commandResponse!,
- errorMessage: (error as OCPPError).message,
- errorStack: (error as OCPPError).stack,
- errorDetails: (error as OCPPError).details
- }
- } finally {
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- this.sendResponse([uuid, responsePayload!])
- }
+ this.sendResponse([uuid, responsePayload!])
+ })
}
private messageErrorHandler (messageEvent: MessageEvent): void {
if (this.commandHandlers.has(command)) {
this.cleanRequestPayload(command, requestPayload)
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- return await this.commandHandlers.get(command)!(requestPayload)
+ const commandHandler = this.commandHandlers.get(command)!
+ if (isAsyncFunction(commandHandler)) {
+ return await commandHandler(requestPayload)
+ }
+ return (
+ commandHandler as (
+ requestPayload?: BroadcastChannelRequestPayload
+ // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
+ ) => CommandResponse | void
+ )(requestPayload)
}
throw new BaseError(`Unknown worker broadcast channel command: '${command}'`)
}
return ResponseStatus.FAILURE
case BroadcastChannelProcedureName.STATUS_NOTIFICATION:
case BroadcastChannelProcedureName.METER_VALUES:
- if (isEmptyObject(commandResponse)) {
+ if (isEmpty(commandResponse)) {
return ResponseStatus.SUCCESS
}
return ResponseStatus.FAILURE