From fdfadef9289f2c69e02bbfbcc78db4dca11ce45a Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 29 Jan 2019 13:17:37 -0800 Subject: [PATCH] Refactored bridge to support transferrables (e.g. typed array buffers) and added transferable param to postMessage for op codes --- shells/browser/chrome/test.js | 2 +- shells/browser/firefox/test.js | 2 +- shells/browser/shared/src/backend.js | 7 ++--- shells/browser/shared/src/panel.js | 4 +-- shells/dev/src/backend.js | 4 +-- shells/dev/src/devtools.js | 4 +-- src/backend/agent.js | 2 +- src/bridge.js | 39 ++++++++-------------------- src/devtools/store.js | 5 ++++ src/types.js | 2 +- 10 files changed, 30 insertions(+), 41 deletions(-) diff --git a/shells/browser/chrome/test.js b/shells/browser/chrome/test.js index 9b9bbbf98f..c010a3c319 100644 --- a/shells/browser/chrome/test.js +++ b/shells/browser/chrome/test.js @@ -3,7 +3,7 @@ const chromeLaunch = require('chrome-launch'); // eslint-disable-line import/no-extraneous-dependencies const { resolve } = require('path'); -const EXTENSION_PATH = resolve('shells/chrome/build/unpacked'); +const EXTENSION_PATH = resolve('shells/browser/chrome/build/unpacked'); const START_URL = 'https://facebook.github.io/react/'; chromeLaunch(START_URL, { diff --git a/shells/browser/firefox/test.js b/shells/browser/firefox/test.js index 850d87c0f7..7dd8d1e65b 100644 --- a/shells/browser/firefox/test.js +++ b/shells/browser/firefox/test.js @@ -4,7 +4,7 @@ const { exec } = require('child-process-promise'); const { Finder } = require('firefox-profile'); const { resolve } = require('path'); -const EXTENSION_PATH = resolve('shells/firefox/build/unpacked'); +const EXTENSION_PATH = resolve('shells/browser/firefox/build/unpacked'); const START_URL = 'https://facebook.github.io/react/'; const main = async () => { diff --git a/shells/browser/shared/src/backend.js b/shells/browser/shared/src/backend.js index fa13e02527..a0a44850b2 100644 --- a/shells/browser/shared/src/backend.js +++ b/shells/browser/shared/src/backend.js @@ -42,13 +42,14 @@ function setup(hook) { listeners.push(listener); window.addEventListener('message', listener); }, - send(data) { + send(event: string, payload: any, transferable?: Array) { window.postMessage( { source: 'react-devtools-bridge', - payload: data, + payload: { event, payload }, }, - '*' + '*', + transferable ); }, }); diff --git a/shells/browser/shared/src/panel.js b/shells/browser/shared/src/panel.js index fd3361764b..67f0584dc0 100644 --- a/shells/browser/shared/src/panel.js +++ b/shells/browser/shared/src/panel.js @@ -50,11 +50,11 @@ inject(chrome.runtime.getURL('build/backend.js'), () => { listen(fn) { port.onMessage.addListener(message => fn(message)); }, - send(data) { + send(event: string, payload: any, transferable?: Array) { if (disconnected) { return; } - port.postMessage(data); + port.postMessage({ event, payload }, transferable); }, }); diff --git a/shells/dev/src/backend.js b/shells/dev/src/backend.js index 3901c8fc19..f5b029eef9 100644 --- a/shells/dev/src/backend.js +++ b/shells/dev/src/backend.js @@ -10,8 +10,8 @@ const bridge = new Bridge({ fn(event.data); }); }, - send(data) { - window.parent.postMessage(data, '*'); + send(event: string, payload: any, transferable?: Array) { + window.parent.postMessage({ event, payload }, '*', transferable); }, }); diff --git a/shells/dev/src/devtools.js b/shells/dev/src/devtools.js index 3ced5923ca..6a43284c33 100644 --- a/shells/dev/src/devtools.js +++ b/shells/dev/src/devtools.js @@ -46,8 +46,8 @@ initDevTools({ fn(data); }); }, - send(data) { - contentWindow.postMessage(data, '*'); + send(event: string, payload: any, transferable?: Array) { + contentWindow.postMessage({ event, payload }, '*', transferable); }, }); diff --git a/src/backend/agent.js b/src/backend/agent.js index 89f13dfe51..c9dd022f15 100644 --- a/src/backend/agent.js +++ b/src/backend/agent.js @@ -44,7 +44,7 @@ export default class Agent extends EventEmitter { onHookOperations = (operations: Uint32Array) => { debug('onHookOperations', operations); - this._bridge.send('operations', operations); + this._bridge.send('operations', operations, [operations.buffer]); }; onHookRootCommitted = (rootID: string) => { diff --git a/src/bridge.js b/src/bridge.js index cf63cb8300..fffb123628 100644 --- a/src/bridge.js +++ b/src/bridge.js @@ -12,7 +12,7 @@ type Message = {| |}; export default class Bridge extends EventEmitter { - _messageQueue: Array = []; + _messageQueue: Array = []; _time: number | null = null; _timeoutID: TimeoutID | null = null; @@ -22,33 +22,20 @@ export default class Bridge extends EventEmitter { super(); this.wall = wall; - wall.listen(messages => { - if (Array.isArray(messages)) { - messages.forEach(message => this._emit(message)); - } else { - this._emit(messages); - } + + wall.listen((message: Message) => { + this._emit(message); }); } - /** - * Send an event. - * - * @param {String} event - * @param {*} payload - */ - - send(event: string, payload: any) { + send(event: string, payload: any, transferable?: Array) { const time = this._time; if (time === null) { - this.wall.send([{ event, payload }]); + this.wall.send(event, payload, transferable); this._time = Date.now(); } else { - this._messageQueue.push({ - event, - payload, - }); + this._messageQueue.push(event, payload, transferable); const now = Date.now(); if (now - time > BATCH_DURATION) { @@ -59,24 +46,20 @@ export default class Bridge extends EventEmitter { } } - /** - * Log a message to the devtools background page. - * - * @param {String} message - */ - log(message: string): void { this.send('log', message); } _flush() { - if (this._messageQueue.length) { - this.wall.send(this._messageQueue); + while (this._messageQueue.length) { + this.wall.send.apply(this.wall, this._messageQueue.splice(0, 3)); } + if (this._timeoutID !== null) { clearTimeout(this._timeoutID); this._timeoutID = null; } + this._messageQueue = []; this._time = null; } diff --git a/src/devtools/store.js b/src/devtools/store.js index 7d0575147a..1661b0c228 100644 --- a/src/devtools/store.js +++ b/src/devtools/store.js @@ -102,6 +102,11 @@ export default class Store extends EventEmitter { } onBridgeOperations = (operations: Uint32Array) => { + if (!(operations instanceof Uint32Array)) { + // $FlowFixMe TODO HACK Temporary workaround for the fact that Chrome is not transferring the typed array. + operations = Uint32Array.from(Object.values(operations)); + } + debug('onBridgeOperations', operations); let haveRootsChanged = false; diff --git a/src/types.js b/src/types.js index c7af7c99a7..84b0b3045b 100644 --- a/src/types.js +++ b/src/types.js @@ -8,5 +8,5 @@ export type Hook = any; export type Wall = {| listen: (fn: Function) => void, - send: (data: any) => void, + send: (event: string, payload: any, transferable?: Array) => void, |};