From 16576a566debbbc1e6afe8e7a39e71dd6704fa46 Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Sun, 4 Aug 2024 12:41:15 -0400 Subject: [PATCH] Split messages sent to devpanel --- .../src/background/store/apiMiddleware.ts | 63 +++++++++++++++++-- extension/src/contentScript/index.ts | 1 + extension/src/devpanel/index.tsx | 37 ++++++++++- 3 files changed, 93 insertions(+), 8 deletions(-) diff --git a/extension/src/background/store/apiMiddleware.ts b/extension/src/background/store/apiMiddleware.ts index 480f6682..8e487582 100644 --- a/extension/src/background/store/apiMiddleware.ts +++ b/extension/src/background/store/apiMiddleware.ts @@ -229,21 +229,72 @@ type MonitorAction> = | UpdateStateAction | SetPersistAction; +// Chrome message limit is 64 MB, but we're using 32 MB to include other object's parts +const maxChromeMsgSize = 32 * 1024 * 1024; + function toMonitors>( action: MonitorAction, tabId?: string | number, verbose?: boolean, ) { - Object.keys(connections.monitor).forEach((id) => { - connections.monitor[id].postMessage( + for (const monitorPort of Object.values(connections.monitor)) { + monitorPort.postMessage( verbose || action.type === 'ERROR' || action.type === SET_PERSIST ? action : { type: UPDATE_STATE }, ); - }); - Object.keys(connections.panel).forEach((id) => { - connections.panel[id].postMessage(action); - }); + } + + for (const panelPort of Object.values(connections.panel)) { + try { + panelPort.postMessage(action); + } catch (err) { + if ( + action.type !== UPDATE_STATE || + err == null || + (err as Error).message !== + 'Message length exceeded maximum allowed length.' + ) { + throw err; + } + + const splitMessageStart = { split: 'start' }; + const toSplit: [string, string][] = []; + let size = 0; + for (const [key, value] of Object.entries( + action.request as unknown as Record, + )) { + if (typeof value === 'string') { + size += value.length; + if (size > maxChromeMsgSize) { + toSplit.push([key, value]); + continue; + } + } + + splitMessageStart[key] = value; + } + + panelPort.postMessage({ ...action, request: splitMessageStart }); + + for (let i = 0; i < toSplit.length; i++) { + for (let j = 0; j < toSplit[i][1].length; j += maxChromeMsgSize) { + panelPort.postMessage({ + ...action, + request: { + split: 'chunk', + chunk: [ + toSplit[i][0], + toSplit[i][1].substring(j, j + maxChromeMsgSize), + ], + }, + }); + } + } + + panelPort.postMessage({ ...action, request: { split: 'end' } }); + } + } } interface ImportMessage { diff --git a/extension/src/contentScript/index.ts b/extension/src/contentScript/index.ts index b9894ab3..123bd3a3 100644 --- a/extension/src/contentScript/index.ts +++ b/extension/src/contentScript/index.ts @@ -16,6 +16,7 @@ import { DispatchAction as AppDispatchAction, } from '@redux-devtools/app'; import { LiftedState } from '@redux-devtools/instrument'; + const source = '@devtools-extension'; const pageSource = '@devtools-page'; // Chrome message limit is 64 MB, but we're using 32 MB to include other object's parts diff --git a/extension/src/devpanel/index.tsx b/extension/src/devpanel/index.tsx index 546aa3a6..e894c2a9 100644 --- a/extension/src/devpanel/index.tsx +++ b/extension/src/devpanel/index.tsx @@ -3,7 +3,11 @@ import React, { CSSProperties, ReactNode } from 'react'; import { createRoot, Root } from 'react-dom/client'; import { Provider } from 'react-redux'; import { Persistor } from 'redux-persist'; -import { REMOVE_INSTANCE, StoreAction } from '@redux-devtools/app'; +import { + REMOVE_INSTANCE, + StoreAction, + UPDATE_STATE, +} from '@redux-devtools/app'; import App from '../app/App'; import configureStore from './store/panelStore'; @@ -90,6 +94,8 @@ function renderNA() { }, 3500); } +let splitMessage; + function init(id: number) { renderNA(); bgConnection = chrome.runtime.connect({ @@ -102,7 +108,34 @@ function init(id: number) { else store!.dispatch({ type: REMOVE_INSTANCE, id: message.id }); } else { if (!rendered) renderDevTools(); - store!.dispatch(message); + + if (message.type === UPDATE_STATE && message.request.split) { + if (message.request.split === 'start') { + splitMessage = message.request; + return; + } + + if (message.request.split === 'chunk') { + if (splitMessage[message.request.chunk[0]]) { + splitMessage[message.request.chunk[0]] += + message.request.chunk[1]; + } else { + splitMessage[message.request.chunk[0]] = message.request.chunk[1]; + } + return; + } + + if (message.request.split === 'end') { + store!.dispatch({ ...message, request: splitMessage }); + return; + } + + throw new Error( + `Unable to process split message with type: ${message.request.split}`, + ); + } else { + store!.dispatch(message); + } } }, );