README.md: document added UI protocol features
[e-mobility-charging-stations-simulator.git] / src / charging-station / UIServiceWorkerBroadcastChannel.ts
CommitLineData
0d2cec76
JB
1import { ResponsePayload, ResponseStatus } from '../types/UIProtocol';
2import type {
3 BroadcastChannelResponse,
4 BroadcastChannelResponsePayload,
5 MessageEvent,
6} from '../types/WorkerBroadcastChannel';
6c8f5d90 7import logger from '../utils/Logger';
db2336d9 8import type AbstractUIService from './ui-server/ui-services/AbstractUIService';
6c8f5d90
JB
9import WorkerBroadcastChannel from './WorkerBroadcastChannel';
10
11const moduleName = 'UIServiceWorkerBroadcastChannel';
12
0d2cec76
JB
13type Responses = {
14 responsesExpected: number;
15 responsesReceived: number;
16 responses: BroadcastChannelResponsePayload[];
17};
18
6c8f5d90 19export default class UIServiceWorkerBroadcastChannel extends WorkerBroadcastChannel {
0d2cec76 20 private readonly uiService: AbstractUIService;
53870cff 21 private readonly responses: Map<string, Responses>;
6c8f5d90
JB
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;
0d2cec76 28 this.responses = new Map<string, Responses>();
6c8f5d90
JB
29 }
30
31 private responseHandler(messageEvent: MessageEvent): void {
32 if (this.isRequest(messageEvent.data)) {
33 return;
34 }
852a4c5f 35 this.validateMessageEvent(messageEvent);
6c8f5d90 36 const [uuid, responsePayload] = messageEvent.data as BroadcastChannelResponse;
0d2cec76
JB
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 + 1 <
45 this.responses.get(uuid)?.responsesExpected
46 ) {
47 this.responses.get(uuid).responsesReceived++;
48 this.responses.get(uuid).responses.push(responsePayload);
49 } else if (
50 this.responses.get(uuid)?.responsesReceived + 1 ===
51 this.responses.get(uuid)?.responsesExpected
52 ) {
53 this.responses.get(uuid).responses.push(responsePayload);
54 this.uiService.sendResponse(uuid, this.buildResponsePayload(uuid));
55 this.responses.delete(uuid);
56 this.uiService.deleteBroadcastChannelRequest(uuid);
57 }
58 }
6c8f5d90 59
0d2cec76
JB
60 private buildResponsePayload(uuid: string): ResponsePayload {
61 const responsesStatus = this.responses
62 .get(uuid)
63 ?.responses.every((response) => response.status === ResponseStatus.SUCCESS)
64 ? ResponseStatus.SUCCESS
65 : ResponseStatus.FAILURE;
66 return {
67 status: responsesStatus,
68 hashIdsSucceeded: this.responses
69 .get(uuid)
70 ?.responses.map(({ status, hashId }) => {
71 if (status === ResponseStatus.SUCCESS) {
72 return hashId;
73 }
74 })
75 .filter((hashId) => hashId !== undefined),
76 ...(responsesStatus === ResponseStatus.FAILURE && {
77 hashIdsFailed: this.responses
78 .get(uuid)
79 ?.responses.map(({ status, hashId }) => {
80 if (status === ResponseStatus.FAILURE) {
81 return hashId;
82 }
83 })
84 .filter((hashId) => hashId !== undefined),
85 }),
86 };
6c8f5d90
JB
87 }
88
89 private messageErrorHandler(messageEvent: MessageEvent): void {
90 logger.error(
91 `${this.uiService.logPrefix(moduleName, 'messageErrorHandler')} Error at handling message:`,
92 { messageEvent, messageEventData: messageEvent.data }
93 );
94 }
95}