fix: cleanup iframe messaging

This commit is contained in:
Michal Szczepanski 2023-04-14 02:53:19 +02:00
parent 990d4e98ac
commit 585a7b903e
10 changed files with 88 additions and 37 deletions

@ -74,11 +74,3 @@ export enum BusMessageType {
CONTENT_THEME = 'content.theme'
// Options
}
export enum IFrameMessage {
FETCH = 'fetch',
PING = 'ping',
ALIVE = 'alive',
START_LISTENERS = 'start-listeners',
STOP_LISTENERS = 'stop-listeners'
}

@ -47,7 +47,7 @@ export interface FetchImageRequest {
}
export interface FetchIframeRequest {
id: string;
uid: string;
depth: number;
}

@ -17,7 +17,7 @@
import { CssStyleListDto } from './obj-pin.dto';
export interface ObjIframeContentDto {
id: string;
uid: string;
ok: boolean;
url: string;
html: string;

@ -32,7 +32,7 @@ export class ContentFetchIframeCommand implements ICommand<Promise<void>> {
const css = await CssFactory.computeCssContent();
const dto: ObjIframeContentDto = {
ok: true,
id: this.data.id,
uid: this.data.uid,
url: this.href,
html: htmlContent.html,
htmlAttr: HtmlFactory.computeHtmlAttr(),

@ -24,6 +24,7 @@ import '@fontsource/roboto/700.css';
import '../css/prosemirror.css';
import { ContentExtensionData, ExtensionThemeDto } from '../common/model/settings.model';
import { IFrameMessageFactory, IFrameMessageType } from './factory/html/iframe-message.model';
import { fnConsoleError, fnConsoleLog } from '../common/fn/console.fn';
import { BrowserApi } from '../common/service/browser.api.wrapper';
import { BrowserStorageWrapper } from '../common/service/browser.storage.wrapper';
@ -47,18 +48,16 @@ class PinMeScript {
this.href = UrlFactory.normalizeHref(window.location.href);
window.addEventListener('message', async (e) => {
// TODO RECEIVE
try {
const msg = JSON.parse(e.data);
if (msg.foo === 'bar') {
//eslint-disable-next-line @typescript-eslint/restrict-template-expressions
window.top?.postMessage(`{"bar":"foo", "id":"${msg.id}"}`, '*');
await new ContentFetchIframeCommand(msg, this.href).execute();
} else if (msg.bar === 'foo') {
fnConsoleLog('PinMeScript->constructor->ping->from-iframe', msg);
TinyEventDispatcher.dispatch(BusMessageType.CONTENT_FETCH_IFRAME_PING, msg);
}
} catch (e) {
/* IGNORE */
const msg = IFrameMessageFactory.parse(e.data);
if (!msg) return;
if (msg.type === IFrameMessageType.PING) {
//eslint-disable-next-line @typescript-eslint/restrict-template-expressions
window.top?.postMessage(IFrameMessageFactory.create({ type: IFrameMessageType.PONG, data: msg.data }));
} else if (msg.type === IFrameMessageType.PONG) {
fnConsoleLog('PinMeScript->constructor->ping->from-iframe', msg);
TinyEventDispatcher.dispatch(BusMessageType.CONTENT_FETCH_IFRAME_PING, msg.data);
} else if (msg.type === IFrameMessageType.FETCH) {
await new ContentFetchIframeCommand(msg.data, this.href).execute();
}
});
ContentMessageHandler.start(this.href);

@ -196,6 +196,7 @@ export class CssFactory {
css = css.replace(urlMatch, newUrl);
} else {
fnConsoleLog('CssFactory->fetchUrl->ERROR !!!', result, baseurl);
break;
}
}
return css;

@ -78,13 +78,13 @@ export class HtmlAttrFactory {
const urlList = attrValue.match(CSS_URL_REG);
if (urlList) {
const value = await CssFactory.fetchUrls(attrValue);
fnConsoleLog(
'HtmlFactory->computeHtmlIntermediateData->image-inside-style',
/*fnConsoleLog(
'HtmlAttrFactory->computeHtmlIntermediateData->image-inside-style',
'prev',
attrValue,
'result',
value
);
);*/
html += `${attr.name}="${value}" `;
} else {
html += `${attr.name}="${attrValue}" `;

@ -15,7 +15,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { fnComputeUrl } from '../../../common/fn/compute-url.fn';
import { fnConsoleLog } from '../../../common/fn/console.fn';
import { fnFetchImage } from '../../../common/fn/fetch-image.fn';
export class HtmlImgFactory {
@ -67,7 +66,7 @@ export class HtmlImgFactory {
const url = fnComputeUrl(value);
const imageData = await fnFetchImage(url);
fnConsoleLog('HtmlImgFactory->computeImgValue', url);
// fnConsoleLog('HtmlImgFactory->computeImgValue', url);
if (imageData.ok) {
return imageData.res;
}

@ -0,0 +1,48 @@
/*
* This file is part of the pinmenote-extension distribution (https://github.com/pinmenote/pinmenote-extension).
* Copyright (c) 2023 Michal Szczepanski.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { fnConsoleLog } from '../../../common/fn/console.fn';
export enum IFrameMessageType {
FETCH = 'fetch',
PING = 'ping',
PONG = 'png',
ALIVE = 'alive',
START_LISTENERS = 'start-listeners',
STOP_LISTENERS = 'stop-listeners'
}
export interface IFrameMessage {
type: IFrameMessageType;
data: any;
}
export class IFrameMessageFactory {
static create(message: IFrameMessage) {
fnConsoleLog('IFrameMessageFactory->create', message);
return JSON.stringify(message);
}
static parse(msg: string): IFrameMessage | undefined {
try {
return JSON.parse(msg);
} catch (e) {
/* IGNORE */
fnConsoleLog('IFrameMessageFactory->parse->error', e, msg);
}
return undefined;
}
}

@ -14,6 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { IFrameMessageFactory, IFrameMessageType } from './iframe-message.model';
import { ObjContentTypeDto, ObjIframeContentDto } from '../../../common/model/obj/obj-content.dto';
import { BusMessageType } from '../../../common/model/bus.model';
import { HtmlAttrFactory } from './html-attr.factory';
@ -57,17 +58,24 @@ export class IframeFactory {
fnConsoleLog('HtmlFactory->fetchIframe', ref.src);
return new Promise<ObjIframeContentDto>((resolve, reject) => {
if (!ref.contentWindow) return HtmlAttrFactory.EMPTY_RESULT;
TinyEventDispatcher.addListener<{ id: string }>(BusMessageType.CONTENT_FETCH_IFRAME_PING, (event, key, value) => {
fnConsoleLog('HtmlFactory->fetchIframe->ping->clear', value.id, uid);
if (value.id === uid) {
TinyEventDispatcher.removeListener(event, key);
clearTimeout(iframeTimeout);
TinyEventDispatcher.addListener<{ uid: string; depth: number }>(
BusMessageType.CONTENT_FETCH_IFRAME_PING,
(event, key, value) => {
fnConsoleLog('HtmlFactory->fetchIframe->ping->clear', value.uid, uid);
if (value.uid === uid && value.depth === depth) {
TinyEventDispatcher.removeListener(event, key);
clearTimeout(iframeTimeout);
ref.contentWindow?.postMessage(
IFrameMessageFactory.create({ type: IFrameMessageType.FETCH, data: { depth, uid } }),
'*'
);
}
}
});
);
const eventKey = TinyEventDispatcher.addListener<ObjIframeContentDto>(
BusMessageType.CONTENT_FETCH_IFRAME_RESULT,
(event, key, value) => {
if (value.id === uid) {
if (value.uid === uid) {
fnConsoleLog('HtmlFactory->fetchIframe->result', uid, value.url, value);
clearTimeout(iframeTimeout);
clearInterval(iframeFetchTimeout);
@ -76,11 +84,15 @@ export class IframeFactory {
}
}
);
ref.contentWindow.postMessage(`{"foo":"bar", "depth":${depth}, "id":"${uid}"}`, '*');
ref.contentWindow.postMessage(
IFrameMessageFactory.create({ type: IFrameMessageType.PING, data: { depth, uid } }),
'*'
);
// ref.contentWindow.postMessage(`{"foo":"bar", "depth":${depth}, "id":"${uid}"}`, '*');
const iframeTimeout = setTimeout(() => {
TinyEventDispatcher.removeListener(BusMessageType.CONTENT_FETCH_IFRAME_RESULT, eventKey);
reject(`Iframe timeout ${uid} ${ref.src}`);
}, 500);
}, 1000);
// TODO handle this more gracefully - like ping iframe for status
const iframeFetchTimeout = setTimeout(() => {
TinyEventDispatcher.removeListener(BusMessageType.CONTENT_FETCH_IFRAME_RESULT, eventKey);