X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=ui%2Fweb%2Fsrc%2Fcomposables%2FUIClient.ts;h=9522c59213c666a526d48927447024f3e8fc065a;hb=7445d18b9b9ac750b9dc3dc3638d4fd0e8aff818;hp=963e0e4b868d2a577f8d92f3a83d8f9c987d83c1;hpb=182f84679517c8be5ebfa7b84a89fff6e355a415;p=e-mobility-charging-stations-simulator.git diff --git a/ui/web/src/composables/UIClient.ts b/ui/web/src/composables/UIClient.ts index 963e0e4b..9522c592 100644 --- a/ui/web/src/composables/UIClient.ts +++ b/ui/web/src/composables/UIClient.ts @@ -1,4 +1,5 @@ import { useToast } from 'vue-toast-notification' + import { ApplicationProtocol, AuthenticationType, @@ -11,6 +12,8 @@ import { type UIServerConfigurationSection } from '@/types' +import { randomUUID, validateUUID } from './Utils' + type ResponseHandler = { procedureName: ProcedureName resolve: (value: ResponsePayload | PromiseLike) => void @@ -20,32 +23,57 @@ type ResponseHandler = { export class UIClient { private static instance: UIClient | null = null - private ws!: WebSocket - private responseHandlers: Map + private ws?: WebSocket + 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 { + public static getInstance(uiServerConfiguration?: UIServerConfigurationSection): UIClient { if (UIClient.instance === null) { + if (uiServerConfiguration == null) { + throw new Error('Cannot initialize UIClient if no configuration is provided') + } UIClient.instance = new UIClient(uiServerConfiguration) } return UIClient.instance } public setConfiguration(uiServerConfiguration: UIServerConfigurationSection): void { - this.ws.close() + if (this.ws?.readyState === WebSocket.OPEN) { + this.ws.close() + delete this.ws + } this.uiServerConfiguration = uiServerConfiguration this.openWS() } public registerWSEventListener( event: K, - listener: (event: WebSocketEventMap[K]) => void + listener: (event: WebSocketEventMap[K]) => void, + options?: boolean | AddEventListenerOptions ) { - this.ws.addEventListener(event, listener) + this.ws?.addEventListener(event, listener, options) + } + + public unregisterWSEventListener( + event: K, + listener: (event: WebSocketEventMap[K]) => void, + options?: boolean | AddEventListenerOptions + ) { + this.ws?.removeEventListener(event, listener, options) + } + + public async simulatorState(): Promise { + return this.sendRequest(ProcedureName.SIMULATOR_STATE, {}) } public async startSimulator(): Promise { @@ -185,8 +213,8 @@ export class UIClient { payload: RequestPayload ): Promise { return new Promise((resolve, reject) => { - if (this.ws.readyState === WebSocket.OPEN) { - const uuid = crypto.randomUUID() + if (this.ws?.readyState === WebSocket.OPEN) { + const uuid = randomUUID() const msg = JSON.stringify([uuid, procedureName, payload]) const sendTimeout = setTimeout(() => { this.responseHandlers.delete(uuid) @@ -208,15 +236,30 @@ 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) + } catch (error) { + useToast().error('Invalid response JSON format') + console.error('Invalid response JSON 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 (!validateUUID(uuid)) { + useToast().error('Response UUID field is invalid') + console.error('Response UUID field is invalid:', response) + return + } + + if (this.responseHandlers.has(uuid)) { const { procedureName, resolve, reject } = this.responseHandlers.get(uuid)! switch (responsePayload.status) { case ResponseStatus.SUCCESS: