Move devices to server folder

Summary:
This is the first of many diffs that extracts the connection, device, client detection out of the flipper core, to create a reusable flipper-server library that can be used in e.g. flipper-dump.

To keep diffs a little smaller, the current connection logic is first moved to the `server/` directory, and decoupled manually from the rest of the core, before moving it over to a separate package.

This first diffs moves the `comms/`, `devices/` and certificate utilities to the `server` directory.

Further untangling will follow in next diffs

Reviewed By: timur-valiev

Differential Revision: D30246551

fbshipit-source-id: c84259bfb1239119b3267a51b015e30c3c080866
This commit is contained in:
Michel Weststrate
2021-08-12 05:42:32 -07:00
committed by Facebook GitHub Bot
parent 5e350add4f
commit 5e8c968222
86 changed files with 273 additions and 172 deletions

View File

@@ -8,7 +8,7 @@
*/
import {PluginDefinition} from './plugin';
import BaseDevice, {OS} from './devices/BaseDevice';
import BaseDevice, {OS} from './server/devices/BaseDevice';
import {Logger} from './fb-interfaces/Logger';
import {Store} from './reducers/index';
import {performance} from 'perf_hooks';
@@ -16,10 +16,9 @@ import {reportPluginFailures} from './utils/metrics';
import {default as isProduction} from './utils/isProduction';
import {EventEmitter} from 'events';
import invariant from 'invariant';
import {
getPluginKey,
defaultEnabledBackgroundPlugins,
} from './utils/pluginUtils';
import {getPluginKey} from './utils/pluginKey';
import {defaultEnabledBackgroundPlugins} from './utils/pluginUtils';
import {processMessagesLater} from './utils/messageQueue';
import {emitBytesReceived} from './dispatcher/tracking';
import {debounce} from 'lodash';
@@ -36,7 +35,7 @@ import {
ConnectionStatus,
ErrorType,
ClientConnection,
} from './comms/ClientConnection';
} from './server/comms/ClientConnection';
type Plugins = Set<string>;
type PluginsArr = Array<string>;

View File

@@ -9,8 +9,8 @@
import {FlipperPlugin, FlipperDevicePlugin} from './plugin';
import {Logger} from './fb-interfaces/Logger';
import BaseDevice from './devices/BaseDevice';
import {pluginKey as getPluginKey} from './utils/pluginUtils';
import BaseDevice from './server/devices/BaseDevice';
import {pluginKey as getPluginKey} from './utils/pluginKey';
import Client from './Client';
import {
ErrorBoundary,

View File

@@ -7,7 +7,7 @@
* @format
*/
import {default as BaseDevice} from '../devices/BaseDevice';
import {default as BaseDevice} from '../server/devices/BaseDevice';
import {createMockFlipperWithPlugin} from '../test-utils/createMockFlipperWithPlugin';
import {
TestUtils,

View File

@@ -11,7 +11,7 @@ import {Button} from '../ui';
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {State as Store} from '../reducers';
import {launchJsEmulator} from '../utils/js-client-server-utils/serverUtils';
import {launchJsEmulator} from '../server/utils/js-client-server-utils/serverUtils';
import {updateSettings, Action} from '../reducers/settings';
import {Settings} from '../reducers/settings';
import {Collapse, Form, Input as AntInput} from 'antd';

View File

@@ -8,7 +8,7 @@
*/
import React, {useCallback, useEffect, useState} from 'react';
import MetroDevice, {MetroReportableEvent} from '../devices/MetroDevice';
import MetroDevice, {MetroReportableEvent} from '../server/devices/MetroDevice';
import {useStore} from '../utils/useStore';
import {Button as AntButton} from 'antd';
import {MenuOutlined, ReloadOutlined} from '@ant-design/icons';

View File

@@ -8,7 +8,7 @@
*/
import React, {Component} from 'react';
import BaseDevice from '../devices/BaseDevice';
import BaseDevice from '../server/devices/BaseDevice';
import {Button, Glyph, colors} from '../ui';
import path from 'path';
import os from 'os';

View File

@@ -14,7 +14,7 @@ import {
import configureStore from 'redux-mock-store';
import {State, createRootReducer} from '../../reducers/index';
import {getInstance} from '../../fb-stubs/Logger';
import {IOSBridge} from '../../utils/IOSBridge';
import {IOSBridge} from '../../server/utils/IOSBridge';
const mockStore = configureStore<State, {}>([])(
createRootReducer()(undefined, {type: 'INIT'}),

View File

@@ -22,7 +22,7 @@ import {_SandyPluginDefinition as SandyPluginDefinition} from 'flipper-plugin';
import MockFlipper from '../../test-utils/MockFlipper';
import Client from '../../Client';
import React from 'react';
import BaseDevice from '../../devices/BaseDevice';
import BaseDevice from '../../server/devices/BaseDevice';
const pluginDetails1 = TestUtils.createMockPluginDetails({
id: 'plugin1',

View File

@@ -7,13 +7,13 @@
* @format
*/
import AndroidDevice from '../devices/AndroidDevice';
import KaiOSDevice from '../devices/KaiOSDevice';
import AndroidDevice from '../server/devices/AndroidDevice';
import KaiOSDevice from '../server/devices/KaiOSDevice';
import child_process from 'child_process';
import {Store} from '../reducers/index';
import BaseDevice from '../devices/BaseDevice';
import BaseDevice from '../server/devices/BaseDevice';
import {Logger} from '../fb-interfaces/Logger';
import {getAdbClient} from '../utils/adbClient';
import {getAdbClient} from '../server/utils/adbClient';
import which from 'which';
import {promisify} from 'util';
import {ServerPorts} from '../reducers/application';
@@ -105,7 +105,7 @@ function createDevice(
export async function getActiveAndroidDevices(
store: Store,
): Promise<Array<BaseDevice>> {
const client = await getAdbClient(store);
const client = await getAdbClient(store.getState().settingsState);
const androidDevices = await client.listDevices();
const devices = await Promise.all(
androidDevices.map((device) => createDevice(client, device, store)),
@@ -169,7 +169,7 @@ export default (store: Store, logger: Logger) => {
console.warn('Failed to query AVDs:', err);
});
return getAdbClient(store)
return getAdbClient(store.getState().settingsState)
.then((client) => {
client
.trackDevices()
@@ -282,7 +282,7 @@ export default (store: Store, logger: Logger) => {
// cleanup method
return () =>
getAdbClient(store).then((client) => {
getAdbClient(store.getState().settingsState).then((client) => {
client.kill();
});
};

View File

@@ -10,7 +10,7 @@
import {remote, ipcRenderer, IpcRendererEvent} from 'electron';
import {Store} from '../reducers/index';
import {Logger} from '../fb-interfaces/Logger';
import {parseFlipperPorts} from '../utils/environmentVariables';
import {parseFlipperPorts} from '../server/utils/environmentVariables';
import {
importFileToStore,
IMPORT_FLIPPER_TRACE_EVENT,

View File

@@ -10,8 +10,8 @@
import {Store} from '../reducers/index';
import {Logger} from '../fb-interfaces/Logger';
import MacDevice from '../devices/MacDevice';
import WindowsDevice from '../devices/WindowsDevice';
import MacDevice from '../server/devices/MacDevice';
import WindowsDevice from '../server/devices/WindowsDevice';
export default (store: Store, _logger: Logger) => {
let device;

View File

@@ -16,8 +16,8 @@ import {promisify} from 'util';
import path from 'path';
import child_process from 'child_process';
const execFile = child_process.execFile;
import iosUtil from '../utils/iOSContainerUtility';
import IOSDevice from '../devices/IOSDevice';
import iosUtil from '../server/utils/iOSContainerUtility';
import IOSDevice from '../server/devices/IOSDevice';
import {addErrorNotification} from '../reducers/notifications';
import {getStaticPath} from '../utils/pathUtils';
import {destroyDevice} from '../reducers/connections';
@@ -25,7 +25,7 @@ import {
ERR_NO_IDB_OR_XCODE_AVAILABLE,
IOSBridge,
makeIOSBridge,
} from '../utils/IOSBridge';
} from '../server/utils/IOSBridge';
type iOSSimulatorDevice = {
state: 'Booted' | 'Shutdown' | 'Shutting Down';

View File

@@ -9,11 +9,11 @@
import {Store} from '../reducers/index';
import {Logger} from '../fb-interfaces/Logger';
import MetroDevice from '../devices/MetroDevice';
import MetroDevice from '../server/devices/MetroDevice';
import http from 'http';
import {addErrorNotification} from '../reducers/notifications';
import {destroyDevice} from '../reducers/connections';
import {parseEnvironmentVariableAsNumber} from '../utils/environmentVariables';
import {parseEnvironmentVariableAsNumber} from '../server/utils/environmentVariables';
const METRO_HOST = 'localhost';
const METRO_PORT = parseEnvironmentVariableAsNumber('METRO_SERVER_PORT', 8081);

View File

@@ -44,10 +44,10 @@ import {
import {deconstructClientId} from '../utils/clientUtils';
import {clearMessageQueue} from '../reducers/pluginMessageQueue';
import {
getPluginKey,
isDevicePluginDefinition,
defaultEnabledBackgroundPlugins,
} from '../utils/pluginUtils';
import {getPluginKey} from '../utils/pluginKey';
const maxInstalledPluginVersionsToKeep = 2;

View File

@@ -8,7 +8,7 @@
*/
import {remote} from 'electron';
import MetroDevice from '../devices/MetroDevice';
import MetroDevice from '../server/devices/MetroDevice';
import {Store} from '../reducers';
type ShortcutEventCommand =

View File

@@ -7,14 +7,14 @@
* @format
*/
import ServerController from '../comms/ServerController';
import ServerController from '../server/comms/ServerController';
import {Store} from '../reducers/index';
import {Logger} from '../fb-interfaces/Logger';
import Client from '../Client';
import {UninitializedClient} from '../UninitializedClient';
import {addErrorNotification} from '../reducers/notifications';
import {CertificateExchangeMedium} from '../utils/CertificateProvider';
import {CertificateExchangeMedium} from '../server/utils/CertificateProvider';
import {selectClient, selectDevice} from '../reducers/connections';
import {isLoggedIn} from '../fb-stubs/user';
import React from 'react';

View File

@@ -25,7 +25,7 @@ import {
selectionChanged,
} from '../reducers/usageTracking';
import produce from 'immer';
import BaseDevice from '../devices/BaseDevice';
import BaseDevice from '../server/devices/BaseDevice';
import {deconstructClientId} from '../utils/clientUtils';
import {getCPUUsage} from 'process';
import {sideEffect} from '../utils/sideEffect';

View File

@@ -7,7 +7,7 @@
* @format
*/
import {OS} from '../devices/BaseDevice';
import {OS} from '../server/devices/BaseDevice';
export default Object.freeze({
GRAPH_APP_ID: '',

View File

@@ -30,19 +30,19 @@ export {reportUsage} from './utils/metrics';
export {default as promiseTimeout} from './utils/promiseTimeout';
export {clipboard, remote, OpenDialogOptions} from 'electron';
export {bufferToBlob} from './utils/screenshot';
export {getPluginKey} from './utils/pluginUtils';
export {getPluginKey} from './utils/pluginKey';
export {Notification, Idler} from 'flipper-plugin';
export {IdlerImpl} from './utils/Idler';
export {Store, State as ReduxState} from './reducers/index';
export {default as BaseDevice} from './devices/BaseDevice';
export {default as BaseDevice} from './server/devices/BaseDevice';
export {default as isProduction} from './utils/isProduction';
export {DetailSidebar} from 'flipper-plugin';
export {default as Device} from './devices/BaseDevice';
export {default as AndroidDevice} from './devices/AndroidDevice';
export {default as ArchivedDevice} from './devices/ArchivedDevice';
export {default as IOSDevice} from './devices/IOSDevice';
export {default as KaiOSDevice} from './devices/KaiOSDevice';
export {OS} from './devices/BaseDevice';
export {default as Device} from './server/devices/BaseDevice';
export {default as AndroidDevice} from './server/devices/AndroidDevice';
export {default as ArchivedDevice} from './server/devices/ArchivedDevice';
export {default as IOSDevice} from './server/devices/IOSDevice';
export {default as KaiOSDevice} from './server/devices/KaiOSDevice';
export {OS} from './server/devices/BaseDevice';
export {default as Button} from './ui/components/Button';
export {default as ToggleButton} from './ui/components/ToggleSwitch';
export {default as ButtonGroup} from './ui/components/ButtonGroup';
@@ -129,7 +129,7 @@ export {Rect} from './utils/geometry';
export {Logger} from './fb-interfaces/Logger';
export {getInstance as getLogger} from './fb-stubs/Logger';
export {callVSCode} from './utils/vscodeUtils';
export {checkIdbIsInstalled} from './utils/iOSContainerUtility';
export {checkIdbIsInstalled} from './server/utils/iOSContainerUtility';
export {IDEFileResolver, IDEType} from './fb-stubs/IDEFileResolver';
export {renderMockFlipperWithPlugin} from './test-utils/createMockFlipperWithPlugin';
export {Tracked} from 'flipper-plugin'; // To be able to use it in legacy plugins

View File

@@ -11,7 +11,7 @@ import {KeyboardActions} from './MenuBar';
import {Logger} from './fb-interfaces/Logger';
import Client from './Client';
import {Component} from 'react';
import BaseDevice from './devices/BaseDevice';
import BaseDevice from './server/devices/BaseDevice';
import {StaticView} from './reducers/connections';
import {State as ReduxState} from './reducers';
import {DEFAULT_MAX_QUEUE_SIZE} from './reducers/pluginMessageQueue';

View File

@@ -9,10 +9,10 @@
import reducer from '../connections';
import {State, selectPlugin} from '../connections';
import BaseDevice from '../../devices/BaseDevice';
import MacDevice from '../../devices/MacDevice';
import BaseDevice from '../../server/devices/BaseDevice';
import MacDevice from '../../server/devices/MacDevice';
import {FlipperDevicePlugin} from '../../plugin';
import MetroDevice from '../../devices/MetroDevice';
import MetroDevice from '../../server/devices/MetroDevice';
import {TestUtils, _setFlipperLibImplementation} from 'flipper-plugin';
import {wrapSandy} from '../../test-utils/createMockFlipperWithPlugin';
import {createMockFlipperLib} from 'flipper-plugin/src/test-utils/test-utils';

View File

@@ -10,18 +10,20 @@
import {ComponentType} from 'react';
import {produce} from 'immer';
import type BaseDevice from '../devices/BaseDevice';
import MacDevice from '../devices/MacDevice';
import type BaseDevice from '../server/devices/BaseDevice';
import MacDevice from '../server/devices/MacDevice';
import type Client from '../Client';
import type {UninitializedClient} from '../UninitializedClient';
import {isEqual} from 'lodash';
import {performance} from 'perf_hooks';
import type {Actions, Store} from '.';
import {WelcomeScreenStaticView} from '../sandy-chrome/WelcomeScreen';
import {getPluginKey, isDevicePluginDefinition} from '../utils/pluginUtils';
import {isDevicePluginDefinition} from '../utils/pluginUtils';
import {getPluginKey} from '../utils/pluginKey';
import {deconstructClientId} from '../utils/clientUtils';
import type {RegisterPluginAction} from './plugins';
import MetroDevice from '../devices/MetroDevice';
import MetroDevice from '../server/devices/MetroDevice';
import {Logger} from 'flipper-plugin';
export type StaticViewProps = {logger: Logger};

View File

@@ -18,7 +18,7 @@ import constants from '../fb-stubs/constants';
import {getInstance} from '../fb-stubs/Logger';
import {logPlatformSuccessRate} from '../utils/metrics';
export const SUPPORT_FORM_PREFIX = 'support-form-v2';
import {OS} from '../devices/BaseDevice';
import {OS} from '../server/devices/BaseDevice';
import {getExportablePlugins} from '../selectors/connections';
const {DEFAULT_SUPPORT_GROUP} = constants;

View File

@@ -18,7 +18,7 @@ import ScreenCaptureButtons from '../../chrome/ScreenCaptureButtons';
import MetroButton from '../../chrome/MetroButton';
import {BookmarkSection} from './BookmarkSection';
import Client from '../../Client';
import BaseDevice from '../../devices/BaseDevice';
import BaseDevice from '../../server/devices/BaseDevice';
import {ExclamationCircleOutlined, FieldTimeOutlined} from '@ant-design/icons';
import {useSelector} from 'react-redux';
import {

View File

@@ -25,7 +25,7 @@ import {
selectClient,
selectDevice,
} from '../../reducers/connections';
import BaseDevice, {OS} from '../../devices/BaseDevice';
import BaseDevice, {OS} from '../../server/devices/BaseDevice';
import Client from '../../Client';
import {State} from '../../reducers';
import {brandColors, brandIcons, colors} from '../../ui/components/colors';

View File

@@ -17,7 +17,7 @@ import {
} from '@ant-design/icons';
import {Store} from '../../reducers';
import {useStore} from '../../utils/useStore';
import {launchEmulator} from '../../devices/AndroidDevice';
import {launchEmulator} from '../../server/devices/AndroidDevice';
import {Layout, renderReactRoot, withTrackingScope} from 'flipper-plugin';
import {Provider} from 'react-redux';
import {

View File

@@ -23,9 +23,9 @@ import {useDispatch, useStore} from '../../utils/useStore';
import {getPluginTitle, getPluginTooltip} from '../../utils/pluginUtils';
import {selectPlugin} from '../../reducers/connections';
import Client from '../../Client';
import BaseDevice from '../../devices/BaseDevice';
import BaseDevice from '../../server/devices/BaseDevice';
import {DownloadablePluginDetails} from 'flipper-plugin-lib';
import MetroDevice from '../../devices/MetroDevice';
import MetroDevice from '../../server/devices/MetroDevice';
import {
DownloadablePluginState,
PluginDownloadStatus,

View File

@@ -17,11 +17,11 @@ import {createRootReducer} from '../../../reducers';
import {act} from 'react-dom/test-utils';
import {sleep} from 'flipper-plugin';
jest.mock('../../../devices/AndroidDevice', () => ({
jest.mock('../../../server/devices/AndroidDevice', () => ({
launchEmulator: jest.fn(() => Promise.resolve([])),
}));
import {launchEmulator} from '../../../devices/AndroidDevice';
import {launchEmulator} from '../../../server/devices/AndroidDevice';
test('Can render and launch android apps', async () => {
const store = createStore(createRootReducer());

View File

@@ -12,8 +12,8 @@ import {
MockFlipperResult,
} from '../../../test-utils/createMockFlipperWithPlugin';
import {FlipperPlugin} from '../../../plugin';
import MetroDevice from '../../../devices/MetroDevice';
import BaseDevice from '../../../devices/BaseDevice';
import MetroDevice from '../../../server/devices/MetroDevice';
import BaseDevice from '../../../server/devices/BaseDevice';
import {_SandyPluginDefinition} from 'flipper-plugin';
import {TestUtils} from 'flipper-plugin';
import {selectPlugin} from '../../../reducers/connections';

View File

@@ -7,7 +7,7 @@
* @format
*/
import MetroDevice from '../devices/MetroDevice';
import MetroDevice from '../server/devices/MetroDevice';
import {State} from '../reducers';
import {
computePluginLists,

View File

@@ -0,0 +1,31 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
/**
* A set of utilities that should be provided by the hosting environment
*/
export interface FlipperServerHost {}
let instance: FlipperServerHost | undefined;
export function getFlipperServerHost(): FlipperServerHost {
if (!instance) {
throw new Error(
'FlipperServerHost not set, call setFlipperServerHost first',
);
}
return instance;
}
export function setFlipperServerHost(impl: FlipperServerHost) {
if (instance) {
throw new Error('FlipperServerHost was already set');
}
instance = impl;
}

View File

@@ -11,7 +11,7 @@ import {
CertificateExchangeMedium,
SecureServerConfig,
} from '../utils/CertificateProvider';
import Client, {ClientQuery} from '../Client';
import Client, {ClientQuery} from '../../Client';
import {ClientConnection} from './ClientConnection';
import {transformCertificateExchangeMediumToType} from './Utilities';

View File

@@ -8,23 +8,23 @@
*/
import {CertificateExchangeMedium} from '../utils/CertificateProvider';
import {Logger} from '../fb-interfaces/Logger';
import {ClientQuery} from '../Client';
import {Store, State} from '../reducers/index';
import {Logger} from '../../fb-interfaces/Logger';
import {ClientQuery} from '../../Client';
import {Store, State} from '../../reducers/index';
import CertificateProvider from '../utils/CertificateProvider';
import Client from '../Client';
import Client from '../../Client';
import {ClientConnection, ConnectionStatus} from './ClientConnection';
import {UninitializedClient} from '../UninitializedClient';
import {reportPlatformFailures} from '../utils/metrics';
import {UninitializedClient} from '../../UninitializedClient';
import {reportPlatformFailures} from '../../utils/metrics';
import {EventEmitter} from 'events';
import invariant from 'invariant';
import GK from '../fb-stubs/GK';
import GK from '../../fb-stubs/GK';
import {initJsEmulatorIPC} from '../utils/js-client-server-utils/serverUtils';
import {buildClientId} from '../utils/clientUtils';
import JSDevice from '../devices/JSDevice';
import DummyDevice from '../devices/DummyDevice';
import BaseDevice from '../devices/BaseDevice';
import {sideEffect} from '../utils/sideEffect';
import {buildClientId} from '../../utils/clientUtils';
import JSDevice from '../../server/devices/JSDevice';
import DummyDevice from '../../server/devices/DummyDevice';
import BaseDevice from '../../server/devices/BaseDevice';
import {sideEffect} from '../../utils/sideEffect';
import {
appNameWithUpdateHint,
transformCertificateExchangeMediumToType,
@@ -79,7 +79,11 @@ class ServerController extends EventEmitter implements ServerEventsListener {
super();
this.logger = logger;
this.connections = new Map();
this.certificateProvider = new CertificateProvider(this, logger, store);
this.certificateProvider = new CertificateProvider(
this,
logger,
store.getState().settingsState,
);
this.connectionTracker = new ConnectionTracker(logger);
this.secureServer = null;
this.insecureServer = null;

View File

@@ -7,7 +7,7 @@
* @format
*/
import GK from '../fb-stubs/GK';
import GK from '../../fb-stubs/GK';
import {SecureServerConfig} from '../utils/CertificateProvider';
import ServerAdapter, {ServerEventsListener} from './ServerAdapter';
import ServerRSocket from './ServerRSocket';

View File

@@ -17,7 +17,7 @@ import net, {Socket} from 'net';
import {RSocketServer} from 'rsocket-core';
import RSocketTCPServer from 'rsocket-tcp-server';
import {Payload, ReactiveSocket, Responder} from 'rsocket-types';
import Client, {ClientQuery} from '../Client';
import Client, {ClientQuery} from '../../Client';
import {Single} from 'rsocket-flowable';
import {
ClientConnection,

View File

@@ -12,7 +12,7 @@ import WebSocket from 'ws';
import ws from 'ws';
import {SecureClientQuery, ServerEventsListener} from './ServerAdapter';
import querystring from 'querystring';
import Client, {ClientQuery} from '../Client';
import Client, {ClientQuery} from '../../Client';
import {OS} from '../devices/BaseDevice';
import {
ClientConnection,

View File

@@ -10,10 +10,10 @@
import ServerWebSocketBase from './ServerWebSocketBase';
import WebSocket from 'ws';
import querystring from 'querystring';
import Client, {ClientQuery} from '../Client';
import Client, {ClientQuery} from '../../Client';
import {BrowserClientFlipperConnection} from './BrowserClientFlipperConnection';
import {ServerEventsListener} from './ServerAdapter';
import constants from '../fb-stubs/constants';
import constants from '../../fb-stubs/constants';
import ws from 'ws';
import {IncomingMessage} from 'http';

View File

@@ -8,7 +8,7 @@
*/
import {CertificateExchangeMedium} from '../utils/CertificateProvider';
import {ClientQuery} from '../Client';
import {ClientQuery} from '../../Client';
/**
* Transforms the certificate exchange medium type as number to the

View File

@@ -10,7 +10,7 @@
import BaseDevice from './BaseDevice';
import type {DeviceType} from 'flipper-plugin';
import {OS, DeviceShell} from './BaseDevice';
import {SupportFormRequestDetailsState} from '../reducers/supportForm';
import {SupportFormRequestDetailsState} from '../../reducers/supportForm';
export default class ArchivedDevice extends BaseDevice {
isArchived = true;

View File

@@ -18,8 +18,8 @@ import {
createState,
getFlipperLib,
} from 'flipper-plugin';
import {PluginDefinition, DevicePluginMap} from '../plugin';
import {DeviceSpec, OS as PluginOS, PluginDetails} from 'flipper-plugin-lib';
import {getPluginKey} from '../../utils/pluginKey';
export type DeviceShell = {
stdout: stream.Readable;
@@ -29,6 +29,9 @@ export type DeviceShell = {
export type OS = PluginOS | 'Windows' | 'MacOS' | 'JSWebApp';
type PluginDefinition = _SandyPluginDefinition;
type PluginMap = Map<string, PluginDefinition>;
export type DeviceExport = {
os: OS;
title: string;
@@ -80,6 +83,7 @@ export default class BaseDevice {
// if imported, stores the original source location
source = '';
// TODO: ideally we don't want BasePlugin to know about the concept of plugins
sandyPluginStates: Map<string, _SandyDevicePluginInstance> = new Map<
string,
_SandyDevicePluginInstance
@@ -221,7 +225,7 @@ export default class BaseDevice {
}
loadDevicePlugins(
devicePlugins: DevicePluginMap,
devicePlugins: PluginMap,
enabledDevicePlugins: Set<string>,
pluginStates?: Record<string, any>,
) {
@@ -249,11 +253,7 @@ export default class BaseDevice {
plugin,
this,
// break circular dep, one of those days again...
require('../utils/pluginUtils').getPluginKey(
undefined,
{serial: this.serial},
plugin.id,
),
getPluginKey(undefined, {serial: this.serial}, plugin.id),
initialState,
),
);

View File

@@ -7,13 +7,12 @@
* @format
*/
import type {LogLevel, DeviceLogEntry, DeviceType} from 'flipper-plugin';
import {LogLevel, DeviceLogEntry, DeviceType, timeout} from 'flipper-plugin';
import child_process, {ChildProcess} from 'child_process';
import BaseDevice from './BaseDevice';
import JSONStream from 'JSONStream';
import {Transform} from 'stream';
import {exec} from 'promisify-child-process';
import {default as promiseTimeout} from '../utils/promiseTimeout';
import {
ERR_PHYSICAL_DEVICE_LOGS_WITHOUT_IDB,
IOSBridge,
@@ -230,7 +229,7 @@ export default class IOSDevice extends BaseDevice {
this.recordingProcess!.kill('SIGINT');
});
const output: string | null = await promiseTimeout<void>(
const output: string | null = await timeout<void>(
5000,
prom,
'Timed out to stop a screen capture.',

View File

@@ -8,11 +8,11 @@
*/
import BaseDevice from '../BaseDevice';
import * as DeviceTestPluginModule from '../../test-utils/DeviceTestPlugin';
import * as DeviceTestPluginModule from '../../../test-utils/DeviceTestPlugin';
import {TestUtils, _SandyPluginDefinition} from 'flipper-plugin';
import ArchivedDevice from '../ArchivedDevice';
import DummyDevice from '../DummyDevice';
import {createMockFlipperWithPlugin} from '../../test-utils/createMockFlipperWithPlugin';
import {createMockFlipperWithPlugin} from '../../../test-utils/createMockFlipperWithPlugin';
const physicalDevicePluginDetails = TestUtils.createMockPluginDetails({
id: 'physicalDevicePlugin',

View File

@@ -7,8 +7,8 @@
* @format
*/
import {Logger} from '../fb-interfaces/Logger';
import {internGraphPOSTAPIRequest} from '../fb-stubs/user';
import {Logger} from '../../fb-interfaces/Logger';
import {internGraphPOSTAPIRequest} from '../../fb-stubs/user';
import ServerController from '../comms/ServerController';
import {promisify} from 'util';
import fs from 'fs';
@@ -21,14 +21,13 @@ import {
import path from 'path';
import tmp, {DirOptions, FileOptions} from 'tmp';
import iosUtil from './iOSContainerUtility';
import {reportPlatformFailures} from './metrics';
import {reportPlatformFailures} from '../../utils/metrics';
import {getAdbClient} from './adbClient';
import * as androidUtil from './androidContainerUtility';
import os from 'os';
import {Client as ADBClient} from 'adbkit';
import {Store} from '../reducers/index';
import archiver from 'archiver';
import promiseTimeout from '../utils/promiseTimeout';
import {timeout} from 'flipper-plugin';
import {v4 as uuid} from 'uuid';
export type CertificateExchangeMedium = 'FS_ACCESS' | 'WWW';
@@ -71,6 +70,12 @@ export type SecureServerConfig = {
rejectUnauthorized: boolean;
};
type CertificateProviderConfig = {
idbPath: string;
androidHome: string;
enablePhysicalIOS: boolean;
};
/*
* This class is responsible for generating and deploying server and client
* certificates to allow for secure communication between Flipper and apps.
@@ -86,17 +91,21 @@ export default class CertificateProvider {
logger: Logger;
adb: Promise<ADBClient>;
certificateSetup: Promise<void>;
store: Store;
config: CertificateProviderConfig;
server: ServerController;
constructor(server: ServerController, logger: Logger, store: Store) {
constructor(
server: ServerController,
logger: Logger,
config: CertificateProviderConfig,
) {
this.logger = logger;
this.adb = getAdbClient(store);
this.adb = getAdbClient(config);
this.certificateSetup = reportPlatformFailures(
this.ensureServerCertExists(),
'ensureServerCertExists',
);
this.store = store;
this.config = config;
this.server = server;
}
@@ -104,7 +113,7 @@ export default class CertificateProvider {
const buff = await fsExtra.readFile(zipPath);
const file = new File([buff], 'certs.zip');
return reportPlatformFailures(
promiseTimeout(
timeout(
5 * 60 * 1000,
internGraphPOSTAPIRequest('flipper/certificates', {
certificate_zip: file,
@@ -345,7 +354,7 @@ export default class CertificateProvider {
filePath,
bundleId,
destination,
this.store.getState().settingsState.idbPath,
this.config.idbPath,
),
);
});
@@ -421,10 +430,7 @@ export default class CertificateProvider {
return Promise.resolve(matches[1]);
}
return iosUtil
.targets(
this.store.getState().settingsState.idbPath,
this.store.getState().settingsState.enablePhysicalIOS,
)
.targets(this.config.idbPath, this.config.enablePhysicalIOS)
.then((targets) => {
if (targets.length === 0) {
throw new Error('No iOS devices found');
@@ -493,7 +499,7 @@ export default class CertificateProvider {
originalFile,
bundleId,
path.join(dir, csrFileName),
this.store.getState().settingsState.idbPath,
this.config.idbPath,
)
.then(() => dir);
})

View File

@@ -13,7 +13,7 @@ import {DeviceType} from 'flipper-plugin-lib';
import {v1 as uuid} from 'uuid';
import path from 'path';
import {exec} from 'promisify-child-process';
import {getAppTempPath} from '../utils/pathUtils';
import {getAppTempPath} from '../../utils/pathUtils';
export const ERR_NO_IDB_OR_XCODE_AVAILABLE =
'Neither Xcode nor idb available. Cannot provide iOS device functionality.';

View File

@@ -7,20 +7,23 @@
* @format
*/
import {reportPlatformFailures} from './metrics';
import {reportPlatformFailures} from '../../utils/metrics';
import {execFile} from 'promisify-child-process';
import promiseRetry from 'promise-retry';
import adbConfig from '../utils/adbConfig';
import adbkit, {Client} from 'adbkit';
import {Store} from '../reducers/index';
import path from 'path';
const MAX_RETRIES = 5;
let instance: Promise<Client>;
export function getAdbClient(store: Store): Promise<Client> {
type Config = {
androidHome: string;
};
export function getAdbClient(config: Config): Promise<Client> {
if (!instance) {
instance = reportPlatformFailures(createClient(store), 'createADBClient');
instance = reportPlatformFailures(createClient(config), 'createADBClient');
}
return instance;
}
@@ -28,8 +31,8 @@ export function getAdbClient(store: Store): Promise<Client> {
/* Adbkit will attempt to start the adb server if it's not already running,
however, it sometimes fails with ENOENT errors. So instead, we start it
manually before requesting a client. */
function createClient(store: Store): Promise<Client> {
const androidHome = store.getState().settingsState.androidHome;
function createClient(config: Config): Promise<Client> {
const androidHome = config.androidHome;
const adbPath = path.resolve(androidHome, 'platform-tools/adb');
return reportPlatformFailures<Client>(
execFile(adbPath, ['start-server']).then(() =>

View File

@@ -12,7 +12,7 @@
* opaque types will ensure the commands are only ever run on validated
* arguments.
*/
import {UnsupportedError} from './metrics';
import {UnsupportedError} from '../../utils/metrics';
import adbkit, {Client} from 'adbkit';
const allowedAppNameRegex = /^[\w.-]+$/;

View File

@@ -11,7 +11,7 @@ import React from 'react';
import {Mutex} from 'async-mutex';
import {exec as unsafeExec, Output} from 'promisify-child-process';
import {killOrphanedInstrumentsProcesses} from './processCleanup';
import {reportPlatformFailures} from './metrics';
import {reportPlatformFailures} from '../../utils/metrics';
import {promises, constants} from 'fs';
import memoize from 'lodash.memoize';
import {notNull} from './typeUtils';
@@ -19,7 +19,7 @@ import {promisify} from 'util';
import child_process from 'child_process';
import fs from 'fs-extra';
import path from 'path';
import fbConfig from '../fb-stubs/config';
import fbConfig from '../../fb-stubs/config';
import {notification, Typography} from 'antd';
const exec = promisify(child_process.exec);

View File

@@ -7,7 +7,7 @@
* @format
*/
import Client, {ClientQuery} from '../../Client';
import Client, {ClientQuery} from '../../../Client';
import {
ClientConnection,
ConnectionStatus,
@@ -16,11 +16,11 @@ import {
} from '../../comms/ClientConnection';
import {ipcRenderer, remote, IpcRendererEvent} from 'electron';
import JSDevice from '../../devices/JSDevice';
import {Store} from '../../reducers';
import {Logger} from '../../fb-interfaces/Logger';
import {Store} from '../../../reducers';
import {Logger} from '../../../fb-interfaces/Logger';
import ServerController from '../../comms/ServerController';
import {buildClientId} from '../clientUtils';
import {destroyDevice} from '../../reducers/connections';
import {buildClientId} from '../../../utils/clientUtils';
import {destroyDevice} from '../../../reducers/connections';
const connections: Map<number, JSClientFlipperConnection> = new Map();

View File

@@ -0,0 +1,14 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
// Typescript doesn't know Array.filter(Boolean) won't contain nulls.
// So use Array.filter(notNull) instead.
export function notNull<T>(x: T | null | undefined): x is T {
return x !== null && x !== undefined;
}

View File

@@ -8,14 +8,14 @@
*/
import {createStore} from 'redux';
import BaseDevice from '../devices/BaseDevice';
import BaseDevice from '../server/devices/BaseDevice';
import {createRootReducer} from '../reducers';
import {Store} from '../reducers/index';
import Client, {ClientQuery} from '../Client';
import {
ClientConnection,
ConnectionStatusChange,
} from '../comms/ClientConnection';
} from '../server/comms/ClientConnection';
import {buildClientId} from '../utils/clientUtils';
import {Logger} from '../fb-interfaces/Logger';
import {PluginDefinition} from '../plugin';
@@ -24,7 +24,7 @@ import {getInstance} from '../fb-stubs/Logger';
import {initializeFlipperLibImplementation} from '../utils/flipperLibImplementation';
import pluginManager from '../dispatcher/pluginManager';
import {PluginDetails} from 'flipper-plugin-lib';
import ArchivedDevice from '../devices/ArchivedDevice';
import ArchivedDevice from '../server/devices/ArchivedDevice';
export interface AppOptions {
plugins?: PluginDefinition[];

View File

@@ -21,7 +21,7 @@ import {
selectDevice,
selectClient,
} from '../reducers/connections';
import BaseDevice from '../devices/BaseDevice';
import BaseDevice from '../server/devices/BaseDevice';
import {Store} from '../reducers/index';
import Client, {ClientQuery} from '../Client';
@@ -29,7 +29,9 @@ import Client, {ClientQuery} from '../Client';
import {Logger} from '../fb-interfaces/Logger';
import {FlipperDevicePlugin, FlipperPlugin, PluginDefinition} from '../plugin';
import PluginContainer from '../PluginContainer';
import {getPluginKey, isDevicePluginDefinition} from '../utils/pluginUtils';
import {isDevicePluginDefinition} from '../utils/pluginUtils';
import {getPluginKey} from '../utils/pluginKey';
import MockFlipper from './MockFlipper';
import {switchPlugin} from '../reducers/pluginManager';
import {createSandyPluginFromClassicPlugin} from '../dispatcher/plugins';

View File

@@ -9,8 +9,8 @@
import {State} from '../../reducers/index';
import configureStore from 'redux-mock-store';
import {default as BaseDevice} from '../../devices/BaseDevice';
import {default as ArchivedDevice} from '../../devices/ArchivedDevice';
import {default as BaseDevice} from '../../server/devices/BaseDevice';
import {default as ArchivedDevice} from '../../server/devices/ArchivedDevice';
import {
processStore,
determinePluginsToProcess,

View File

@@ -19,7 +19,7 @@ import {
selectDevice,
} from '../../reducers/connections';
import {processMessageQueue} from '../messageQueue';
import {getPluginKey} from '../pluginUtils';
import {getPluginKey} from '../pluginKey';
import {TestIdler} from '../Idler';
import {registerPlugins} from '../../reducers/plugins';
import {

View File

@@ -7,7 +7,7 @@
* @format
*/
import {getPluginKey} from '../pluginUtils';
import {getPluginKey} from '../pluginKey';
import {FlipperPlugin, FlipperDevicePlugin} from '../../plugin';
import {createMockFlipperWithPlugin} from '../../test-utils/createMockFlipperWithPlugin';
import {getExportablePlugins} from '../../selectors/connections';

View File

@@ -8,7 +8,7 @@
*/
import type Client from '../Client';
import type BaseDevice from '../devices/BaseDevice';
import type BaseDevice from '../server/devices/BaseDevice';
/* A Client uniuely identifies an app running on some device.

View File

@@ -12,15 +12,15 @@ import path from 'path';
import electron from 'electron';
import {getInstance as getLogger} from '../fb-stubs/Logger';
import {Store, MiddlewareAPI} from '../reducers';
import {DeviceExport} from '../devices/BaseDevice';
import {DeviceExport} from '../server/devices/BaseDevice';
import {State as PluginsState} from '../reducers/plugins';
import {PluginNotification} from '../reducers/notifications';
import Client, {ClientExport, ClientQuery} from '../Client';
import {getAppVersion} from './info';
import {pluginKey} from '../utils/pluginUtils';
import {pluginKey} from '../utils/pluginKey';
import {DevicePluginMap, ClientPluginMap} from '../plugin';
import {default as BaseDevice} from '../devices/BaseDevice';
import {default as ArchivedDevice} from '../devices/ArchivedDevice';
import {default as BaseDevice} from '../server/devices/BaseDevice';
import {default as ArchivedDevice} from '../server/devices/ArchivedDevice';
import fs from 'fs';
import {v4 as uuidv4} from 'uuid';
import {remote, OpenDialogOptions} from 'electron';

View File

@@ -12,7 +12,7 @@ import type {Logger} from '../fb-interfaces/Logger';
import type {Store} from '../reducers';
import createPaste from '../fb-stubs/createPaste';
import GK from '../fb-stubs/GK';
import type BaseDevice from '../devices/BaseDevice';
import type BaseDevice from '../server/devices/BaseDevice';
import {clipboard, shell} from 'electron';
import constants from '../fb-stubs/constants';
import {addNotification} from '../reducers/notifications';

View File

@@ -0,0 +1,27 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
export function getPluginKey(
selectedAppId: string | null | undefined,
baseDevice: {serial: string} | null | undefined,
pluginID: string,
): string {
if (selectedAppId) {
return `${selectedAppId}#${pluginID}`;
}
if (baseDevice) {
// If selected App is not defined, then the plugin is a device plugin
return `${baseDevice.serial}#${pluginID}`;
}
return `unknown#${pluginID}`;
}
export const pluginKey = (serial: string, pluginName: string): string => {
return `${serial}#${pluginName}`;
};

View File

@@ -10,7 +10,7 @@
import type {PluginDefinition} from '../plugin';
import type {State} from '../reducers';
import type {State as PluginsState} from '../reducers/plugins';
import type BaseDevice from '../devices/BaseDevice';
import type BaseDevice from '../server/devices/BaseDevice';
import type Client from '../Client';
import type {
ActivatablePluginDetails,
@@ -19,6 +19,7 @@ import type {
PluginDetails,
} from 'flipper-plugin-lib';
import {getLatestCompatibleVersionOfEachPlugin} from '../dispatcher/plugins';
import {getPluginKey} from './pluginKey';
export type PluginLists = {
devicePlugins: PluginDefinition[];
@@ -63,25 +64,6 @@ export function pluginsClassMap(
]);
}
export function getPluginKey(
selectedAppId: string | null | undefined,
baseDevice: {serial: string} | null | undefined,
pluginID: string,
): string {
if (selectedAppId) {
return `${selectedAppId}#${pluginID}`;
}
if (baseDevice) {
// If selected App is not defined, then the plugin is a device plugin
return `${baseDevice.serial}#${pluginID}`;
}
return `unknown#${pluginID}`;
}
export const pluginKey = (serial: string, pluginName: string): string => {
return `${serial}#${pluginName}`;
};
export function computeExportablePlugins(
state: Pick<State, 'plugins' | 'connections' | 'pluginMessageQueue'>,
device: BaseDevice | null,

View File

@@ -7,21 +7,22 @@
* @format
*/
import {sleep} from 'flipper-plugin';
import {timeout} from 'flipper-plugin';
import {StatusMessageType} from '../reducers/application';
/**
* @deprecated use timeout from flipper-plugin
* @param ms @
* @param promise
* @param timeoutMessage
* @returns
*/
export default function promiseTimeout<T>(
ms: number,
promise: Promise<T>,
timeoutMessage?: string,
): Promise<T> {
// Create a promise that rejects in <ms> milliseconds
const timeout = sleep(ms).then(() => {
throw new Error(timeoutMessage || `Timed out in ${ms} ms.`);
});
// Returns a race between our timeout and the passed in promise
return Promise.race([promise, timeout]);
return timeout(ms, promise, timeoutMessage);
}
export function showStatusUpdatesForPromise<T>(

View File

@@ -8,7 +8,7 @@
*/
import {State} from '../reducers/index';
import {DeviceExport} from '../devices/BaseDevice';
import {DeviceExport} from '../server/devices/BaseDevice';
export const stateSanitizer = (state: State) => {
if (state.connections && state.connections.devices) {

View File

@@ -9,7 +9,7 @@
import fs from 'fs';
import path from 'path';
import BaseDevice from '../devices/BaseDevice';
import BaseDevice from '../server/devices/BaseDevice';
import {reportPlatformFailures} from './metrics';
import expandTilde from 'expand-tilde';
import {remote} from 'electron';

View File

@@ -61,6 +61,7 @@ test('Correct top level API exposed', () => {
"styled",
"textContent",
"theme",
"timeout",
"useLocalStorageState",
"useLogger",
"useMemoize",

View File

@@ -76,6 +76,8 @@ export {
export {DataFormatter} from './ui/DataFormatter';
export {sleep} from './utils/sleep';
export {timeout} from './utils/timeout';
export {
LogTypes,
TrackType,

View File

@@ -0,0 +1,24 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
import {sleep} from './sleep';
export function timeout<T>(
ms: number,
promise: Promise<T>,
timeoutMessage?: string,
): Promise<T> {
// Create a promise that rejects in <ms> milliseconds
const timeout = sleep(ms).then(() => {
throw new Error(timeoutMessage || `Timed out in ${ms} ms.`);
});
// Returns a race between our timeout and the passed in promise
return Promise.race([promise, timeout]);
}

View File

@@ -1044,6 +1044,10 @@ Usage: `await sleep(1000)`
Creates a promise that automatically resolves after the specified amount of milliseconds.
## timeout
Usage `await timeout(1000, promise, message?)`
## styled
A convenience re-export of `styled` from [emotion](https://emotion.sh/docs/styled).