fix: ensure no null serialized values end in UI server response payload
[e-mobility-charging-stations-simulator.git] / src / charging-station / broadcast-channel / UIServiceWorkerBroadcastChannel.ts
CommitLineData
4c3c0d59 1import { WorkerBroadcastChannel } from './WorkerBroadcastChannel';
268a74bb
JB
2import {
3 type BroadcastChannelResponse,
4 type BroadcastChannelResponsePayload,
5 type MessageEvent,
6 type ResponsePayload,
7 ResponseStatus,
7671fa0b 8} from '../../types';
9bf0ef23 9import { isNullOrUndefined, logger } from '../../utils';
7671fa0b 10import type { AbstractUIService } from '../ui-server/ui-services/AbstractUIService';
6c8f5d90
JB
11
12const moduleName = 'UIServiceWorkerBroadcastChannel';
13
e1d9a0f4 14interface Responses {
0d2cec76
JB
15 responsesExpected: number;
16 responsesReceived: number;
17 responses: BroadcastChannelResponsePayload[];
e1d9a0f4 18}
0d2cec76 19
268a74bb 20export class UIServiceWorkerBroadcastChannel extends WorkerBroadcastChannel {
0d2cec76 21 private readonly uiService: AbstractUIService;
53870cff 22 private readonly responses: Map<string, Responses>;
6c8f5d90
JB
23
24 constructor(uiService: AbstractUIService) {
25 super();
26 this.uiService = uiService;
a37fc6dc
JB
27 this.onmessage = this.responseHandler.bind(this) as (message: unknown) => void;
28 this.onmessageerror = this.messageErrorHandler.bind(this) as (message: unknown) => void;
0d2cec76 29 this.responses = new Map<string, Responses>();
6c8f5d90
JB
30 }
31
32 private responseHandler(messageEvent: MessageEvent): void {
5dea4c94
JB
33 const validatedMessageEvent = this.validateMessageEvent(messageEvent);
34 if (validatedMessageEvent === false) {
6c8f5d90
JB
35 return;
36 }
5dea4c94
JB
37 if (this.isRequest(validatedMessageEvent.data) === true) {
38 return;
39 }
40 const [uuid, responsePayload] = validatedMessageEvent.data as BroadcastChannelResponse;
0d2cec76
JB
41 if (this.responses.has(uuid) === false) {
42 this.responses.set(uuid, {
43 responsesExpected: this.uiService.getBroadcastChannelExpectedResponses(uuid),
44 responsesReceived: 1,
45 responses: [responsePayload],
46 });
47 } else if (
e1d9a0f4 48 this.responses.get(uuid)!.responsesReceived <= this.responses.get(uuid)!.responsesExpected
0d2cec76 49 ) {
e1d9a0f4 50 ++this.responses.get(uuid)!.responsesReceived;
72092cfc 51 this.responses.get(uuid)?.responses.push(responsePayload);
6d9876e7
JB
52 }
53 if (
54 this.responses.get(uuid)?.responsesReceived === this.responses.get(uuid)?.responsesExpected
0d2cec76 55 ) {
0d2cec76
JB
56 this.uiService.sendResponse(uuid, this.buildResponsePayload(uuid));
57 this.responses.delete(uuid);
58 this.uiService.deleteBroadcastChannelRequest(uuid);
59 }
60 }
6c8f5d90 61
0d2cec76 62 private buildResponsePayload(uuid: string): ResponsePayload {
c56450e3
JB
63 const responsesStatus =
64 this.responses
65 .get(uuid)
66 ?.responses.every(({ status }) => status === ResponseStatus.SUCCESS) === true
67 ? ResponseStatus.SUCCESS
68 : ResponseStatus.FAILURE;
0d2cec76
JB
69 return {
70 status: responsesStatus,
71 hashIdsSucceeded: this.responses
72 .get(uuid)
31fdd918
JB
73 ?.responses.map(({ status, hashId }) => {
74 if (hashId !== undefined && status === ResponseStatus.SUCCESS) {
0d2cec76
JB
75 return hashId;
76 }
31fdd918
JB
77 })
78 .filter((hashId) => !isNullOrUndefined(hashId)) as string[],
0d2cec76
JB
79 ...(responsesStatus === ResponseStatus.FAILURE && {
80 hashIdsFailed: this.responses
81 .get(uuid)
31fdd918
JB
82 ?.responses.map(({ status, hashId }) => {
83 if (hashId !== undefined && status === ResponseStatus.FAILURE) {
0d2cec76
JB
84 return hashId;
85 }
31fdd918
JB
86 })
87 .filter((hashId) => !isNullOrUndefined(hashId)) as string[],
0d2cec76 88 }),
f53c88d0
JB
89 ...(responsesStatus === ResponseStatus.FAILURE && {
90 responsesFailed: this.responses
91 .get(uuid)
31fdd918
JB
92 ?.responses.map((response) => {
93 if (response !== undefined && response.status === ResponseStatus.FAILURE) {
f53c88d0
JB
94 return response;
95 }
31fdd918
JB
96 })
97 .filter((response) => !isNullOrUndefined(response)) as BroadcastChannelResponsePayload[],
f53c88d0 98 }),
0d2cec76 99 };
6c8f5d90
JB
100 }
101
102 private messageErrorHandler(messageEvent: MessageEvent): void {
103 logger.error(
104 `${this.uiService.logPrefix(moduleName, 'messageErrorHandler')} Error at handling message:`,
5edd8ba0 105 messageEvent,
6c8f5d90
JB
106 );
107 }
108}