e7615e611e30f3b7f895bb06caf14dff79fe0645
[e-mobility-charging-stations-simulator.git] / src / charging-station / UIServiceWorkerBroadcastChannel.ts
1 import { ResponsePayload, ResponseStatus } from '../types/UIProtocol';
2 import type {
3 BroadcastChannelResponse,
4 BroadcastChannelResponsePayload,
5 MessageEvent,
6 } from '../types/WorkerBroadcastChannel';
7 import logger from '../utils/Logger';
8 import type AbstractUIService from './ui-server/ui-services/AbstractUIService';
9 import WorkerBroadcastChannel from './WorkerBroadcastChannel';
10
11 const moduleName = 'UIServiceWorkerBroadcastChannel';
12
13 type Responses = {
14 responsesExpected: number;
15 responsesReceived: number;
16 responses: BroadcastChannelResponsePayload[];
17 };
18
19 export default class UIServiceWorkerBroadcastChannel extends WorkerBroadcastChannel {
20 private readonly uiService: AbstractUIService;
21 private readonly responses: Map<string, Responses>;
22
23 constructor(uiService: AbstractUIService) {
24 super();
25 this.uiService = uiService;
26 this.onmessage = this.responseHandler.bind(this) as (message: MessageEvent) => void;
27 this.onmessageerror = this.messageErrorHandler.bind(this) as (message: MessageEvent) => void;
28 this.responses = new Map<string, Responses>();
29 }
30
31 private responseHandler(messageEvent: MessageEvent): void {
32 if (this.isRequest(messageEvent.data)) {
33 return;
34 }
35 const [uuid, responsePayload] = this.validateMessageEvent(messageEvent)
36 .data as BroadcastChannelResponse;
37 if (this.responses.has(uuid) === false) {
38 this.responses.set(uuid, {
39 responsesExpected: this.uiService.getBroadcastChannelExpectedResponses(uuid),
40 responsesReceived: 1,
41 responses: [responsePayload],
42 });
43 } else if (
44 this.responses.get(uuid)?.responsesReceived <= this.responses.get(uuid)?.responsesExpected
45 ) {
46 this.responses.get(uuid).responsesReceived++;
47 this.responses.get(uuid).responses.push(responsePayload);
48 }
49 if (
50 this.responses.get(uuid)?.responsesReceived === this.responses.get(uuid)?.responsesExpected
51 ) {
52 this.uiService.sendResponse(uuid, this.buildResponsePayload(uuid));
53 this.responses.delete(uuid);
54 this.uiService.deleteBroadcastChannelRequest(uuid);
55 }
56 }
57
58 private buildResponsePayload(uuid: string): ResponsePayload {
59 const responsesStatus = this.responses
60 .get(uuid)
61 ?.responses.every((response) => response.status === ResponseStatus.SUCCESS)
62 ? ResponseStatus.SUCCESS
63 : ResponseStatus.FAILURE;
64 return {
65 status: responsesStatus,
66 hashIdsSucceeded: this.responses
67 .get(uuid)
68 ?.responses.map(({ status, hashId }) => {
69 if (status === ResponseStatus.SUCCESS) {
70 return hashId;
71 }
72 })
73 .filter((hashId) => hashId !== undefined),
74 ...(responsesStatus === ResponseStatus.FAILURE && {
75 hashIdsFailed: this.responses
76 .get(uuid)
77 ?.responses.map(({ status, hashId }) => {
78 if (status === ResponseStatus.FAILURE) {
79 return hashId;
80 }
81 })
82 .filter((hashId) => hashId !== undefined),
83 }),
84 };
85 }
86
87 private messageErrorHandler(messageEvent: MessageEvent): void {
88 logger.error(
89 `${this.uiService.logPrefix(moduleName, 'messageErrorHandler')} Error at handling message:`,
90 { messageEvent }
91 );
92 }
93 }