Merge branch 'feat/inda-383-daily-stat' into 'main'
[ProtonMail-WebClient.git] / packages / docs-core / lib / Bridge / ClientToEditorBridge.ts
blobea5279569ad09e881e8090f101ac6662d2da15d5
1 import type {
2   EditorToClientGenericMessage,
3   EditorToClientInvokationMessage,
4   EditorToClientReplyMessage,
5   ClientToEditorReplyMessage,
6   EditorRequiresClientMethods,
7   InternalEventBusInterface,
8   SyncedEditorState,
9 } from '@proton/docs-shared'
10 import { EditorBridgeMessageType, BridgeOriginProvider, DOCS_EDITOR_DEBUG_KEY } from '@proton/docs-shared'
11 import { EditorInvoker } from './EditorInvoker'
12 import { EditorToClientRequestHandler } from './EditorToClientRequestHandler'
13 import { Logger } from '@proton/utils/logs'
14 import type { EditorOrchestratorInterface } from '../Services/Orchestrator/EditorOrchestratorInterface'
16 export class ClientToEditorBridge {
17   public readonly logger = new Logger('DocsClient', DOCS_EDITOR_DEBUG_KEY)
18   public readonly editorInvoker = new EditorInvoker(this.editorFrame, this.logger)
19   private editorRequestHandler: EditorToClientRequestHandler
21   constructor(
22     private editorFrame: HTMLIFrameElement,
23     private readonly editorController: EditorOrchestratorInterface,
24     private readonly eventBus: InternalEventBusInterface,
25     private readonly syncedEditorState?: SyncedEditorState,
26   ) {
27     this.editorRequestHandler = new EditorToClientRequestHandler(this.editorFrame, this.editorController, this.eventBus)
29     this.syncedEditorState?.subscribeToAnyProperty((property, value) => {
30       void this.editorInvoker.syncProperty(property, value)
31     })
33     window.addEventListener('message', (event) => {
34       if (event.source !== this.editorFrame.contentWindow) {
35         this.logger.info('Client ignoring message from unknown source', event.data)
36         return
37       }
39       const message = event.data as EditorToClientGenericMessage
41       this.logger.debug('Received message data from editor', message)
43       if (message.type === EditorBridgeMessageType.EditorToClientInvokation) {
44         void this.handleEditorRequestingClientMethod(
45           message as EditorToClientInvokationMessage<keyof EditorRequiresClientMethods>,
46         )
47       } else if (message.type === EditorBridgeMessageType.EditorToClientReply) {
48         this.editorInvoker.handleReplyFromEditor(message as EditorToClientReplyMessage)
49       }
50     })
52     editorController.provideEditorInvoker(this.editorInvoker)
53   }
55   private async handleEditorRequestingClientMethod(
56     message: EditorToClientInvokationMessage<keyof EditorRequiresClientMethods>,
57   ) {
58     const func = this.editorRequestHandler[message.functionName].bind(this.editorRequestHandler)
60     try {
61       // @ts-ignore
62       const returnValue = await func(...message.args)
64       const reply: ClientToEditorReplyMessage = {
65         messageId: message.messageId,
66         returnValue,
67         type: EditorBridgeMessageType.ClientToEditorReply,
68       }
70       this.editorFrame.contentWindow?.postMessage(reply, BridgeOriginProvider.GetEditorOrigin())
71     } catch (error) {
72       this.logger.error('Error while handling editor request', 'message:', message, 'error:', String(error))
73     }
74   }