From: Jérôme Benoit Date: Sat, 9 Mar 2024 20:50:20 +0000 (+0100) Subject: refactor: strong type UUID usage in UI protocol X-Git-Tag: v1.3.0~9 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=2c5c744359d7b1c65da4eb255db1d67da7b604f3;p=e-mobility-charging-stations-simulator.git refactor: strong type UUID usage in UI protocol Signed-off-by: Jérôme Benoit --- diff --git a/src/charging-station/ui-server/AbstractUIServer.ts b/src/charging-station/ui-server/AbstractUIServer.ts index 9056dc0d..b2a5b44e 100644 --- a/src/charging-station/ui-server/AbstractUIServer.ts +++ b/src/charging-station/ui-server/AbstractUIServer.ts @@ -27,7 +27,11 @@ export abstract class AbstractUIServer { public readonly chargingStations: Map public readonly chargingStationTemplates: Set protected readonly httpServer: Server | Http2Server - protected readonly responseHandlers: Map + protected readonly responseHandlers: Map< + `${string}-${string}-${string}-${string}-${string}`, + ServerResponse | WebSocket + > + protected readonly uiServices: Map public constructor (protected readonly uiServerConfiguration: UIServerConfiguration) { @@ -45,20 +49,26 @@ export abstract class AbstractUIServer { `Unsupported application protocol version ${this.uiServerConfiguration.version}` ) } - this.responseHandlers = new Map() + this.responseHandlers = new Map< + `${string}-${string}-${string}-${string}-${string}`, + ServerResponse | WebSocket + >() this.uiServices = new Map() } public buildProtocolRequest ( - id: string, + uuid: `${string}-${string}-${string}-${string}-${string}`, procedureName: ProcedureName, requestPayload: RequestPayload ): ProtocolRequest { - return [id, procedureName, requestPayload] + return [uuid, procedureName, requestPayload] } - public buildProtocolResponse (id: string, responsePayload: ResponsePayload): ProtocolResponse { - return [id, responsePayload] + public buildProtocolResponse ( + uuid: `${string}-${string}-${string}-${string}-${string}`, + responsePayload: ResponsePayload + ): ProtocolResponse { + return [uuid, responsePayload] } public stop (): void { @@ -82,8 +92,8 @@ export abstract class AbstractUIServer { ?.requestHandler(request) as Promise) } - public hasResponseHandler (id: string): boolean { - return this.responseHandlers.has(id) + public hasResponseHandler (uuid: `${string}-${string}-${string}-${string}-${string}`): boolean { + return this.responseHandlers.has(uuid) } protected startHttpServer (): void { diff --git a/src/charging-station/ui-server/ui-services/AbstractUIService.ts b/src/charging-station/ui-server/ui-services/AbstractUIService.ts index 07bb2cdb..204b5431 100644 --- a/src/charging-station/ui-server/ui-services/AbstractUIService.ts +++ b/src/charging-station/ui-server/ui-services/AbstractUIService.ts @@ -66,7 +66,10 @@ export abstract class AbstractUIService { private readonly version: ProtocolVersion private readonly uiServer: AbstractUIServer private readonly uiServiceWorkerBroadcastChannel: UIServiceWorkerBroadcastChannel - private readonly broadcastChannelRequests: Map + private readonly broadcastChannelRequests: Map< + `${string}-${string}-${string}-${string}-${string}`, + number + > constructor (uiServer: AbstractUIServer, version: ProtocolVersion) { this.uiServer = uiServer @@ -81,7 +84,10 @@ export abstract class AbstractUIService { [ProcedureName.STOP_SIMULATOR, this.handleStopSimulator.bind(this)] ]) this.uiServiceWorkerBroadcastChannel = new UIServiceWorkerBroadcastChannel(this) - this.broadcastChannelRequests = new Map() + this.broadcastChannelRequests = new Map< + `${string}-${string}-${string}-${string}-${string}`, + number + >() } public stop (): void { @@ -90,12 +96,12 @@ export abstract class AbstractUIService { } public async requestHandler (request: ProtocolRequest): Promise { - let messageId: string | undefined + let uuid: `${string}-${string}-${string}-${string}-${string}` | undefined let command: ProcedureName | undefined let requestPayload: RequestPayload | undefined let responsePayload: ResponsePayload | undefined try { - [messageId, command, requestPayload] = request + [uuid, command, requestPayload] = request if (!this.requestHandlers.has(command)) { throw new BaseError( @@ -111,7 +117,7 @@ export abstract class AbstractUIService { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const requestHandler = this.requestHandlers.get(command)! if (isAsyncFunction(requestHandler)) { - responsePayload = await requestHandler(messageId, command, requestPayload) + responsePayload = await requestHandler(uuid, command, requestPayload) } else { responsePayload = ( requestHandler as ( @@ -119,7 +125,7 @@ export abstract class AbstractUIService { procedureName?: ProcedureName, payload?: RequestPayload ) => undefined | ResponsePayload - )(messageId, command, requestPayload) + )(uuid, command, requestPayload) } } catch (error) { // Log @@ -137,23 +143,26 @@ export abstract class AbstractUIService { } if (responsePayload != null) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - return this.uiServer.buildProtocolResponse(messageId!, responsePayload) + return this.uiServer.buildProtocolResponse(uuid!, responsePayload) } } // public sendRequest ( - // messageId: string, + // uuid: `${string}-${string}-${string}-${string}-${string}`, // procedureName: ProcedureName, // requestPayload: RequestPayload // ): void { // this.uiServer.sendRequest( - // this.uiServer.buildProtocolRequest(messageId, procedureName, requestPayload) + // this.uiServer.buildProtocolRequest(uuid, procedureName, requestPayload) // ) // } - public sendResponse (messageId: string, responsePayload: ResponsePayload): void { - if (this.uiServer.hasResponseHandler(messageId)) { - this.uiServer.sendResponse(this.uiServer.buildProtocolResponse(messageId, responsePayload)) + public sendResponse ( + uuid: `${string}-${string}-${string}-${string}-${string}`, + responsePayload: ResponsePayload + ): void { + if (this.uiServer.hasResponseHandler(uuid)) { + this.uiServer.sendResponse(this.uiServer.buildProtocolResponse(uuid, responsePayload)) } } @@ -161,17 +170,21 @@ export abstract class AbstractUIService { return this.uiServer.logPrefix(modName, methodName, this.version) } - public deleteBroadcastChannelRequest (uuid: string): void { + public deleteBroadcastChannelRequest ( + uuid: `${string}-${string}-${string}-${string}-${string}` + ): void { this.broadcastChannelRequests.delete(uuid) } - public getBroadcastChannelExpectedResponses (uuid: string): number { + public getBroadcastChannelExpectedResponses ( + uuid: `${string}-${string}-${string}-${string}-${string}` + ): number { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion return this.broadcastChannelRequests.get(uuid)! } protected handleProtocolRequest ( - uuid: string, + uuid: `${string}-${string}-${string}-${string}-${string}`, procedureName: ProcedureName, payload: RequestPayload ): void { @@ -184,7 +197,7 @@ export abstract class AbstractUIService { } private sendBroadcastChannelRequest ( - uuid: string, + uuid: `${string}-${string}-${string}-${string}-${string}`, procedureName: BroadcastChannelProcedureName, payload: BroadcastChannelRequestPayload ): void { @@ -233,7 +246,7 @@ export abstract class AbstractUIService { } private async handleAddChargingStations ( - _messageId?: string, + _uuid?: `${string}-${string}-${string}-${string}-${string}`, _procedureName?: ProcedureName, requestPayload?: RequestPayload ): Promise { diff --git a/src/types/UIProtocol.ts b/src/types/UIProtocol.ts index b1b71b73..f53696da 100644 --- a/src/types/UIProtocol.ts +++ b/src/types/UIProtocol.ts @@ -19,11 +19,18 @@ export enum ProtocolVersion { '0.0.1' = '0.0.1' } -export type ProtocolRequest = [string, ProcedureName, RequestPayload] -export type ProtocolResponse = [string, ResponsePayload] +export type ProtocolRequest = [ + `${string}-${string}-${string}-${string}-${string}`, + ProcedureName, + RequestPayload +] +export type ProtocolResponse = [ + `${string}-${string}-${string}-${string}-${string}`, + ResponsePayload +] export type ProtocolRequestHandler = ( - uuid?: string, + uuid?: `${string}-${string}-${string}-${string}-${string}`, procedureName?: ProcedureName, payload?: RequestPayload ) => undefined | Promise | ResponsePayload | Promise diff --git a/src/types/WorkerBroadcastChannel.ts b/src/types/WorkerBroadcastChannel.ts index caa56e9f..077c2f37 100644 --- a/src/types/WorkerBroadcastChannel.ts +++ b/src/types/WorkerBroadcastChannel.ts @@ -1,11 +1,14 @@ import type { RequestPayload, ResponsePayload } from './UIProtocol.js' export type BroadcastChannelRequest = [ - string, + `${string}-${string}-${string}-${string}-${string}`, BroadcastChannelProcedureName, BroadcastChannelRequestPayload ] -export type BroadcastChannelResponse = [string, BroadcastChannelResponsePayload] +export type BroadcastChannelResponse = [ + `${string}-${string}-${string}-${string}-${string}`, + BroadcastChannelResponsePayload +] export enum BroadcastChannelProcedureName { START_CHARGING_STATION = 'startChargingStation', diff --git a/src/utils/Utils.ts b/src/utils/Utils.ts index c021cadb..69f0cd42 100644 --- a/src/utils/Utils.ts +++ b/src/utils/Utils.ts @@ -25,11 +25,13 @@ export const logPrefix = (prefixString = ''): string => { return `${new Date().toLocaleString()}${prefixString}` } -export const generateUUID = (): string => { +export const generateUUID = (): `${string}-${string}-${string}-${string}-${string}` => { return randomUUID() } -export const validateUUID = (uuid: string): boolean => { +export const validateUUID = ( + uuid: `${string}-${string}-${string}-${string}-${string}` +): uuid is `${string}-${string}-${string}-${string}-${string}` => { return /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(uuid) } @@ -263,7 +265,7 @@ export const isNotEmptyString = (value: unknown): value is string => { return isString(value) && value.trim().length > 0 } -export const isEmptyArray = (value: unknown): value is never[] => { +export const isEmptyArray = (value: unknown): value is [] => { return Array.isArray(value) && value.length === 0 } diff --git a/ui/web/src/composables/UIClient.ts b/ui/web/src/composables/UIClient.ts index 64f2bc69..781854db 100644 --- a/ui/web/src/composables/UIClient.ts +++ b/ui/web/src/composables/UIClient.ts @@ -24,11 +24,17 @@ export class UIClient { private static instance: UIClient | null = null private ws?: WebSocket - private responseHandlers: Map + private responseHandlers: Map< + `${string}-${string}-${string}-${string}-${string}`, + ResponseHandler + > private constructor(private uiServerConfiguration: UIServerConfigurationSection) { this.openWS() - this.responseHandlers = new Map() + this.responseHandlers = new Map< + `${string}-${string}-${string}-${string}-${string}`, + ResponseHandler + >() } public static getInstance(uiServerConfiguration?: UIServerConfigurationSection): UIClient { @@ -230,15 +236,24 @@ export class UIClient { } private responseHandler(messageEvent: MessageEvent): void { - const response = JSON.parse(messageEvent.data) as ProtocolResponse + let response: ProtocolResponse + try { + response = JSON.parse(messageEvent.data) as ProtocolResponse + } catch (error) { + useToast().error('Invalid response format') + console.error('Invalid response format', error) + return + } - if (Array.isArray(response) === false) { - throw new Error(`Response not an array: ${JSON.stringify(response, undefined, 2)}`) + if (!Array.isArray(response)) { + useToast().error(`Response not an array`) + console.error(`Response not an array:`, response) + return } const [uuid, responsePayload] = response - if (this.responseHandlers.has(uuid) === true) { + if (this.responseHandlers.has(uuid)) { const { procedureName, resolve, reject } = this.responseHandlers.get(uuid)! switch (responsePayload.status) { case ResponseStatus.SUCCESS: diff --git a/ui/web/src/types/UIProtocol.ts b/ui/web/src/types/UIProtocol.ts index 5b3efcdc..8522aa11 100644 --- a/ui/web/src/types/UIProtocol.ts +++ b/ui/web/src/types/UIProtocol.ts @@ -17,8 +17,15 @@ export enum AuthenticationType { PROTOCOL_BASIC_AUTH = 'protocol-basic-auth' } -export type ProtocolRequest = [string, ProcedureName, RequestPayload] -export type ProtocolResponse = [string, ResponsePayload] +export type ProtocolRequest = [ + `${string}-${string}-${string}-${string}-${string}`, + ProcedureName, + RequestPayload +] +export type ProtocolResponse = [ + `${string}-${string}-${string}-${string}-${string}`, + ResponsePayload +] export type ProtocolRequestHandler = ( payload: RequestPayload