Merge branch 'main' of github.com:SAP/e-mobility-charging-stations-simulator
[e-mobility-charging-stations-simulator.git] / src / charging-station / UIServiceWorkerBroadcastChannel.ts
index d50d514a469496159b5aad15f752bde3c3a0d031..5f77b0e3450768bc79a87cacbfa744e77c3f268b 100644 (file)
-import { BroadcastChannelResponse, MessageEvent } from '../types/WorkerBroadcastChannel';
-import logger from '../utils/Logger';
-import type AbstractUIService from './ui-server/ui-services/AbstractUIService';
-import WorkerBroadcastChannel from './WorkerBroadcastChannel';
+import { type AbstractUIService, WorkerBroadcastChannel } from './internal';
+import {
+  type BroadcastChannelResponse,
+  type BroadcastChannelResponsePayload,
+  type MessageEvent,
+  type ResponsePayload,
+  ResponseStatus,
+} from '../types';
+import { Utils, logger } from '../utils';
 
 const moduleName = 'UIServiceWorkerBroadcastChannel';
 
-export default class UIServiceWorkerBroadcastChannel extends WorkerBroadcastChannel {
-  private uiService: AbstractUIService;
+type Responses = {
+  responsesExpected: number;
+  responsesReceived: number;
+  responses: BroadcastChannelResponsePayload[];
+};
+
+export class UIServiceWorkerBroadcastChannel extends WorkerBroadcastChannel {
+  private readonly uiService: AbstractUIService;
+  private readonly responses: Map<string, Responses>;
 
   constructor(uiService: AbstractUIService) {
     super();
     this.uiService = uiService;
     this.onmessage = this.responseHandler.bind(this) as (message: MessageEvent) => void;
     this.onmessageerror = this.messageErrorHandler.bind(this) as (message: MessageEvent) => void;
+    this.responses = new Map<string, Responses>();
   }
 
   private responseHandler(messageEvent: MessageEvent): void {
-    if (this.isRequest(messageEvent.data)) {
+    const validatedMessageEvent = this.validateMessageEvent(messageEvent);
+    if (validatedMessageEvent === false) {
+      return;
+    }
+    if (this.isRequest(validatedMessageEvent.data) === true) {
       return;
     }
-    const [uuid, responsePayload] = messageEvent.data as BroadcastChannelResponse;
+    const [uuid, responsePayload] = validatedMessageEvent.data as BroadcastChannelResponse;
+    if (this.responses.has(uuid) === false) {
+      this.responses.set(uuid, {
+        responsesExpected: this.uiService.getBroadcastChannelExpectedResponses(uuid),
+        responsesReceived: 1,
+        responses: [responsePayload],
+      });
+    } else if (
+      this.responses.get(uuid)?.responsesReceived <= this.responses.get(uuid)?.responsesExpected
+    ) {
+      this.responses.get(uuid).responsesReceived++;
+      this.responses.get(uuid)?.responses.push(responsePayload);
+    }
+    if (
+      this.responses.get(uuid)?.responsesReceived === this.responses.get(uuid)?.responsesExpected
+    ) {
+      this.uiService.sendResponse(uuid, this.buildResponsePayload(uuid));
+      this.responses.delete(uuid);
+      this.uiService.deleteBroadcastChannelRequest(uuid);
+    }
+  }
 
-    this.uiService.sendResponse(uuid, responsePayload);
+  private buildResponsePayload(uuid: string): ResponsePayload {
+    const responsesStatus =
+      this.responses
+        .get(uuid)
+        ?.responses.every(({ status }) => status === ResponseStatus.SUCCESS) === true
+        ? ResponseStatus.SUCCESS
+        : ResponseStatus.FAILURE;
+    return {
+      status: responsesStatus,
+      hashIdsSucceeded: this.responses
+        .get(uuid)
+        ?.responses.filter(({ hashId }) => !Utils.isNullOrUndefined(hashId))
+        .map(({ status, hashId }) => {
+          if (status === ResponseStatus.SUCCESS) {
+            return hashId;
+          }
+        }),
+      ...(responsesStatus === ResponseStatus.FAILURE && {
+        hashIdsFailed: this.responses
+          .get(uuid)
+          ?.responses.filter(({ hashId }) => !Utils.isNullOrUndefined(hashId))
+          .map(({ status, hashId }) => {
+            if (status === ResponseStatus.FAILURE) {
+              return hashId;
+            }
+          }),
+      }),
+      ...(responsesStatus === ResponseStatus.FAILURE && {
+        responsesFailed: this.responses
+          .get(uuid)
+          ?.responses.filter((response) => !Utils.isNullOrUndefined(response))
+          .map((response) => {
+            if (response.status === ResponseStatus.FAILURE) {
+              return response;
+            }
+          }),
+      }),
+    };
   }
 
   private messageErrorHandler(messageEvent: MessageEvent): void {
     logger.error(
       `${this.uiService.logPrefix(moduleName, 'messageErrorHandler')} Error at handling message:`,
-      { messageEvent, messageEventData: messageEvent.data }
+      messageEvent
     );
   }
 }