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