Freeze incoming data

Summary:
This diff will enabling freezing (making immutable) of all data we receive from the device. This prevents dev mistakes causing components not to update or logic being hard to reason about. Also this makes Immer's `produce` faster in the typical case

Since this is potentially a risky change, that might break existing plugin logic, it has been put behind a GK https://www.internalfb.com/intern/gatekeeper/projects/flipper_frozen_data/

I did some quick exploratory testing on all plugins available for Facebook iOS / Android, and the only plugin that caused trouble was Fresco, which is fixed in this diff as well.

Reviewed By: nikoant

Differential Revision: D25055056

fbshipit-source-id: 8525511f4a8a0221740a6e1371ce7f2b757a203e
This commit is contained in:
Michel Weststrate
2020-11-18 08:49:30 -08:00
committed by Facebook GitHub Bot
parent 2e5b52d247
commit 25158416ce
2 changed files with 13 additions and 3 deletions

View File

@@ -39,6 +39,8 @@ import {batch} from 'react-redux';
import {_SandyPluginInstance} from 'flipper-plugin'; import {_SandyPluginInstance} from 'flipper-plugin';
import {flipperMessagesClientPlugin} from './utils/self-inspection/plugins/FlipperMessagesClientPlugin'; import {flipperMessagesClientPlugin} from './utils/self-inspection/plugins/FlipperMessagesClientPlugin';
import {getFlipperLibImplementation} from './utils/flipperLibImplementation'; import {getFlipperLibImplementation} from './utils/flipperLibImplementation';
import {freeze} from 'immer';
import GK from './fb-stubs/GK';
type Plugins = Array<string>; type Plugins = Array<string>;
@@ -133,6 +135,7 @@ export default class Client extends EventEmitter {
connection: FlipperClientConnection<any, any> | null | undefined; connection: FlipperClientConnection<any, any> | null | undefined;
store: Store; store: Store;
activePlugins: Set<string>; activePlugins: Set<string>;
freezeData = GK.get('flipper_frozen_data');
/** /**
* @deprecated * @deprecated
@@ -395,6 +398,9 @@ export default class Client extends EventEmitter {
let rawData; let rawData;
try { try {
rawData = JSON.parse(msg); rawData = JSON.parse(msg);
if (this.freezeData) {
rawData = freeze(rawData, true);
}
} catch (err) { } catch (err) {
console.error(`Invalid JSON: ${msg}`, 'clientMessage'); console.error(`Invalid JSON: ${msg}`, 'clientMessage');
return; return;

View File

@@ -132,7 +132,10 @@ export default class FlipperImagesPlugin extends FlipperPlugin<
) { ) {
const surface = attribution[0] ? attribution[0].trim() : undefined; const surface = attribution[0] ? attribution[0].trim() : undefined;
if (surface && surface.length > 0) { if (surface && surface.length > 0) {
pluginData.surfaceList.add(surface); pluginData.surfaceList = new Set([
...pluginData.surfaceList,
surface,
]);
} }
} }
pluginData = { pluginData = {
@@ -182,16 +185,17 @@ export default class FlipperImagesPlugin extends FlipperPlugin<
} else if (method == 'events') { } else if (method == 'events') {
const event: ImageEvent = data as ImageEvent; const event: ImageEvent = data as ImageEvent;
debugLog('Received events', event); debugLog('Received events', event);
const {surfaceList} = persistedState; let {surfaceList} = persistedState;
const {attribution} = event; const {attribution} = event;
if (attribution instanceof Array && attribution.length > 0) { if (attribution instanceof Array && attribution.length > 0) {
const surface = attribution[0] ? attribution[0].trim() : undefined; const surface = attribution[0] ? attribution[0].trim() : undefined;
if (surface && surface.length > 0) { if (surface && surface.length > 0) {
surfaceList.add(surface); surfaceList = new Set([...surfaceList, surface]);
} }
} }
return { return {
...persistedState, ...persistedState,
surfaceList,
events: [ events: [
{eventId: persistedState.nextEventId, ...event}, {eventId: persistedState.nextEventId, ...event},
...persistedState.events, ...persistedState.events,