From 16bb83f74a0405d9bd9c26b926c24a0640a99e89 Mon Sep 17 00:00:00 2001 From: Tilman Vatteroth Date: Tue, 27 Sep 2022 16:46:22 +0200 Subject: [PATCH] feat(window post message communicator): Add uuid to frames Signed-off-by: Tilman Vatteroth --- ...renderer-communicator-context-provider.tsx | 7 ++-- ...o-editor-communicator-context-provider.tsx | 10 ++++- ...render-page-url-on-iframe-load-callback.ts | 7 +++- .../window-post-message-communicator.ts | 41 +++++++++++-------- 4 files changed, 43 insertions(+), 22 deletions(-) diff --git a/src/components/editor-page/render-context/editor-to-renderer-communicator-context-provider.tsx b/src/components/editor-page/render-context/editor-to-renderer-communicator-context-provider.tsx index 683ffc600..bc741f11f 100644 --- a/src/components/editor-page/render-context/editor-to-renderer-communicator-context-provider.tsx +++ b/src/components/editor-page/render-context/editor-to-renderer-communicator-context-provider.tsx @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -7,6 +7,7 @@ import type { PropsWithChildren } from 'react' import React, { createContext, useContext, useEffect, useMemo } from 'react' import { EditorToRendererCommunicator } from '../../render-page/window-post-message-communicator/editor-to-renderer-communicator' +import { v4 as uuid } from 'uuid' const EditorToRendererCommunicatorContext = createContext(undefined) @@ -27,8 +28,8 @@ export const useEditorToRendererCommunicator: () => EditorToRendererCommunicator /** * Provides a {@link EditorToRendererCommunicator editor to renderer communicator} for the child components via Context. */ -export const EditorToRendererCommunicatorContextProvider: React.FC> = ({ children }) => { - const communicator = useMemo(() => new EditorToRendererCommunicator(), []) +export const EditorToRendererCommunicatorContextProvider: React.FC = ({ children }) => { + const communicator = useMemo(() => new EditorToRendererCommunicator(uuid()), []) useEffect(() => { const currentCommunicator = communicator diff --git a/src/components/editor-page/render-context/renderer-to-editor-communicator-context-provider.tsx b/src/components/editor-page/render-context/renderer-to-editor-communicator-context-provider.tsx index 749a960d9..0c95fdf6e 100644 --- a/src/components/editor-page/render-context/renderer-to-editor-communicator-context-provider.tsx +++ b/src/components/editor-page/render-context/renderer-to-editor-communicator-context-provider.tsx @@ -9,6 +9,7 @@ import React, { createContext, useContext, useEffect, useMemo } from 'react' import { RendererToEditorCommunicator } from '../../render-page/window-post-message-communicator/renderer-to-editor-communicator' import { CommunicationMessageType } from '../../render-page/window-post-message-communicator/rendering-message' import { ORIGIN, useBaseUrl } from '../../../hooks/common/use-base-url' +import { useSingleStringUrlParameter } from '../../../hooks/common/use-single-string-url-parameter' const RendererToEditorCommunicatorContext = createContext(undefined) @@ -28,7 +29,14 @@ export const useRendererToEditorCommunicator: () => RendererToEditorCommunicator export const RendererToEditorCommunicatorContextProvider: React.FC> = ({ children }) => { const editorOrigin = useBaseUrl(ORIGIN.EDITOR) - const communicator = useMemo(() => new RendererToEditorCommunicator(), []) + const uuid = useSingleStringUrlParameter('uuid', undefined) + const communicator = useMemo(() => { + if (uuid === undefined) { + throw new Error('no uuid found in url!') + } else { + return new RendererToEditorCommunicator(uuid) + } + }, [uuid]) useEffect(() => { const currentCommunicator = communicator diff --git a/src/components/editor-page/renderer-pane/hooks/use-force-render-page-url-on-iframe-load-callback.ts b/src/components/editor-page/renderer-pane/hooks/use-force-render-page-url-on-iframe-load-callback.ts index dbeb4fa88..f1f4cdc67 100644 --- a/src/components/editor-page/renderer-pane/hooks/use-force-render-page-url-on-iframe-load-callback.ts +++ b/src/components/editor-page/renderer-pane/hooks/use-force-render-page-url-on-iframe-load-callback.ts @@ -8,6 +8,7 @@ import type { RefObject } from 'react' import { useCallback, useEffect, useMemo, useRef } from 'react' import { Logger } from '../../../../utils/logger' import { ORIGIN, useBaseUrl } from '../../../../hooks/common/use-base-url' +import { useEditorToRendererCommunicator } from '../../render-context/editor-to-renderer-communicator-context-provider' const log = new Logger('IframeLoader') @@ -19,14 +20,16 @@ const log = new Logger('IframeLoader') */ export const useForceRenderPageUrlOnIframeLoadCallback = ( iFrameReference: RefObject, - onNavigateAway?: () => void + onNavigateAway: () => void ): (() => void) => { + const iframeCommunicator = useEditorToRendererCommunicator() const rendererBaseUrl = useBaseUrl(ORIGIN.RENDERER) const forcedUrl = useMemo(() => { const renderUrl = new URL(rendererBaseUrl) renderUrl.pathname += 'render' + renderUrl.searchParams.set('uuid', iframeCommunicator.getUuid()) return renderUrl.toString() - }, [rendererBaseUrl]) + }, [iframeCommunicator, rendererBaseUrl]) const redirectionInProgress = useRef(false) const loadCallback = useCallback(() => { diff --git a/src/components/render-page/window-post-message-communicator/window-post-message-communicator.ts b/src/components/render-page/window-post-message-communicator/window-post-message-communicator.ts index de82a888e..5c4b8dbc4 100644 --- a/src/components/render-page/window-post-message-communicator/window-post-message-communicator.ts +++ b/src/components/render-page/window-post-message-communicator/window-post-message-communicator.ts @@ -17,6 +17,11 @@ export type Handler = ( values: Extract> ) => void +export interface MessagePayloadWithUuid { + uuid: string + payload: MessagePayload +} + export interface MessagePayload { type: MESSAGE_TYPE } @@ -36,12 +41,16 @@ export abstract class WindowPostMessageCommunicator< private readonly log: Logger private readonly boundListener: (event: MessageEvent) => void - public constructor() { + public constructor(private uuid: string) { this.boundListener = this.handleEvent.bind(this) this.communicationEnabled = false this.log = this.createLogger() } + public getUuid(): string { + return this.uuid + } + protected abstract createLogger(): Logger /** @@ -104,7 +113,13 @@ export abstract class WindowPostMessageCommunicator< ) } this.log.debug('Sent event', message) - this.messageTarget.postMessage(message, this.targetOrigin) + this.messageTarget.postMessage( + { + uuid: this.uuid, + payload: message + } as MessagePayloadWithUuid, + this.targetOrigin + ) } /** @@ -135,19 +150,13 @@ export abstract class WindowPostMessageCommunicator< * @param event The received event * @return {@link true} if the event was processed. */ - protected handleEvent(event: MessageEvent>): void { - Optional.ofNullable(event.data).ifPresent((payload) => { - event.stopPropagation() - event.preventDefault() - this.processPayload(payload) - }) - } - - /** - * Processes a {@link MessagePayload message payload} using the correct {@link Handler handler}. - * @param payload The payload that should be processed - */ - private processPayload(payload: MessagePayload): void { - this.emitter.emit(payload.type, payload) + protected handleEvent(event: MessageEvent>): void { + Optional.ofNullable(event.data) + .filter((value) => value.uuid === this.uuid) + .ifPresent((payload) => { + event.stopPropagation() + event.preventDefault() + this.emitter.emit(payload.payload.type, payload.payload) + }) } }