diff --git a/headless/index.js b/headless/index.js index 245805b4c..5948de082 100644 --- a/headless/index.js +++ b/headless/index.js @@ -12,7 +12,7 @@ import yargs from 'yargs'; import dispatcher from '../src/dispatcher/index.js'; import {init as initLogger} from '../src/fb-stubs/Logger.js'; import reducers from '../src/reducers/index.js'; -import {exportStore} from '../src/utils/exportData.js'; +import {exportStore, pluginsClassMap} from '../src/utils/exportData.js'; import { exportMetricsWithoutTrace, exportMetricsFromTrace, @@ -120,7 +120,10 @@ async function exitActions( const {metrics, exit} = userArguments; if (shouldExportMetric(metrics) && metrics && metrics.length > 0) { try { - const payload = await exportMetricsFromTrace(metrics, store.getState()); + const payload = await exportMetricsFromTrace( + metrics, + pluginsClassMap(store.getState()), + ); originalConsole.log(payload); } catch (error) { console.error(error); @@ -133,7 +136,7 @@ async function exitActions( if (shouldExportMetric(metrics) && !metrics) { const state = store.getState(); const payload = await exportMetricsWithoutTrace( - state, + store, state.pluginStates, ); originalConsole.log(payload); diff --git a/src/utils/exportData.js b/src/utils/exportData.js index d85764931..7cd589bf6 100644 --- a/src/utils/exportData.js +++ b/src/utils/exportData.js @@ -25,6 +25,8 @@ import {readCurrentRevision} from './packageMetadata.js'; import {tryCatchReportPlatformFailures} from './metrics'; import {promisify} from 'util'; import promiseTimeout from './promiseTimeout'; +import type {State} from '../reducers'; + export const IMPORT_FLIPPER_TRACE_EVENT = 'import-flipper-trace'; export const EXPORT_FLIPPER_TRACE_EVENT = 'export-flipper-trace'; @@ -46,6 +48,22 @@ export function processClients( return clients.filter(client => client.query.device_id === serial); } +export function pluginsClassMap( + state: State, +): Map | FlipperPlugin<>>> { + const pluginsMap: Map< + string, + Class | FlipperPlugin<>>, + > = new Map([]); + state.plugins.clientPlugins.forEach((val, key) => { + pluginsMap.set(key, val); + }); + state.plugins.devicePlugins.forEach((val, key) => { + pluginsMap.set(key, val); + }); + return pluginsMap; +} + export function processPluginStates( clients: Array, serial: string, @@ -184,34 +202,17 @@ export const processStore = async ( return null; }; -export async function getStoreExport( +export async function fetchMetadata( + pluginStates: PluginStatesState, + pluginsMap: Map | FlipperPlugin<>>>, store: MiddlewareAPI, -): Promise<{exportData: ?ExportType, errorArray: Array}> { - const state = store.getState(); - const {clients} = state.connections; - const {pluginStates} = state; - const {plugins} = state; - const {selectedDevice} = store.getState().connections; - if (!selectedDevice) { - throw new Error('Please select a device before exporting data.'); - } +): Promise<{pluginStates: PluginStatesState, errorArray: Array}> { const newPluginState = {...pluginStates}; - // TODO: T39612653 Make Client mockable. Currently rsocket logic is tightly coupled. - // Not passing the entire state as currently Client is not mockable. - - const pluginsMap: Map< - string, - Class | FlipperPlugin<>>, - > = new Map([]); - plugins.clientPlugins.forEach((val, key) => { - pluginsMap.set(key, val); - }); - plugins.devicePlugins.forEach((val, key) => { - pluginsMap.set(key, val); - }); const errorArray: Array = []; + const clients = store.getState().connections.clients; + const selectedDevice = store.getState().connections.selectedDevice; for (let client of clients) { - if (!client.id.includes(selectedDevice.serial)) { + if (!selectedDevice || !client.id.includes(selectedDevice.serial)) { continue; } for (let plugin of client.plugins) { @@ -235,6 +236,37 @@ export async function getStoreExport( } } } + return {pluginStates: newPluginState, errorArray}; +} + +export async function getStoreExport( + store: MiddlewareAPI, +): Promise<{exportData: ?ExportType, errorArray: Array}> { + const state = store.getState(); + const {clients} = state.connections; + const {pluginStates} = state; + const {plugins} = state; + const {selectedDevice} = store.getState().connections; + if (!selectedDevice) { + throw new Error('Please select a device before exporting data.'); + } + // TODO: T39612653 Make Client mockable. Currently rsocket logic is tightly coupled. + // Not passing the entire state as currently Client is not mockable. + + const pluginsMap: Map< + string, + Class | FlipperPlugin<>>, + > = new Map([]); + plugins.clientPlugins.forEach((val, key) => { + pluginsMap.set(key, val); + }); + plugins.devicePlugins.forEach((val, key) => { + pluginsMap.set(key, val); + }); + + const metadata = await fetchMetadata(pluginStates, pluginsMap, store); + const {errorArray} = metadata; + const newPluginState = metadata.pluginStates; const {activeNotifications} = store.getState().notifications; const {devicePlugins} = store.getState().plugins; diff --git a/src/utils/exportMetrics.js b/src/utils/exportMetrics.js index a517651b1..7ae60e333 100644 --- a/src/utils/exportMetrics.js +++ b/src/utils/exportMetrics.js @@ -7,16 +7,17 @@ import type {FlipperPlugin, FlipperDevicePlugin} from 'flipper'; import {serialize} from './serialization'; import type {State as PluginStatesState} from '../reducers/pluginStates'; -import type {State} from '../reducers/index.js'; +import type {Store} from '../reducers'; import fs from 'fs'; import type {ExportType} from './exportData'; +import {fetchMetadata, pluginsClassMap} from './exportData'; import {deserializeObject} from './serialization'; export type MetricType = {[metricName: string]: number}; type MetricPluginType = {[pluginID: string]: MetricType}; export type ExportMetricType = {[clientID: string]: MetricPluginType}; -export async function exportMetrics( +async function exportMetrics( pluginStates: PluginStatesState, pluginsMap: Map | FlipperPlugin<>>>, ): Promise { @@ -45,21 +46,21 @@ export async function exportMetrics( } export async function exportMetricsWithoutTrace( - state: State, + store: Store, pluginStates: PluginStatesState, ): Promise { const pluginsMap: Map< string, Class | FlipperPlugin<>>, - > = new Map([]); - state.plugins.clientPlugins.forEach((val, key) => { - pluginsMap.set(key, val); - }); - state.plugins.devicePlugins.forEach((val, key) => { - pluginsMap.set(key, val); - }); + > = pluginsClassMap(store.getState()); + const metadata = await fetchMetadata(pluginStates, pluginsMap, store); + const newPluginStates = metadata.pluginStates; + const {errorArray} = metadata; + if (errorArray.length > 0) { + console.error(errorArray); + } - const metrics = await exportMetrics(pluginStates, pluginsMap); + const metrics = await exportMetrics(newPluginStates, pluginsMap); return metrics; } @@ -74,7 +75,7 @@ function parseJSON(str: string): ?any { export async function exportMetricsFromTrace( trace: string, - state: State, + pluginsMap: Map | FlipperPlugin<>>>, ): Promise { const data = fs.readFileSync(trace, 'utf8'); const parsedJSONData = parseJSON(data); @@ -102,6 +103,5 @@ export async function exportMetricsFromTrace( ), ); } - const metrics = await exportMetricsWithoutTrace(state, pluginStates); - return metrics; + return await exportMetrics(pluginStates, pluginsMap); }