chore(deps-dev): apply updates
[e-mobility-charging-stations-simulator.git] / src / charging-station / broadcast-channel / UIServiceWorkerBroadcastChannel.ts
... / ...
CommitLineData
1import type { AbstractUIService } from '../ui-server/ui-services/AbstractUIService.js'
2
3import {
4 type BroadcastChannelResponse,
5 type BroadcastChannelResponsePayload,
6 type MessageEvent,
7 type ResponsePayload,
8 ResponseStatus,
9} from '../../types/index.js'
10import { logger } from '../../utils/index.js'
11import { WorkerBroadcastChannel } from './WorkerBroadcastChannel.js'
12
13const moduleName = 'UIServiceWorkerBroadcastChannel'
14
15interface Responses {
16 responses: BroadcastChannelResponsePayload[]
17 responsesExpected: number
18 responsesReceived: number
19}
20
21export class UIServiceWorkerBroadcastChannel extends WorkerBroadcastChannel {
22 private readonly responses: Map<string, Responses>
23 private readonly uiService: AbstractUIService
24
25 constructor (uiService: AbstractUIService) {
26 super()
27 this.uiService = uiService
28 this.onmessage = this.responseHandler.bind(this) as (message: unknown) => void
29 this.onmessageerror = this.messageErrorHandler.bind(this) as (message: unknown) => void
30 this.responses = new Map<string, Responses>()
31 }
32
33 private buildResponsePayload (uuid: string): ResponsePayload {
34 const responsesStatus =
35 this.responses
36 .get(uuid)
37 ?.responses.every(({ status }) => status === ResponseStatus.SUCCESS) === true
38 ? ResponseStatus.SUCCESS
39 : ResponseStatus.FAILURE
40 return {
41 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain
42 hashIdsSucceeded: this.responses
43 .get(uuid)
44 ?.responses.map(({ hashId, status }) => {
45 if (hashId != null && status === ResponseStatus.SUCCESS) {
46 return hashId
47 }
48 return undefined
49 })
50 .filter(hashId => hashId != null)!,
51 status: responsesStatus,
52 ...(responsesStatus === ResponseStatus.FAILURE && {
53 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain
54 hashIdsFailed: this.responses
55 .get(uuid)
56 ?.responses.map(({ hashId, status }) => {
57 if (hashId != null && status === ResponseStatus.FAILURE) {
58 return hashId
59 }
60 return undefined
61 })
62 .filter(hashId => hashId != null)!,
63 }),
64 ...(responsesStatus === ResponseStatus.FAILURE && {
65 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain
66 responsesFailed: this.responses
67 .get(uuid)
68 ?.responses.map(response => {
69 if (response.status === ResponseStatus.FAILURE) {
70 return response
71 }
72 return undefined
73 })
74 .filter(response => response != null)!,
75 }),
76 }
77 }
78
79 private messageErrorHandler (messageEvent: MessageEvent): void {
80 logger.error(
81 `${this.uiService.logPrefix(moduleName, 'messageErrorHandler')} Error at handling message:`,
82 messageEvent
83 )
84 }
85
86 private responseHandler (messageEvent: MessageEvent): void {
87 const validatedMessageEvent = this.validateMessageEvent(messageEvent)
88 if (validatedMessageEvent === false) {
89 return
90 }
91 if (this.isRequest(validatedMessageEvent.data)) {
92 return
93 }
94 const [uuid, responsePayload] = validatedMessageEvent.data as BroadcastChannelResponse
95 if (!this.responses.has(uuid)) {
96 this.responses.set(uuid, {
97 responses: [responsePayload],
98 responsesExpected: this.uiService.getBroadcastChannelExpectedResponses(uuid),
99 responsesReceived: 1,
100 })
101 } else if (
102 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
103 this.responses.get(uuid)!.responsesReceived <= this.responses.get(uuid)!.responsesExpected
104 ) {
105 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
106 ++this.responses.get(uuid)!.responsesReceived
107 this.responses.get(uuid)?.responses.push(responsePayload)
108 }
109 if (
110 this.responses.get(uuid)?.responsesReceived === this.responses.get(uuid)?.responsesExpected
111 ) {
112 this.uiService.sendResponse(uuid, this.buildResponsePayload(uuid))
113 this.responses.delete(uuid)
114 this.uiService.deleteBroadcastChannelRequest(uuid)
115 }
116 }
117}