Move app/server to flipper-server-core
Summary: moved `app/src/server` to `flipper-server-core/src` and fixed any fallout from that (aka integration points I missed on the preparing diffs). Reviewed By: passy Differential Revision: D31541378 fbshipit-source-id: 8a7e0169ebefa515781f6e5e0f7b926415d4b7e9
This commit is contained in:
committed by
Facebook GitHub Bot
parent
3e7a6b1b4b
commit
d88b28330a
@@ -22,7 +22,6 @@
|
||||
"@tanishiking/aho-corasick": "^0.0.1",
|
||||
"@types/archiver": "^5.1.1",
|
||||
"@types/uuid": "^8.3.1",
|
||||
"JSONStream": "^1.3.1",
|
||||
"adbkit": "^2.11.1",
|
||||
"adbkit-logcat": "^2.0.1",
|
||||
"antd": "4.16.8",
|
||||
@@ -69,12 +68,7 @@
|
||||
"redux": "^4.1.1",
|
||||
"redux-persist": "^6.0.0",
|
||||
"reselect": "^4.0.0",
|
||||
"rsocket-core": "^0.0.27",
|
||||
"rsocket-flowable": "^0.0.27",
|
||||
"rsocket-tcp-server": "^0.0.25",
|
||||
"rsocket-types": "^0.0.25",
|
||||
"semver": "^7.3.5",
|
||||
"split2": "^3.2.2",
|
||||
"tmp": "^0.2.1",
|
||||
"uuid": "^8.3.2",
|
||||
"which": "^2.0.1",
|
||||
|
||||
@@ -94,7 +94,7 @@ const handleError = (
|
||||
crashReporterPlugin.instanceApi.reportCrash(payload);
|
||||
};
|
||||
|
||||
interface ClientConnection {
|
||||
export interface ClientConnection {
|
||||
send(data: any): void;
|
||||
sendExpectResponse(data: any): Promise<ClientResponseType>;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,12 @@ Object {
|
||||
"TestPlugin",
|
||||
],
|
||||
},
|
||||
"flipperServer": undefined,
|
||||
"flipperServer": Object {
|
||||
"close": [MockFunction],
|
||||
"exec": [MockFunction],
|
||||
"off": [MockFunction],
|
||||
"on": [MockFunction],
|
||||
},
|
||||
"selectedAppId": "TestApp#Android#MockAndroidDevice#serial",
|
||||
"selectedAppPluginListRevision": 0,
|
||||
"selectedDevice": Object {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
import React, {useCallback, useEffect, useState} from 'react';
|
||||
import {MetroReportableEvent} from '../server/devices/metro/MetroDevice';
|
||||
import {MetroReportableEvent} from 'flipper-common';
|
||||
import {useStore} from '../utils/useStore';
|
||||
import {Button as AntButton} from 'antd';
|
||||
import {MenuOutlined, ReloadOutlined} from '@ant-design/icons';
|
||||
|
||||
@@ -38,7 +38,6 @@ type OwnProps = {
|
||||
type StateFromProps = {
|
||||
settings: Settings;
|
||||
launcherSettings: LauncherSettings;
|
||||
isXcodeDetected: boolean;
|
||||
};
|
||||
|
||||
type DispatchFromProps = {
|
||||
@@ -356,11 +355,9 @@ class SettingsSheet extends Component<Props, State> {
|
||||
}
|
||||
|
||||
export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
|
||||
({settingsState, launcherSettingsState, connections}) => ({
|
||||
({settingsState, launcherSettingsState}) => ({
|
||||
settings: settingsState,
|
||||
launcherSettings: launcherSettingsState,
|
||||
isXcodeDetected:
|
||||
connections.flipperServer?.ios.xcodeCommandLineToolsDetected ?? false,
|
||||
}),
|
||||
{updateSettings, updateLauncherSettings},
|
||||
)(withTrackingScope(SettingsSheet));
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import * as DeviceTestPluginModule from '../../../test-utils/DeviceTestPlugin';
|
||||
import * as DeviceTestPluginModule from '../../test-utils/DeviceTestPlugin';
|
||||
import {TestUtils, _SandyPluginDefinition} from 'flipper-plugin';
|
||||
import {createMockFlipperWithPlugin} from '../../../test-utils/createMockFlipperWithPlugin';
|
||||
import {TestDevice} from '../../../test-utils/TestDevice';
|
||||
import ArchivedDevice from '../../../devices/ArchivedDevice';
|
||||
import {createMockFlipperWithPlugin} from '../../test-utils/createMockFlipperWithPlugin';
|
||||
import {TestDevice} from '../../test-utils/TestDevice';
|
||||
import ArchivedDevice from '../../devices/ArchivedDevice';
|
||||
|
||||
const physicalDevicePluginDetails = TestUtils.createMockPluginDetails({
|
||||
id: 'physicalDevicePlugin',
|
||||
@@ -12,7 +12,6 @@
|
||||
import {remote, ipcRenderer, IpcRendererEvent} from 'electron';
|
||||
import {Store} from '../reducers/index';
|
||||
import {Logger} from 'flipper-common';
|
||||
import {parseFlipperPorts} from '../server/utils/environmentVariables';
|
||||
import {
|
||||
importFileToStore,
|
||||
IMPORT_FLIPPER_TRACE_EVENT,
|
||||
@@ -80,36 +79,4 @@ export default (store: Store, logger: Logger) => {
|
||||
}, `${IMPORT_FLIPPER_TRACE_EVENT}:Deeplink`);
|
||||
},
|
||||
);
|
||||
|
||||
if (process.env.FLIPPER_PORTS) {
|
||||
const portOverrides = parseFlipperPorts(process.env.FLIPPER_PORTS);
|
||||
if (portOverrides) {
|
||||
store.dispatch({
|
||||
type: 'SET_SERVER_PORTS',
|
||||
payload: portOverrides,
|
||||
});
|
||||
} else {
|
||||
console.error(
|
||||
`Ignoring malformed FLIPPER_PORTS env variable:
|
||||
"${process.env.FLIPPER_PORTS || ''}".
|
||||
Example expected format: "1111,2222".`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (process.env.FLIPPER_ALT_PORTS) {
|
||||
const portOverrides = parseFlipperPorts(process.env.FLIPPER_ALT_PORTS);
|
||||
if (portOverrides) {
|
||||
store.dispatch({
|
||||
type: 'SET_ALT_SERVER_PORTS',
|
||||
payload: portOverrides,
|
||||
});
|
||||
} else {
|
||||
console.error(
|
||||
`Ignoring malformed FLIPPER_ALT_PORTS env variable:
|
||||
"${process.env.FLIPPER_ALT_PORTS || ''}".
|
||||
Example expected format: "1111,2222".`,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -10,10 +10,7 @@
|
||||
import React from 'react';
|
||||
import {State, Store} from '../reducers/index';
|
||||
import {Logger} from 'flipper-common';
|
||||
import {
|
||||
FlipperServerConfig,
|
||||
FlipperServerImpl,
|
||||
} from '../server/FlipperServerImpl';
|
||||
import {FlipperServerImpl, setFlipperServerConfig} from 'flipper-server-core';
|
||||
import {selectClient} from '../reducers/connections';
|
||||
import Client from '../Client';
|
||||
import {notification} from 'antd';
|
||||
@@ -21,22 +18,23 @@ import BaseDevice from '../devices/BaseDevice';
|
||||
import {ClientDescription, timeout} from 'flipper-common';
|
||||
import {reportPlatformFailures} from 'flipper-common';
|
||||
import {sideEffect} from '../utils/sideEffect';
|
||||
import {getAppTempPath, getStaticPath} from '../utils/pathUtils';
|
||||
import constants from '../fb-stubs/constants';
|
||||
|
||||
export default async (store: Store, logger: Logger) => {
|
||||
const {enableAndroid, androidHome, idbPath, enableIOS, enablePhysicalIOS} =
|
||||
store.getState().settingsState;
|
||||
const server = new FlipperServerImpl(
|
||||
{
|
||||
setFlipperServerConfig({
|
||||
enableAndroid,
|
||||
androidHome,
|
||||
idbPath,
|
||||
enableIOS,
|
||||
enablePhysicalIOS,
|
||||
serverPorts: store.getState().application.serverPorts,
|
||||
altServerPorts: store.getState().application.altServerPorts,
|
||||
} as FlipperServerConfig,
|
||||
logger,
|
||||
);
|
||||
staticPath: getStaticPath(),
|
||||
tmpPath: getAppTempPath(),
|
||||
validWebSocketOrigins: constants.VALID_WEB_SOCKET_REQUEST_ORIGIN_PREFIXES,
|
||||
});
|
||||
const server = new FlipperServerImpl(logger);
|
||||
|
||||
store.dispatch({
|
||||
type: 'SET_FLIPPER_SERVER',
|
||||
|
||||
@@ -43,7 +43,7 @@ import {
|
||||
getClientsByAppName,
|
||||
getAllClients,
|
||||
} from '../reducers/connections';
|
||||
import {deconstructClientId} from '../utils/clientUtils';
|
||||
import {deconstructClientId} from 'flipper-common';
|
||||
import {clearMessageQueue} from '../reducers/pluginMessageQueue';
|
||||
import {
|
||||
isDevicePluginDefinition,
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
} from '../reducers/usageTracking';
|
||||
import produce from 'immer';
|
||||
import BaseDevice from '../devices/BaseDevice';
|
||||
import {deconstructClientId} from '../utils/clientUtils';
|
||||
import {deconstructClientId} from 'flipper-common';
|
||||
import {getCPUUsage} from 'process';
|
||||
import {sideEffect} from '../utils/sideEffect';
|
||||
import {getSelectionInfo} from '../utils/info';
|
||||
|
||||
@@ -126,7 +126,6 @@ export {Rect} from './utils/geometry';
|
||||
export {Logger} from 'flipper-common';
|
||||
export {getLogger} from 'flipper-common';
|
||||
export {callVSCode} from './utils/vscodeUtils';
|
||||
export {checkIdbIsInstalled} from './server/devices/ios/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
|
||||
|
||||
@@ -51,12 +51,13 @@ import {getVersionString} from './utils/versionString';
|
||||
import {PersistGate} from 'redux-persist/integration/react';
|
||||
// eslint-disable-next-line flipper/no-electron-remote-imports
|
||||
import {ipcRenderer, remote} from 'electron';
|
||||
import {helloWorld} from 'flipper-server-core';
|
||||
import {setLoggerInstance, setUserSessionManagerInstance} from 'flipper-common';
|
||||
import {
|
||||
setLoggerInstance,
|
||||
setUserSessionManagerInstance,
|
||||
GK as flipperCommonGK,
|
||||
} from 'flipper-common';
|
||||
import {internGraphPOSTAPIRequest} from './fb-stubs/user';
|
||||
|
||||
helloWorld();
|
||||
|
||||
if (process.env.NODE_ENV === 'development' && os.platform() === 'darwin') {
|
||||
// By default Node.JS has its internal certificate storage and doesn't use
|
||||
// the system store. Because of this, it's impossible to access ondemand / devserver
|
||||
@@ -186,6 +187,8 @@ function setProcessState(store: Store) {
|
||||
}
|
||||
|
||||
function init() {
|
||||
// TODO: centralise all those initialisations in a single configuration call
|
||||
flipperCommonGK.get = (name) => GK.get(name);
|
||||
const store = getStore();
|
||||
const logger = initLogger(store);
|
||||
setLoggerInstance(logger);
|
||||
|
||||
@@ -17,10 +17,6 @@ export type LauncherMsg = {
|
||||
message: string;
|
||||
severity: 'warning' | 'error';
|
||||
};
|
||||
export type ServerPorts = {
|
||||
insecure: number;
|
||||
secure: number;
|
||||
};
|
||||
|
||||
export type StatusMessageType = {
|
||||
msg: string;
|
||||
@@ -49,8 +45,6 @@ export type State = {
|
||||
windowIsFocused: boolean;
|
||||
share: ShareType | null;
|
||||
sessionId: string | null;
|
||||
serverPorts: ServerPorts;
|
||||
altServerPorts: ServerPorts;
|
||||
launcherMsg: LauncherMsg;
|
||||
statusMessages: Array<string>;
|
||||
};
|
||||
@@ -69,20 +63,6 @@ export type Action =
|
||||
type: 'windowIsFocused';
|
||||
payload: {isFocused: boolean; time: number};
|
||||
}
|
||||
| {
|
||||
type: 'SET_SERVER_PORTS';
|
||||
payload: {
|
||||
insecure: number;
|
||||
secure: number;
|
||||
};
|
||||
}
|
||||
| {
|
||||
type: 'SET_ALT_SERVER_PORTS';
|
||||
payload: {
|
||||
insecure: number;
|
||||
secure: number;
|
||||
};
|
||||
}
|
||||
| {
|
||||
type: 'LAUNCHER_MSG';
|
||||
payload: {
|
||||
@@ -107,14 +87,6 @@ export const initialState: () => State = () => ({
|
||||
activeSheet: null,
|
||||
share: null,
|
||||
sessionId: uuidv1(),
|
||||
serverPorts: {
|
||||
insecure: 8089,
|
||||
secure: 8088,
|
||||
},
|
||||
altServerPorts: {
|
||||
insecure: 9089,
|
||||
secure: 9088,
|
||||
},
|
||||
launcherMsg: {
|
||||
severity: 'warning',
|
||||
message: '',
|
||||
@@ -163,16 +135,6 @@ export default function reducer(
|
||||
...state,
|
||||
windowIsFocused: action.payload.isFocused,
|
||||
};
|
||||
} else if (action.type === 'SET_SERVER_PORTS') {
|
||||
return {
|
||||
...state,
|
||||
serverPorts: action.payload,
|
||||
};
|
||||
} else if (action.type === 'SET_ALT_SERVER_PORTS') {
|
||||
return {
|
||||
...state,
|
||||
altServerPorts: action.payload,
|
||||
};
|
||||
} else if (action.type === 'LAUNCHER_MSG') {
|
||||
return {
|
||||
...state,
|
||||
|
||||
@@ -12,16 +12,20 @@ import {produce} from 'immer';
|
||||
|
||||
import type BaseDevice from '../devices/BaseDevice';
|
||||
import type Client from '../Client';
|
||||
import type {UninitializedClient, DeviceOS, Logger} from 'flipper-common';
|
||||
import type {
|
||||
UninitializedClient,
|
||||
DeviceOS,
|
||||
Logger,
|
||||
FlipperServer,
|
||||
} from 'flipper-common';
|
||||
import {performance} from 'perf_hooks';
|
||||
import type {Actions} from '.';
|
||||
import {WelcomeScreenStaticView} from '../sandy-chrome/WelcomeScreen';
|
||||
import {isDevicePluginDefinition} from '../utils/pluginUtils';
|
||||
import {getPluginKey} from '../utils/pluginKey';
|
||||
|
||||
import {deconstructClientId} from '../utils/clientUtils';
|
||||
import {deconstructClientId} from 'flipper-common';
|
||||
import type {RegisterPluginAction} from './plugins';
|
||||
import {FlipperServerImpl} from '../server/FlipperServerImpl';
|
||||
import {shallowEqual} from 'react-redux';
|
||||
|
||||
export type StaticViewProps = {logger: Logger};
|
||||
@@ -74,7 +78,7 @@ type StateV2 = {
|
||||
deepLinkPayload: unknown;
|
||||
staticView: StaticView;
|
||||
selectedAppPluginListRevision: number;
|
||||
flipperServer: FlipperServerImpl | undefined;
|
||||
flipperServer: FlipperServer | undefined;
|
||||
};
|
||||
|
||||
type StateV1 = Omit<StateV2, 'enabledPlugins' | 'enabledDevicePlugins'> & {
|
||||
@@ -158,7 +162,7 @@ export type Action =
|
||||
}
|
||||
| {
|
||||
type: 'SET_FLIPPER_SERVER';
|
||||
payload: FlipperServerImpl;
|
||||
payload: FlipperServer;
|
||||
}
|
||||
| RegisterPluginAction;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
import produce from 'immer';
|
||||
import {deconstructPluginKey} from '../utils/clientUtils';
|
||||
import {deconstructPluginKey} from 'flipper-common';
|
||||
|
||||
export const DEFAULT_MAX_QUEUE_SIZE = 10000;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
import {Actions, Store} from './';
|
||||
import {setStaticView} from './connections';
|
||||
import {deconstructClientId} from '../utils/clientUtils';
|
||||
import {deconstructClientId} from 'flipper-common';
|
||||
import {switchPlugin} from './pluginManager';
|
||||
import {showStatusUpdatesForDuration} from '../utils/promiseTimeout';
|
||||
import {selectedPlugins as setSelectedPlugins} from './plugins';
|
||||
|
||||
@@ -17,13 +17,9 @@ import {
|
||||
} from '@ant-design/icons';
|
||||
import {Store} from '../../reducers';
|
||||
import {useStore} from '../../utils/useStore';
|
||||
import {launchEmulator} from '../../server/devices/android/AndroidDevice';
|
||||
import {Layout, renderReactRoot, withTrackingScope} from 'flipper-plugin';
|
||||
import {Provider} from 'react-redux';
|
||||
import {
|
||||
launchSimulator, // TODO: move to iOSDeviceManager
|
||||
IOSDeviceParams,
|
||||
} from '../../server/devices/ios/iOSDeviceManager';
|
||||
import {IOSDeviceParams} from 'flipper-common';
|
||||
|
||||
const COLD_BOOT = 'cold-boot';
|
||||
|
||||
@@ -36,26 +32,12 @@ export function showEmulatorLauncher(store: Store) {
|
||||
}
|
||||
|
||||
function LaunchEmulatorContainer({onClose}: {onClose: () => void}) {
|
||||
const flipperServer = useStore((state) => state.connections.flipperServer);
|
||||
return (
|
||||
<LaunchEmulatorDialog
|
||||
onClose={onClose}
|
||||
getSimulators={() => flipperServer!.ios.getSimulators(false)}
|
||||
getEmulators={() => flipperServer!.android.getAndroidEmulators()}
|
||||
/>
|
||||
);
|
||||
return <LaunchEmulatorDialog onClose={onClose} />;
|
||||
}
|
||||
|
||||
export const LaunchEmulatorDialog = withTrackingScope(
|
||||
function LaunchEmulatorDialog({
|
||||
onClose,
|
||||
getSimulators,
|
||||
getEmulators,
|
||||
}: {
|
||||
onClose: () => void;
|
||||
getSimulators: () => Promise<IOSDeviceParams[]>;
|
||||
getEmulators: () => Promise<string[]>;
|
||||
}) {
|
||||
function LaunchEmulatorDialog({onClose}: {onClose: () => void}) {
|
||||
const flipperServer = useStore((state) => state.connections.flipperServer);
|
||||
const iosEnabled = useStore((state) => state.settingsState.enableIOS);
|
||||
const androidEnabled = useStore(
|
||||
(state) => state.settingsState.enableAndroid,
|
||||
@@ -63,12 +45,12 @@ export const LaunchEmulatorDialog = withTrackingScope(
|
||||
const [iosEmulators, setIosEmulators] = useState<IOSDeviceParams[]>([]);
|
||||
const [androidEmulators, setAndroidEmulators] = useState<string[]>([]);
|
||||
|
||||
const store = useStore();
|
||||
useEffect(() => {
|
||||
if (!iosEnabled) {
|
||||
return;
|
||||
}
|
||||
getSimulators()
|
||||
flipperServer!
|
||||
.exec('ios-get-simulators', false)
|
||||
.then((emulators) => {
|
||||
setIosEmulators(
|
||||
emulators.filter(
|
||||
@@ -81,20 +63,21 @@ export const LaunchEmulatorDialog = withTrackingScope(
|
||||
.catch((e) => {
|
||||
console.warn('Failed to find simulators', e);
|
||||
});
|
||||
}, [iosEnabled, getSimulators, store]);
|
||||
}, [iosEnabled, flipperServer]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!androidEnabled) {
|
||||
return;
|
||||
}
|
||||
getEmulators()
|
||||
flipperServer!
|
||||
.exec('android-get-emulators')
|
||||
.then((emulators) => {
|
||||
setAndroidEmulators(emulators);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.warn('Failed to find emulators', e);
|
||||
});
|
||||
}, [androidEnabled, getEmulators]);
|
||||
}, [androidEnabled, flipperServer]);
|
||||
|
||||
const items = [
|
||||
...(androidEmulators.length > 0
|
||||
@@ -102,7 +85,8 @@ export const LaunchEmulatorDialog = withTrackingScope(
|
||||
: []),
|
||||
...androidEmulators.map((name) => {
|
||||
const launch = (coldBoot: boolean) => {
|
||||
launchEmulator(name, coldBoot)
|
||||
flipperServer!
|
||||
.exec('android-launch-emulator', name, coldBoot)
|
||||
.then(onClose)
|
||||
.catch((e) => {
|
||||
console.error('Failed to start emulator: ', e);
|
||||
@@ -139,7 +123,8 @@ export const LaunchEmulatorDialog = withTrackingScope(
|
||||
<Button
|
||||
key={device.udid}
|
||||
onClick={() =>
|
||||
launchSimulator(device.udid)
|
||||
flipperServer!
|
||||
.exec('ios-launch-simulator', device.udid)
|
||||
.catch((e) => {
|
||||
console.error('Failed to start simulator: ', e);
|
||||
message.error('Failed to start simulator: ' + e);
|
||||
|
||||
@@ -15,23 +15,23 @@ import {LaunchEmulatorDialog} from '../LaunchEmulator';
|
||||
|
||||
import {createRootReducer} from '../../../reducers';
|
||||
import {sleep} from 'flipper-plugin';
|
||||
|
||||
import {launchEmulator} from '../../../server/devices/android/AndroidDevice';
|
||||
jest.mock('../../../server/devices/android/AndroidDevice', () => ({
|
||||
launchEmulator: jest.fn(() => Promise.resolve([])),
|
||||
}));
|
||||
import {createFlipperServerMock} from '../../../test-utils/createFlipperServerMock';
|
||||
|
||||
test('Can render and launch android apps - empty', async () => {
|
||||
const store = createStore(createRootReducer());
|
||||
const mockServer = createFlipperServerMock({
|
||||
'ios-get-simulators': () => Promise.resolve([]),
|
||||
'android-get-emulators': () => Promise.resolve([]),
|
||||
});
|
||||
store.dispatch({
|
||||
type: 'SET_FLIPPER_SERVER',
|
||||
payload: mockServer,
|
||||
});
|
||||
const onClose = jest.fn();
|
||||
|
||||
const renderer = render(
|
||||
<Provider store={store}>
|
||||
<LaunchEmulatorDialog
|
||||
onClose={onClose}
|
||||
getSimulators={() => Promise.resolve([])}
|
||||
getEmulators={() => Promise.resolve([])}
|
||||
/>
|
||||
<LaunchEmulatorDialog onClose={onClose} />
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
@@ -45,7 +45,21 @@ test('Can render and launch android apps - empty', async () => {
|
||||
});
|
||||
|
||||
test('Can render and launch android apps', async () => {
|
||||
let p: Promise<any> | undefined = undefined;
|
||||
|
||||
const store = createStore(createRootReducer());
|
||||
const launch = jest.fn().mockImplementation(() => Promise.resolve());
|
||||
const mockServer = createFlipperServerMock({
|
||||
'ios-get-simulators': () => Promise.resolve([]),
|
||||
'android-get-emulators': () =>
|
||||
(p = Promise.resolve(['emulator1', 'emulator2'])),
|
||||
'android-launch-emulator': launch,
|
||||
});
|
||||
store.dispatch({
|
||||
type: 'SET_FLIPPER_SERVER',
|
||||
payload: mockServer,
|
||||
});
|
||||
|
||||
store.dispatch({
|
||||
type: 'UPDATE_SETTINGS',
|
||||
payload: {
|
||||
@@ -55,15 +69,9 @@ test('Can render and launch android apps', async () => {
|
||||
});
|
||||
const onClose = jest.fn();
|
||||
|
||||
let p: Promise<any> | undefined = undefined;
|
||||
|
||||
const renderer = render(
|
||||
<Provider store={store}>
|
||||
<LaunchEmulatorDialog
|
||||
onClose={onClose}
|
||||
getSimulators={() => Promise.resolve([])}
|
||||
getEmulators={() => (p = Promise.resolve(['emulator1', 'emulator2']))}
|
||||
/>
|
||||
<LaunchEmulatorDialog onClose={onClose} />
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
@@ -84,5 +92,5 @@ test('Can render and launch android apps', async () => {
|
||||
fireEvent.click(renderer.getByText('emulator2'));
|
||||
await sleep(1000);
|
||||
expect(onClose).toBeCalled();
|
||||
expect(launchEmulator).toBeCalledWith('emulator2', false);
|
||||
expect(launch).toBeCalledWith('emulator2', false);
|
||||
});
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
@@ -11,13 +11,8 @@ import {createStore} from 'redux';
|
||||
import BaseDevice from '../devices/BaseDevice';
|
||||
import {createRootReducer} from '../reducers';
|
||||
import {Store} from '../reducers/index';
|
||||
import Client from '../Client';
|
||||
import {
|
||||
ClientConnection,
|
||||
ConnectionStatusChange,
|
||||
} from '../server/comms/ClientConnection';
|
||||
import {buildClientId} from '../utils/clientUtils';
|
||||
import {Logger} from 'flipper-common';
|
||||
import Client, {ClientConnection} from '../Client';
|
||||
import {Logger, buildClientId, FlipperServer} from 'flipper-common';
|
||||
import {PluginDefinition} from '../plugin';
|
||||
import {registerPlugins} from '../reducers/plugins';
|
||||
import {getLogger} from 'flipper-common';
|
||||
@@ -27,6 +22,7 @@ import {PluginDetails} from 'flipper-plugin-lib';
|
||||
import ArchivedDevice from '../devices/ArchivedDevice';
|
||||
import {ClientQuery, DeviceOS} from 'flipper-common';
|
||||
import {TestDevice} from './TestDevice';
|
||||
import {createFlipperServerMock} from './createFlipperServerMock';
|
||||
|
||||
export interface AppOptions {
|
||||
plugins?: PluginDefinition[];
|
||||
@@ -56,6 +52,7 @@ export default class MockFlipper {
|
||||
private _clients: Client[] = [];
|
||||
private _deviceCounter: number = 0;
|
||||
private _clientCounter: number = 0;
|
||||
private _flipperServer: FlipperServer = createFlipperServerMock();
|
||||
|
||||
public get store(): Store {
|
||||
return this._store;
|
||||
@@ -89,6 +86,10 @@ export default class MockFlipper {
|
||||
});
|
||||
initializeFlipperLibImplementation(this._store, this._logger);
|
||||
this._store.dispatch(registerPlugins(plugins ?? []));
|
||||
this._store.dispatch({
|
||||
type: 'SET_FLIPPER_SERVER',
|
||||
payload: this._flipperServer,
|
||||
});
|
||||
}
|
||||
|
||||
public async initWithDeviceAndClient(
|
||||
@@ -237,12 +238,9 @@ export default class MockFlipper {
|
||||
return client;
|
||||
}
|
||||
}
|
||||
function createStubConnection(): ClientConnection | null | undefined {
|
||||
|
||||
function createStubConnection(): ClientConnection {
|
||||
return {
|
||||
subscribeToEvents(_: ConnectionStatusChange) {},
|
||||
close() {
|
||||
throw new Error('Should not be called in test');
|
||||
},
|
||||
send(_: any) {
|
||||
throw new Error('Should not be called in test');
|
||||
},
|
||||
|
||||
32
desktop/app/src/test-utils/createFlipperServerMock.tsx
Normal file
32
desktop/app/src/test-utils/createFlipperServerMock.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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 {FlipperServer, FlipperServerCommands} from 'flipper-common';
|
||||
|
||||
export function createFlipperServerMock(
|
||||
overrides?: Partial<FlipperServerCommands>,
|
||||
): FlipperServer {
|
||||
return {
|
||||
on: jest.fn(),
|
||||
off: jest.fn(),
|
||||
exec: jest
|
||||
.fn()
|
||||
.mockImplementation(
|
||||
(cmd: keyof FlipperServerCommands, ...args: any[]) => {
|
||||
if (overrides?.[cmd]) {
|
||||
return (overrides[cmd] as any)(...args);
|
||||
}
|
||||
return Promise.reject(
|
||||
new Error(`FlipperServerMock exec not implemented: ${cmd}}`),
|
||||
);
|
||||
},
|
||||
),
|
||||
close: jest.fn(),
|
||||
};
|
||||
}
|
||||
@@ -7,39 +7,10 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import {deconstructClientId} from 'flipper-common';
|
||||
import type Client from '../Client';
|
||||
import type BaseDevice from '../devices/BaseDevice';
|
||||
|
||||
/* A Client uniuely identifies an app running on some device.
|
||||
|
||||
Always use this utility to construct and parse clientId strings.
|
||||
*/
|
||||
export type ClientIdConstituents = {
|
||||
app: string;
|
||||
os: string;
|
||||
device: string;
|
||||
device_id: string;
|
||||
};
|
||||
|
||||
/* A plugin key is a string uniquely identifying an instance of a plugin.
|
||||
This can be a device plugin for a particular device, or a client plugin for a particular client (app).
|
||||
In the device plugin case, the "client" is the device it's connected to.
|
||||
In the client plugin case (normal plugins), the "client" is the app it's connected to.
|
||||
|
||||
Always use this utility to construct and parse pluginKey strings.
|
||||
*/
|
||||
type PluginKeyConstituents =
|
||||
| {
|
||||
type: 'device';
|
||||
pluginName: string;
|
||||
client: string;
|
||||
}
|
||||
| ({
|
||||
type: 'client';
|
||||
pluginName: string;
|
||||
client: string;
|
||||
} & ClientIdConstituents);
|
||||
|
||||
export function currentActiveApps(
|
||||
clients: Array<Client>,
|
||||
selectedDevice: null | BaseDevice,
|
||||
@@ -56,65 +27,3 @@ export function currentActiveApps(
|
||||
.map((client) => client.appName);
|
||||
return currentActiveApps;
|
||||
}
|
||||
|
||||
export function buildClientId(clientInfo: {
|
||||
app: string;
|
||||
os: string;
|
||||
device: string;
|
||||
device_id: string;
|
||||
}): string {
|
||||
// N.B.: device_id can be empty, which designates the host device
|
||||
for (const key of ['app', 'os', 'device'] as Array<
|
||||
keyof ClientIdConstituents
|
||||
>) {
|
||||
if (!clientInfo[key]) {
|
||||
console.error(
|
||||
`Attempted to build clientId with invalid ${key}: "${clientInfo[key]}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
const escapedName = escape(clientInfo.app);
|
||||
return `${escapedName}#${clientInfo.os}#${clientInfo.device}#${clientInfo.device_id}`;
|
||||
}
|
||||
|
||||
export function deconstructClientId(clientId: string): ClientIdConstituents {
|
||||
if (!clientId || clientId.split('#').length !== 4) {
|
||||
console.error(`Attempted to deconstruct invalid clientId: "${clientId}"`);
|
||||
}
|
||||
let [app, os, device, device_id] = clientId.split('#');
|
||||
app = unescape(app);
|
||||
return {
|
||||
app,
|
||||
os,
|
||||
device,
|
||||
device_id,
|
||||
};
|
||||
}
|
||||
|
||||
export function deconstructPluginKey(pluginKey: string): PluginKeyConstituents {
|
||||
const parts = pluginKey.split('#');
|
||||
if (parts.length === 2) {
|
||||
// Device plugin
|
||||
return {
|
||||
type: 'device',
|
||||
client: parts[0],
|
||||
pluginName: parts[1],
|
||||
};
|
||||
} else {
|
||||
// Client plugin
|
||||
const lastHashIndex = pluginKey.lastIndexOf('#');
|
||||
const clientId = pluginKey.slice(0, lastHashIndex);
|
||||
const pluginName = pluginKey.slice(lastHashIndex + 1);
|
||||
if (!pluginName) {
|
||||
console.error(
|
||||
`Attempted to deconstruct invalid pluginKey: "${pluginKey}"`,
|
||||
);
|
||||
}
|
||||
return {
|
||||
type: 'client',
|
||||
...deconstructClientId(clientId),
|
||||
client: clientId,
|
||||
pluginName: pluginName,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ import {
|
||||
resetSupportFormV2State,
|
||||
SupportFormRequestDetailsState,
|
||||
} from '../reducers/supportForm';
|
||||
import {deconstructClientId} from '../utils/clientUtils';
|
||||
import {deconstructClientId} from 'flipper-common';
|
||||
import {performance} from 'perf_hooks';
|
||||
import {processMessageQueue} from './messageQueue';
|
||||
import {getPluginTitle} from './pluginUtils';
|
||||
|
||||
@@ -16,7 +16,7 @@ import type BaseDevice from '../devices/BaseDevice';
|
||||
import {clipboard, shell} from 'electron';
|
||||
import constants from '../fb-stubs/constants';
|
||||
import {addNotification} from '../reducers/notifications';
|
||||
import {deconstructPluginKey} from './clientUtils';
|
||||
import {deconstructPluginKey} from 'flipper-common';
|
||||
import {DetailSidebarImpl} from '../sandy-chrome/DetailSidebarImpl';
|
||||
|
||||
export function initializeFlipperLibImplementation(
|
||||
|
||||
@@ -12,9 +12,8 @@ import isProduction from './isProduction';
|
||||
import fs from 'fs-extra';
|
||||
import {getStaticPath} from './pathUtils';
|
||||
import type {State, Store} from '../reducers/index';
|
||||
import {deconstructClientId} from './clientUtils';
|
||||
import {sideEffect} from './sideEffect';
|
||||
import {Logger, isTest} from 'flipper-common';
|
||||
import {Logger, isTest, deconstructClientId} from 'flipper-common';
|
||||
|
||||
type PlatformInfo = {
|
||||
arch: string;
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
} from '../reducers/pluginMessageQueue';
|
||||
import {IdlerImpl} from './Idler';
|
||||
import {isPluginEnabled, getSelectedPluginKey} from '../reducers/connections';
|
||||
import {deconstructPluginKey} from './clientUtils';
|
||||
import {deconstructPluginKey} from 'flipper-common';
|
||||
import {defaultEnabledBackgroundPlugins} from './pluginUtils';
|
||||
import {batch, Idler, _SandyPluginInstance} from 'flipper-plugin';
|
||||
import {addBackgroundStat} from './pluginStats';
|
||||
|
||||
14
desktop/flipper-common/src/GK.tsx
Normal file
14
desktop/flipper-common/src/GK.tsx
Normal 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
|
||||
*/
|
||||
|
||||
export const GK = {
|
||||
get(_name: string): boolean {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
100
desktop/flipper-common/src/clientUtils.tsx
Normal file
100
desktop/flipper-common/src/clientUtils.tsx
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* 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 Client uniuely identifies an app running on some device.
|
||||
|
||||
Always use this utility to construct and parse clientId strings.
|
||||
*/
|
||||
export type ClientIdConstituents = {
|
||||
app: string;
|
||||
os: string;
|
||||
device: string;
|
||||
device_id: string;
|
||||
};
|
||||
|
||||
/* A plugin key is a string uniquely identifying an instance of a plugin.
|
||||
This can be a device plugin for a particular device, or a client plugin for a particular client (app).
|
||||
In the device plugin case, the "client" is the device it's connected to.
|
||||
In the client plugin case (normal plugins), the "client" is the app it's connected to.
|
||||
|
||||
Always use this utility to construct and parse pluginKey strings.
|
||||
*/
|
||||
type PluginKeyConstituents =
|
||||
| {
|
||||
type: 'device';
|
||||
pluginName: string;
|
||||
client: string;
|
||||
}
|
||||
| ({
|
||||
type: 'client';
|
||||
pluginName: string;
|
||||
client: string;
|
||||
} & ClientIdConstituents);
|
||||
|
||||
export function buildClientId(clientInfo: {
|
||||
app: string;
|
||||
os: string;
|
||||
device: string;
|
||||
device_id: string;
|
||||
}): string {
|
||||
// N.B.: device_id can be empty, which designates the host device
|
||||
for (const key of ['app', 'os', 'device'] as Array<
|
||||
keyof ClientIdConstituents
|
||||
>) {
|
||||
if (!clientInfo[key]) {
|
||||
console.error(
|
||||
`Attempted to build clientId with invalid ${key}: "${clientInfo[key]}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
const escapedName = escape(clientInfo.app);
|
||||
return `${escapedName}#${clientInfo.os}#${clientInfo.device}#${clientInfo.device_id}`;
|
||||
}
|
||||
|
||||
export function deconstructClientId(clientId: string): ClientIdConstituents {
|
||||
if (!clientId || clientId.split('#').length !== 4) {
|
||||
console.error(`Attempted to deconstruct invalid clientId: "${clientId}"`);
|
||||
}
|
||||
let [app, os, device, device_id] = clientId.split('#');
|
||||
app = unescape(app);
|
||||
return {
|
||||
app,
|
||||
os,
|
||||
device,
|
||||
device_id,
|
||||
};
|
||||
}
|
||||
|
||||
export function deconstructPluginKey(pluginKey: string): PluginKeyConstituents {
|
||||
const parts = pluginKey.split('#');
|
||||
if (parts.length === 2) {
|
||||
// Device plugin
|
||||
return {
|
||||
type: 'device',
|
||||
client: parts[0],
|
||||
pluginName: parts[1],
|
||||
};
|
||||
} else {
|
||||
// Client plugin
|
||||
const lastHashIndex = pluginKey.lastIndexOf('#');
|
||||
const clientId = pluginKey.slice(0, lastHashIndex);
|
||||
const pluginName = pluginKey.slice(lastHashIndex + 1);
|
||||
if (!pluginName) {
|
||||
console.error(
|
||||
`Attempted to deconstruct invalid pluginKey: "${pluginKey}"`,
|
||||
);
|
||||
}
|
||||
return {
|
||||
type: 'client',
|
||||
...deconstructClientId(clientId),
|
||||
client: clientId,
|
||||
pluginName: pluginName,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -41,3 +41,5 @@ export {
|
||||
getErrorFromErrorLike,
|
||||
} from './utils/errors';
|
||||
export * from './user-session';
|
||||
export * from './GK';
|
||||
export * from './clientUtils';
|
||||
|
||||
@@ -112,6 +112,14 @@ export type FlipperServerEvents = {
|
||||
};
|
||||
};
|
||||
|
||||
export type IOSDeviceParams = {
|
||||
udid: string;
|
||||
type: DeviceType;
|
||||
name: string;
|
||||
deviceTypeIdentifier?: string;
|
||||
state?: string;
|
||||
};
|
||||
|
||||
export type FlipperServerCommands = {
|
||||
'device-start-logging': (serial: string) => Promise<void>;
|
||||
'device-stop-logging': (serial: string) => Promise<void>;
|
||||
@@ -137,6 +145,10 @@ export type FlipperServerCommands = {
|
||||
clientId: string,
|
||||
payload: any,
|
||||
) => Promise<ClientResponseType>;
|
||||
'android-get-emulators': () => Promise<string[]>;
|
||||
'android-launch-emulator': (name: string, coldboot: boolean) => Promise<void>;
|
||||
'ios-get-simulators': (bootedOnly: boolean) => Promise<IOSDeviceParams[]>;
|
||||
'ios-launch-simulator': (udid: string) => Promise<void>;
|
||||
};
|
||||
|
||||
export interface FlipperServer {
|
||||
@@ -154,3 +166,95 @@ export interface FlipperServer {
|
||||
): ReturnType<FlipperServerCommands[Event]>;
|
||||
close(): void;
|
||||
}
|
||||
|
||||
// From xplat/js/metro/packages/metro/src/lib/reporting.js
|
||||
export type MetroBundleDetails = {
|
||||
entryFile: string;
|
||||
platform?: string;
|
||||
dev: boolean;
|
||||
minify: boolean;
|
||||
bundleType: string;
|
||||
};
|
||||
|
||||
// From xplat/js/metro/packages/metro/src/lib/reporting.js
|
||||
export type MetroGlobalCacheDisabledReason =
|
||||
| 'too_many_errors'
|
||||
| 'too_many_misses';
|
||||
|
||||
/**
|
||||
* A tagged union of all the actions that may happen and we may want to
|
||||
* report to the tool user.
|
||||
*
|
||||
* Based on xplat/js/metro/packages/metro/src/lib/TerminalReporter.js
|
||||
*/
|
||||
export type MetroReportableEvent =
|
||||
| {
|
||||
port: number;
|
||||
projectRoots: ReadonlyArray<string>;
|
||||
type: 'initialize_started';
|
||||
}
|
||||
| {type: 'initialize_done'}
|
||||
| {
|
||||
type: 'initialize_failed';
|
||||
port: number;
|
||||
error: Error;
|
||||
}
|
||||
| {
|
||||
buildID: string;
|
||||
type: 'bundle_build_done';
|
||||
}
|
||||
| {
|
||||
buildID: string;
|
||||
type: 'bundle_build_failed';
|
||||
}
|
||||
| {
|
||||
buildID: string;
|
||||
bundleDetails: MetroBundleDetails;
|
||||
type: 'bundle_build_started';
|
||||
}
|
||||
| {
|
||||
error: Error;
|
||||
type: 'bundling_error';
|
||||
}
|
||||
| {type: 'dep_graph_loading'}
|
||||
| {type: 'dep_graph_loaded'}
|
||||
| {
|
||||
buildID: string;
|
||||
type: 'bundle_transform_progressed';
|
||||
transformedFileCount: number;
|
||||
totalFileCount: number;
|
||||
}
|
||||
| {
|
||||
type: 'global_cache_error';
|
||||
error: Error;
|
||||
}
|
||||
| {
|
||||
type: 'global_cache_disabled';
|
||||
reason: MetroGlobalCacheDisabledReason;
|
||||
}
|
||||
| {type: 'transform_cache_reset'}
|
||||
| {
|
||||
type: 'worker_stdout_chunk';
|
||||
chunk: string;
|
||||
}
|
||||
| {
|
||||
type: 'worker_stderr_chunk';
|
||||
chunk: string;
|
||||
}
|
||||
| {
|
||||
type: 'hmr_client_error';
|
||||
error: Error;
|
||||
}
|
||||
| {
|
||||
type: 'client_log';
|
||||
level:
|
||||
| 'trace'
|
||||
| 'info'
|
||||
| 'warn'
|
||||
| 'log'
|
||||
| 'group'
|
||||
| 'groupCollapsed'
|
||||
| 'groupEnd'
|
||||
| 'debug';
|
||||
data: Array<any>;
|
||||
};
|
||||
|
||||
@@ -9,7 +9,29 @@
|
||||
"types": "lib/index.d.ts",
|
||||
"license": "MIT",
|
||||
"bugs": "https://github.com/facebook/flipper/issues",
|
||||
"dependencies": {},
|
||||
"dependencies": {
|
||||
"JSONStream": "^1.3.1",
|
||||
"adbkit": "^2.11.1",
|
||||
"adbkit-logcat": "^2.0.1",
|
||||
"archiver": "^5.3.0",
|
||||
"async-mutex": "^0.3.2",
|
||||
"flipper-common": "0.0.0",
|
||||
"fs-extra": "^10.0.0",
|
||||
"invariant": "^2.2.4",
|
||||
"js-base64": "^3.7.2",
|
||||
"lodash.memoize": "^4.1.2",
|
||||
"openssl-wrapper": "^0.3.4",
|
||||
"promisify-child-process": "^4.1.1",
|
||||
"rsocket-core": "^0.0.27",
|
||||
"rsocket-flowable": "^0.0.27",
|
||||
"rsocket-tcp-server": "^0.0.25",
|
||||
"rsocket-types": "^0.0.25",
|
||||
"split2": "^3.2.2",
|
||||
"tmp": "^0.2.1",
|
||||
"uuid": "^8.3.2",
|
||||
"which": "^2.0.2",
|
||||
"ws": "^8.2.3"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"peerDependencies": {},
|
||||
"scripts": {
|
||||
|
||||
93
desktop/flipper-server-core/src/FlipperServerConfig.tsx
Normal file
93
desktop/flipper-server-core/src/FlipperServerConfig.tsx
Normal file
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* 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 {isTest} from 'flipper-common';
|
||||
import {parseFlipperPorts} from './utils/environmentVariables';
|
||||
|
||||
export interface FlipperServerConfig {
|
||||
enableAndroid: boolean;
|
||||
androidHome: string;
|
||||
enableIOS: boolean;
|
||||
idbPath: string;
|
||||
enablePhysicalIOS: boolean;
|
||||
validWebSocketOrigins: string[];
|
||||
staticPath: string;
|
||||
tmpPath: string;
|
||||
}
|
||||
|
||||
// defaultConfig should be used for testing only, and disables by default all features
|
||||
const testConfig: FlipperServerConfig = {
|
||||
androidHome: '',
|
||||
enableAndroid: false,
|
||||
enableIOS: false,
|
||||
enablePhysicalIOS: false,
|
||||
idbPath: '',
|
||||
validWebSocketOrigins: [],
|
||||
staticPath: '/static/',
|
||||
tmpPath: '/temp/',
|
||||
};
|
||||
|
||||
let currentConfig: FlipperServerConfig | undefined = undefined;
|
||||
|
||||
export function getFlipperServerConfig(): FlipperServerConfig {
|
||||
if (!currentConfig) {
|
||||
if (isTest()) return testConfig;
|
||||
throw new Error('FlipperServerConfig has not been set');
|
||||
}
|
||||
return currentConfig;
|
||||
}
|
||||
|
||||
export function setFlipperServerConfig(config: FlipperServerConfig) {
|
||||
currentConfig = config;
|
||||
}
|
||||
|
||||
type ServerPorts = {
|
||||
insecure: number;
|
||||
secure: number;
|
||||
};
|
||||
|
||||
export function getServerPortsConfig(): {
|
||||
serverPorts: ServerPorts;
|
||||
altServerPorts: ServerPorts;
|
||||
} {
|
||||
let portOverrides: ServerPorts | undefined;
|
||||
if (process.env.FLIPPER_PORTS) {
|
||||
portOverrides = parseFlipperPorts(process.env.FLIPPER_PORTS);
|
||||
if (!portOverrides) {
|
||||
console.error(
|
||||
`Ignoring malformed FLIPPER_PORTS env variable:
|
||||
"${process.env.FLIPPER_PORTS || ''}".
|
||||
Example expected format: "1111,2222".`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let portAltOverrides: ServerPorts | undefined;
|
||||
if (process.env.FLIPPER_ALT_PORTS) {
|
||||
portAltOverrides = parseFlipperPorts(process.env.FLIPPER_ALT_PORTS);
|
||||
if (!portAltOverrides) {
|
||||
console.error(
|
||||
`Ignoring malformed FLIPPER_ALT_PORTS env variable:
|
||||
"${process.env.FLIPPER_ALT_PORTS || ''}".
|
||||
Example expected format: "1111,2222".`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
serverPorts: portOverrides ?? {
|
||||
insecure: 8089,
|
||||
secure: 8088,
|
||||
},
|
||||
altServerPorts: portAltOverrides ?? {
|
||||
insecure: 9089,
|
||||
secure: 9088,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -11,9 +11,11 @@ import EventEmitter from 'events';
|
||||
import {Logger} from 'flipper-common';
|
||||
import ServerController from './comms/ServerController';
|
||||
import {CertificateExchangeMedium} from './utils/CertificateProvider';
|
||||
import {ServerPorts} from '../reducers/application';
|
||||
import {AndroidDeviceManager} from './devices/android/androidDeviceManager';
|
||||
import {IOSDeviceManager} from './devices/ios/iOSDeviceManager';
|
||||
import {
|
||||
IOSDeviceManager,
|
||||
launchSimulator,
|
||||
} from './devices/ios/iOSDeviceManager';
|
||||
import metroDevice from './devices/metro/metroDeviceManager';
|
||||
import desktopDevice from './devices/desktop/desktopDeviceManager';
|
||||
import {
|
||||
@@ -26,33 +28,8 @@ import {
|
||||
import {ServerDevice} from './devices/ServerDevice';
|
||||
import {Base64} from 'js-base64';
|
||||
import MetroDevice from './devices/metro/MetroDevice';
|
||||
|
||||
export interface FlipperServerConfig {
|
||||
enableAndroid: boolean;
|
||||
androidHome: string;
|
||||
enableIOS: boolean;
|
||||
idbPath: string;
|
||||
enablePhysicalIOS: boolean;
|
||||
serverPorts: ServerPorts;
|
||||
altServerPorts: ServerPorts;
|
||||
}
|
||||
|
||||
// defaultConfig should be used for testing only, and disables by default all features
|
||||
const defaultConfig: FlipperServerConfig = {
|
||||
androidHome: '',
|
||||
enableAndroid: false,
|
||||
enableIOS: false,
|
||||
enablePhysicalIOS: false,
|
||||
idbPath: '',
|
||||
serverPorts: {
|
||||
insecure: -1,
|
||||
secure: -1,
|
||||
},
|
||||
altServerPorts: {
|
||||
insecure: -1,
|
||||
secure: -1,
|
||||
},
|
||||
};
|
||||
import {launchEmulator} from './devices/android/AndroidDevice';
|
||||
import {getFlipperServerConfig} from './FlipperServerConfig';
|
||||
|
||||
/**
|
||||
* FlipperServer takes care of all incoming device & client connections.
|
||||
@@ -63,8 +40,6 @@ const defaultConfig: FlipperServerConfig = {
|
||||
* using '.on'. All events are strongly typed.
|
||||
*/
|
||||
export class FlipperServerImpl implements FlipperServer {
|
||||
public config: FlipperServerConfig;
|
||||
|
||||
private readonly events = new EventEmitter();
|
||||
// server handles the incoming RSocket / WebSocket connections from Flipper clients
|
||||
readonly server: ServerController;
|
||||
@@ -74,8 +49,8 @@ export class FlipperServerImpl implements FlipperServer {
|
||||
android: AndroidDeviceManager;
|
||||
ios: IOSDeviceManager;
|
||||
|
||||
constructor(config: Partial<FlipperServerConfig>, public logger: Logger) {
|
||||
this.config = {...defaultConfig, ...config};
|
||||
constructor(public logger: Logger) {
|
||||
getFlipperServerConfig(); // Config should be available at this point!
|
||||
const server = (this.server = new ServerController(this));
|
||||
this.android = new AndroidDeviceManager(this);
|
||||
this.ios = new IOSDeviceManager(this);
|
||||
@@ -239,6 +214,12 @@ export class FlipperServerImpl implements FlipperServer {
|
||||
},
|
||||
};
|
||||
},
|
||||
'android-get-emulators': async () => this.android.getAndroidEmulators(),
|
||||
'android-launch-emulator': async (name, coldBoot) =>
|
||||
launchEmulator(name, coldBoot),
|
||||
'ios-get-simulators': async (bootedOnly) =>
|
||||
this.ios.getSimulators(bootedOnly),
|
||||
'ios-launch-simulator': async (udid) => launchSimulator(udid),
|
||||
};
|
||||
|
||||
registerDevice(device: ServerDevice) {
|
||||
@@ -9,16 +9,20 @@
|
||||
|
||||
import {CertificateExchangeMedium} from '../utils/CertificateProvider';
|
||||
import {Logger} from 'flipper-common';
|
||||
import {ClientDescription, ClientQuery, isTest} from 'flipper-common';
|
||||
import {
|
||||
ClientDescription,
|
||||
ClientQuery,
|
||||
isTest,
|
||||
GK,
|
||||
buildClientId,
|
||||
} from 'flipper-common';
|
||||
import CertificateProvider from '../utils/CertificateProvider';
|
||||
import {ClientConnection, ConnectionStatus} from './ClientConnection';
|
||||
import {UninitializedClient} from 'flipper-common';
|
||||
import {reportPlatformFailures} from 'flipper-common';
|
||||
import {EventEmitter} from 'events';
|
||||
import invariant from 'invariant';
|
||||
import GK from '../../fb-stubs/GK';
|
||||
import {buildClientId} from '../../utils/clientUtils';
|
||||
import DummyDevice from '../../server/devices/DummyDevice';
|
||||
import DummyDevice from '../devices/DummyDevice';
|
||||
import {
|
||||
appNameWithUpdateHint,
|
||||
transformCertificateExchangeMediumToType,
|
||||
@@ -33,6 +37,10 @@ import {
|
||||
TransportType,
|
||||
} from './ServerFactory';
|
||||
import {FlipperServerImpl} from '../FlipperServerImpl';
|
||||
import {
|
||||
getServerPortsConfig,
|
||||
getFlipperServerConfig,
|
||||
} from '../FlipperServerConfig';
|
||||
|
||||
type ClientInfo = {
|
||||
connection: ClientConnection | null | undefined;
|
||||
@@ -80,7 +88,7 @@ class ServerController extends EventEmitter implements ServerEventsListener {
|
||||
this.certificateProvider = new CertificateProvider(
|
||||
this,
|
||||
this.logger,
|
||||
this.flipperServer.config,
|
||||
getFlipperServerConfig(),
|
||||
);
|
||||
this.connectionTracker = new ConnectionTracker(this.logger);
|
||||
this.secureServer = null;
|
||||
@@ -111,7 +119,7 @@ class ServerController extends EventEmitter implements ServerEventsListener {
|
||||
if (isTest()) {
|
||||
throw new Error('Spawing new server is not supported in test');
|
||||
}
|
||||
const {insecure, secure} = this.flipperServer.config.serverPorts;
|
||||
const {insecure, secure} = getServerPortsConfig().serverPorts;
|
||||
|
||||
this.initialized = this.certificateProvider
|
||||
.loadSecureServerConfig()
|
||||
@@ -119,7 +127,7 @@ class ServerController extends EventEmitter implements ServerEventsListener {
|
||||
console.info('[conn] secure server listening at port: ', secure);
|
||||
this.secureServer = createServer(secure, this, options);
|
||||
if (GK.get('flipper_websocket_server')) {
|
||||
const {secure: altSecure} = this.flipperServer.config.altServerPorts;
|
||||
const {secure: altSecure} = getServerPortsConfig().altServerPorts;
|
||||
console.info(
|
||||
'[conn] secure server (ws) listening at port: ',
|
||||
altSecure,
|
||||
@@ -136,8 +144,7 @@ class ServerController extends EventEmitter implements ServerEventsListener {
|
||||
console.info('[conn] insecure server listening at port: ', insecure);
|
||||
this.insecureServer = createServer(insecure, this);
|
||||
if (GK.get('flipper_websocket_server')) {
|
||||
const {insecure: altInsecure} =
|
||||
this.flipperServer.config.altServerPorts;
|
||||
const {insecure: altInsecure} = getServerPortsConfig().altServerPorts;
|
||||
console.info(
|
||||
'[conn] insecure server (ws) listening at port: ',
|
||||
altInsecure,
|
||||
@@ -214,13 +221,13 @@ class ServerController extends EventEmitter implements ServerEventsListener {
|
||||
|
||||
const {os, app, device_id} = clientQuery;
|
||||
// without these checks, the user might see a connection timeout error instead, which would be much harder to track down
|
||||
if (os === 'iOS' && !this.flipperServer.config.enableIOS) {
|
||||
if (os === 'iOS' && !getFlipperServerConfig().enableIOS) {
|
||||
console.error(
|
||||
`Refusing connection from ${app} on ${device_id}, since iOS support is disabled in settings`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (os === 'Android' && !this.flipperServer.config.enableAndroid) {
|
||||
if (os === 'Android' && !getFlipperServerConfig().enableAndroid) {
|
||||
console.error(
|
||||
`Refusing connection from ${app} on ${device_id}, since Android support is disabled in settings`,
|
||||
);
|
||||
@@ -12,10 +12,10 @@ import WebSocket from 'ws';
|
||||
import querystring from 'querystring';
|
||||
import {BrowserClientFlipperConnection} from './BrowserClientFlipperConnection';
|
||||
import {ServerEventsListener} from './ServerAdapter';
|
||||
import constants from '../../fb-stubs/constants';
|
||||
import ws from 'ws';
|
||||
import {IncomingMessage} from 'http';
|
||||
import {ClientDescription, ClientQuery} from 'flipper-common';
|
||||
import {getFlipperServerConfig} from '../FlipperServerConfig';
|
||||
|
||||
/**
|
||||
* WebSocket-based server which uses a connect/disconnect handshake over an insecure channel.
|
||||
@@ -27,7 +27,7 @@ class ServerWebSocketBrowser extends ServerWebSocketBase {
|
||||
|
||||
verifyClient(): ws.VerifyClientCallbackSync {
|
||||
return (info: {origin: string; req: IncomingMessage; secure: boolean}) => {
|
||||
const ok = constants.VALID_WEB_SOCKET_REQUEST_ORIGIN_PREFIXES.some(
|
||||
const ok = getFlipperServerConfig().validWebSocketOrigins.some(
|
||||
(validPrefix) => info.origin.startsWith(validPrefix),
|
||||
);
|
||||
if (!ok) {
|
||||
@@ -17,6 +17,10 @@ import {Client as ADBClient, Device} from 'adbkit';
|
||||
import {join} from 'path';
|
||||
import {FlipperServerImpl} from '../../FlipperServerImpl';
|
||||
import {notNull} from '../../utils/typeUtils';
|
||||
import {
|
||||
getServerPortsConfig,
|
||||
getFlipperServerConfig,
|
||||
} from '../../FlipperServerConfig';
|
||||
|
||||
export class AndroidDeviceManager {
|
||||
// cache emulator path
|
||||
@@ -58,12 +62,10 @@ export class AndroidDeviceManager {
|
||||
abiList,
|
||||
sdkVersion,
|
||||
);
|
||||
if (this.flipperServer.config.serverPorts) {
|
||||
const ports = getServerPortsConfig();
|
||||
if (ports.serverPorts) {
|
||||
await androidLikeDevice
|
||||
.reverse([
|
||||
this.flipperServer.config.serverPorts.secure,
|
||||
this.flipperServer.config.serverPorts.insecure,
|
||||
])
|
||||
.reverse([ports.serverPorts.secure, ports.serverPorts.insecure])
|
||||
// We may not be able to establish a reverse connection, e.g. for old Android SDKs.
|
||||
// This is *generally* fine, because we hard-code the ports on the SDK side.
|
||||
.catch((e) => {
|
||||
@@ -177,7 +179,7 @@ export class AndroidDeviceManager {
|
||||
|
||||
async watchAndroidDevices() {
|
||||
try {
|
||||
const client = await getAdbClient(this.flipperServer.config);
|
||||
const client = await getAdbClient(getFlipperServerConfig());
|
||||
client
|
||||
.trackDevices()
|
||||
.then((tracker) => {
|
||||
@@ -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 {getFlipperServerConfig} from '../../FlipperServerConfig';
|
||||
|
||||
export const ERR_NO_IDB_OR_XCODE_AVAILABLE =
|
||||
'Neither Xcode nor idb available. Cannot provide iOS device functionality.';
|
||||
@@ -98,8 +98,7 @@ export function xcrunStartLogListener(udid: string, deviceType: DeviceType) {
|
||||
|
||||
function makeTempScreenshotFilePath() {
|
||||
const imageName = uuid() + '.png';
|
||||
const directory = getAppTempPath();
|
||||
return path.join(directory, imageName);
|
||||
return path.join(getFlipperServerConfig().tmpPath, imageName);
|
||||
}
|
||||
|
||||
async function runScreenshotCommand(
|
||||
@@ -10,20 +10,16 @@
|
||||
import {makeIOSBridge} from '../IOSBridge';
|
||||
import childProcess from 'child_process';
|
||||
import * as promisifyChildProcess from 'promisify-child-process';
|
||||
import {mocked} from 'ts-jest/utils';
|
||||
|
||||
jest.mock('child_process');
|
||||
const spawn = mocked(childProcess.spawn);
|
||||
|
||||
jest.mock('promisify-child-process');
|
||||
const exec = mocked(promisifyChildProcess.exec);
|
||||
|
||||
test('uses xcrun with no idb when xcode is detected', async () => {
|
||||
const ib = await makeIOSBridge('', true);
|
||||
|
||||
ib.startLogListener('deadbeef', 'emulator');
|
||||
|
||||
expect(spawn).toHaveBeenCalledWith(
|
||||
expect(childProcess.spawn).toHaveBeenCalledWith(
|
||||
'xcrun',
|
||||
[
|
||||
'simctl',
|
||||
@@ -47,7 +43,7 @@ test('uses idb when present and xcode detected', async () => {
|
||||
|
||||
ib.startLogListener('deadbeef', 'emulator');
|
||||
|
||||
expect(spawn).toHaveBeenCalledWith(
|
||||
expect(childProcess.spawn).toHaveBeenCalledWith(
|
||||
'/usr/local/bin/idb',
|
||||
[
|
||||
'log',
|
||||
@@ -70,7 +66,7 @@ test('uses idb when present and xcode detected and physical device connected', a
|
||||
|
||||
ib.startLogListener('deadbeef', 'physical');
|
||||
|
||||
expect(spawn).toHaveBeenCalledWith(
|
||||
expect(childProcess.spawn).toHaveBeenCalledWith(
|
||||
'/usr/local/bin/idb',
|
||||
[
|
||||
'log',
|
||||
@@ -101,7 +97,7 @@ test.unix(
|
||||
|
||||
ib.screenshot('deadbeef');
|
||||
|
||||
expect(exec).toHaveBeenCalledWith(
|
||||
expect(promisifyChildProcess.exec).toHaveBeenCalledWith(
|
||||
'xcrun simctl io deadbeef screenshot /temp/00000000-0000-0000-0000-000000000000.png',
|
||||
);
|
||||
},
|
||||
@@ -112,7 +108,7 @@ test.unix('uses idb to take screenshots when available', async () => {
|
||||
|
||||
ib.screenshot('deadbeef');
|
||||
|
||||
expect(exec).toHaveBeenCalledWith(
|
||||
expect(promisifyChildProcess.exec).toHaveBeenCalledWith(
|
||||
'idb screenshot --udid deadbeef /temp/00000000-0000-0000-0000-000000000000.png',
|
||||
);
|
||||
});
|
||||
@@ -122,7 +118,7 @@ test('uses xcrun to navigate with no idb when xcode is detected', async () => {
|
||||
|
||||
ib.navigate('deadbeef', 'fb://dummy');
|
||||
|
||||
expect(exec).toHaveBeenCalledWith(
|
||||
expect(promisifyChildProcess.exec).toHaveBeenCalledWith(
|
||||
'xcrun simctl io deadbeef launch url "fb://dummy"',
|
||||
);
|
||||
});
|
||||
@@ -132,7 +128,9 @@ test('uses idb to navigate when available', async () => {
|
||||
|
||||
ib.navigate('deadbeef', 'fb://dummy');
|
||||
|
||||
expect(exec).toHaveBeenCalledWith('idb open --udid deadbeef "fb://dummy"');
|
||||
expect(promisifyChildProcess.exec).toHaveBeenCalledWith(
|
||||
'idb open --udid deadbeef "fb://dummy"',
|
||||
);
|
||||
});
|
||||
|
||||
test('uses xcrun to record with no idb when xcode is detected', async () => {
|
||||
@@ -140,7 +138,7 @@ test('uses xcrun to record with no idb when xcode is detected', async () => {
|
||||
|
||||
ib.recordVideo('deadbeef', '/tmp/video.mp4');
|
||||
|
||||
expect(exec).toHaveBeenCalledWith(
|
||||
expect(promisifyChildProcess.exec).toHaveBeenCalledWith(
|
||||
'xcrun simctl io deadbeef recordVideo --codec=h264 --force /tmp/video.mp4',
|
||||
);
|
||||
});
|
||||
@@ -150,7 +148,7 @@ test('uses idb to record when available', async () => {
|
||||
|
||||
ib.recordVideo('deadbeef', '/tmo/video.mp4');
|
||||
|
||||
expect(exec).toHaveBeenCalledWith(
|
||||
expect(promisifyChildProcess.exec).toHaveBeenCalledWith(
|
||||
'idb record-video --udid deadbeef /tmo/video.mp4',
|
||||
);
|
||||
});
|
||||
@@ -8,16 +8,10 @@
|
||||
*/
|
||||
|
||||
import {parseXcodeFromCoreSimPath} from '../iOSDeviceManager';
|
||||
import configureStore from 'redux-mock-store';
|
||||
import {State, createRootReducer} from '../../../../reducers/index';
|
||||
import {getLogger} from 'flipper-common';
|
||||
import {IOSBridge} from '../IOSBridge';
|
||||
import {FlipperServerImpl} from '../../../FlipperServerImpl';
|
||||
|
||||
const mockStore = configureStore<State, {}>([])(
|
||||
createRootReducer()(undefined, {type: 'INIT'}),
|
||||
);
|
||||
|
||||
const standardCoresimulatorLog =
|
||||
'username 1264 0.0 0.1 5989740 41648 ?? Ss 2:23PM 0:12.92 /Applications/Xcode_12.4.0_fb.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/libexec/mobileassetd';
|
||||
|
||||
@@ -59,7 +53,7 @@ test('test parseXcodeFromCoreSimPath from standard locations', () => {
|
||||
});
|
||||
|
||||
test('test getAllPromisesForQueryingDevices when xcode detected', () => {
|
||||
const flipperServer = new FlipperServerImpl({}, getLogger());
|
||||
const flipperServer = new FlipperServerImpl(getLogger());
|
||||
flipperServer.ios.iosBridge = {} as IOSBridge;
|
||||
const promises = flipperServer.ios.getAllPromisesForQueryingDevices(
|
||||
true,
|
||||
@@ -69,7 +63,7 @@ test('test getAllPromisesForQueryingDevices when xcode detected', () => {
|
||||
});
|
||||
|
||||
test('test getAllPromisesForQueryingDevices when xcode is not detected', () => {
|
||||
const flipperServer = new FlipperServerImpl({}, getLogger());
|
||||
const flipperServer = new FlipperServerImpl(getLogger());
|
||||
flipperServer.ios.iosBridge = {} as IOSBridge;
|
||||
const promises = flipperServer.ios.getAllPromisesForQueryingDevices(
|
||||
false,
|
||||
@@ -79,7 +73,7 @@ test('test getAllPromisesForQueryingDevices when xcode is not detected', () => {
|
||||
});
|
||||
|
||||
test('test getAllPromisesForQueryingDevices when xcode and idb are both unavailable', () => {
|
||||
const flipperServer = new FlipperServerImpl({}, getLogger());
|
||||
const flipperServer = new FlipperServerImpl(getLogger());
|
||||
flipperServer.ios.iosBridge = {} as IOSBridge;
|
||||
const promises = flipperServer.ios.getAllPromisesForQueryingDevices(
|
||||
false,
|
||||
@@ -89,7 +83,7 @@ test('test getAllPromisesForQueryingDevices when xcode and idb are both unavaila
|
||||
});
|
||||
|
||||
test('test getAllPromisesForQueryingDevices when both idb and xcode are available', () => {
|
||||
const flipperServer = new FlipperServerImpl({}, getLogger());
|
||||
const flipperServer = new FlipperServerImpl(getLogger());
|
||||
flipperServer.ios.iosBridge = {} as IOSBridge;
|
||||
const promises = flipperServer.ios.getAllPromisesForQueryingDevices(
|
||||
true,
|
||||
@@ -7,7 +7,6 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import {Mutex} from 'async-mutex';
|
||||
import {exec as unsafeExec, Output} from 'promisify-child-process';
|
||||
import {reportPlatformFailures} from 'flipper-common';
|
||||
@@ -18,8 +17,6 @@ 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 {notification, Typography} from 'antd';
|
||||
const exec = promisify(child_process.exec);
|
||||
|
||||
// Use debug to get helpful logs when idb fails
|
||||
@@ -251,14 +248,9 @@ function handleMissingIdb(e: Error, idbPath: string): void {
|
||||
e.message.includes('sudo: no tty present and no askpass program specified')
|
||||
) {
|
||||
console.warn(e);
|
||||
const message = `idb doesn't appear to be installed. Run "${idbPath} list-targets" to fix this.`;
|
||||
notification.error({
|
||||
message: 'Cannot connect to idb',
|
||||
duration: null,
|
||||
description: message,
|
||||
key: 'idb_connection_failed',
|
||||
});
|
||||
return;
|
||||
throw new Error(
|
||||
`idb doesn't appear to be installed. Run "${idbPath} list-targets" to fix this.`,
|
||||
);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
@@ -271,24 +263,11 @@ function handleMissingPermissions(e: Error): void {
|
||||
e.message.includes('sonar/app.csr')
|
||||
) {
|
||||
console.warn(e);
|
||||
const message = fbConfig.isFBBuild ? (
|
||||
<>
|
||||
Idb lacks permissions to exchange certificates. Did you install a source
|
||||
build or a debug build with certificate exchange enabled?{' '}
|
||||
<Typography.Link href="https://www.internalfb.com/intern/staticdocs/flipper/docs/getting-started/fb/connecting-to-flipper#app-on-physical-ios-device">
|
||||
How To
|
||||
</Typography.Link>
|
||||
</>
|
||||
) : (
|
||||
'Idb lacks permissions to exchange certificates. Did you install a source build?'
|
||||
throw new Error(
|
||||
'Cannot connect to iOS application. idb_certificate_pull_failed' +
|
||||
'Idb lacks permissions to exchange certificates. Did you install a source build ([FB] or enable certificate exchange)? ' +
|
||||
e,
|
||||
);
|
||||
notification.error({
|
||||
message: 'Cannot connect to iOS application',
|
||||
duration: null,
|
||||
description: message,
|
||||
key: 'idb_certificate_pull_failed',
|
||||
});
|
||||
return;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
@@ -8,13 +8,12 @@
|
||||
*/
|
||||
|
||||
import {ChildProcess} from 'child_process';
|
||||
import type {DeviceType} from 'flipper-common';
|
||||
import type {IOSDeviceParams} from 'flipper-common';
|
||||
import path from 'path';
|
||||
import childProcess from 'child_process';
|
||||
import {exec, execFile} from 'promisify-child-process';
|
||||
import iosUtil from './iOSContainerUtility';
|
||||
import IOSDevice from './IOSDevice';
|
||||
import {getStaticPath} from '../../../utils/pathUtils';
|
||||
import {
|
||||
ERR_NO_IDB_OR_XCODE_AVAILABLE,
|
||||
IOSBridge,
|
||||
@@ -22,6 +21,7 @@ import {
|
||||
} from './IOSBridge';
|
||||
import {FlipperServerImpl} from '../../FlipperServerImpl';
|
||||
import {notNull} from '../../utils/typeUtils';
|
||||
import {getFlipperServerConfig} from '../../FlipperServerConfig';
|
||||
|
||||
type iOSSimulatorDevice = {
|
||||
state: 'Booted' | 'Shutdown' | 'Shutting Down';
|
||||
@@ -31,14 +31,6 @@ type iOSSimulatorDevice = {
|
||||
udid: string;
|
||||
};
|
||||
|
||||
export type IOSDeviceParams = {
|
||||
udid: string;
|
||||
type: DeviceType;
|
||||
name: string;
|
||||
deviceTypeIdentifier?: string;
|
||||
state?: string;
|
||||
};
|
||||
|
||||
function isAvailable(simulator: iOSSimulatorDevice): boolean {
|
||||
// For some users "availability" is set, for others it's "isAvailable"
|
||||
// It's not clear which key is set, so we are checking both.
|
||||
@@ -53,13 +45,12 @@ function isAvailable(simulator: iOSSimulatorDevice): boolean {
|
||||
export class IOSDeviceManager {
|
||||
private portForwarders: Array<ChildProcess> = [];
|
||||
|
||||
private portforwardingClient = getStaticPath(
|
||||
path.join(
|
||||
private portforwardingClient = path.join(
|
||||
getFlipperServerConfig().staticPath,
|
||||
'PortForwardingMacApp.app',
|
||||
'Contents',
|
||||
'MacOS',
|
||||
'PortForwardingMacApp',
|
||||
),
|
||||
);
|
||||
iosBridge: IOSBridge | undefined;
|
||||
private xcodeVersionMismatchFound = false;
|
||||
@@ -114,7 +105,7 @@ export class IOSDeviceManager {
|
||||
isXcodeDetected: boolean,
|
||||
isIdbAvailable: boolean,
|
||||
): Array<Promise<any>> {
|
||||
const {config} = this.flipperServer;
|
||||
const config = getFlipperServerConfig();
|
||||
return [
|
||||
isIdbAvailable
|
||||
? getActiveDevices(config.idbPath, config.enablePhysicalIOS).then(
|
||||
@@ -133,7 +124,7 @@ export class IOSDeviceManager {
|
||||
}
|
||||
|
||||
private async queryDevices(): Promise<any> {
|
||||
const {config} = this.flipperServer;
|
||||
const config = getFlipperServerConfig();
|
||||
const isXcodeInstalled = await iosUtil.isXcodeDetected();
|
||||
const isIdbAvailable = await iosUtil.isAvailable(config.idbPath);
|
||||
return Promise.all(
|
||||
@@ -177,19 +168,19 @@ export class IOSDeviceManager {
|
||||
|
||||
public async watchIOSDevices() {
|
||||
// TODO: pull this condition up
|
||||
if (!this.flipperServer.config.enableIOS) {
|
||||
if (!getFlipperServerConfig().enableIOS) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const isDetected = await iosUtil.isXcodeDetected();
|
||||
this.xcodeCommandLineToolsDetected = isDetected;
|
||||
if (this.flipperServer.config.enablePhysicalIOS) {
|
||||
if (getFlipperServerConfig().enablePhysicalIOS) {
|
||||
this.startDevicePortForwarders();
|
||||
}
|
||||
try {
|
||||
// Awaiting the promise here to trigger immediate error handling.
|
||||
this.iosBridge = await makeIOSBridge(
|
||||
this.flipperServer.config.idbPath,
|
||||
getFlipperServerConfig().idbPath,
|
||||
isDetected,
|
||||
);
|
||||
this.queryDevicesForever();
|
||||
@@ -7,101 +7,11 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import {DeviceLogLevel} from 'flipper-common';
|
||||
import {DeviceLogLevel, MetroReportableEvent} from 'flipper-common';
|
||||
import util from 'util';
|
||||
import {FlipperServerImpl} from '../../FlipperServerImpl';
|
||||
import {ServerDevice} from '../ServerDevice';
|
||||
|
||||
// From xplat/js/metro/packages/metro/src/lib/reporting.js
|
||||
export type BundleDetails = {
|
||||
entryFile: string;
|
||||
platform?: string;
|
||||
dev: boolean;
|
||||
minify: boolean;
|
||||
bundleType: string;
|
||||
};
|
||||
|
||||
// From xplat/js/metro/packages/metro/src/lib/reporting.js
|
||||
export type GlobalCacheDisabledReason = 'too_many_errors' | 'too_many_misses';
|
||||
|
||||
/**
|
||||
* A tagged union of all the actions that may happen and we may want to
|
||||
* report to the tool user.
|
||||
*
|
||||
* Based on xplat/js/metro/packages/metro/src/lib/TerminalReporter.js
|
||||
*/
|
||||
export type MetroReportableEvent =
|
||||
| {
|
||||
port: number;
|
||||
projectRoots: ReadonlyArray<string>;
|
||||
type: 'initialize_started';
|
||||
}
|
||||
| {type: 'initialize_done'}
|
||||
| {
|
||||
type: 'initialize_failed';
|
||||
port: number;
|
||||
error: Error;
|
||||
}
|
||||
| {
|
||||
buildID: string;
|
||||
type: 'bundle_build_done';
|
||||
}
|
||||
| {
|
||||
buildID: string;
|
||||
type: 'bundle_build_failed';
|
||||
}
|
||||
| {
|
||||
buildID: string;
|
||||
bundleDetails: BundleDetails;
|
||||
type: 'bundle_build_started';
|
||||
}
|
||||
| {
|
||||
error: Error;
|
||||
type: 'bundling_error';
|
||||
}
|
||||
| {type: 'dep_graph_loading'}
|
||||
| {type: 'dep_graph_loaded'}
|
||||
| {
|
||||
buildID: string;
|
||||
type: 'bundle_transform_progressed';
|
||||
transformedFileCount: number;
|
||||
totalFileCount: number;
|
||||
}
|
||||
| {
|
||||
type: 'global_cache_error';
|
||||
error: Error;
|
||||
}
|
||||
| {
|
||||
type: 'global_cache_disabled';
|
||||
reason: GlobalCacheDisabledReason;
|
||||
}
|
||||
| {type: 'transform_cache_reset'}
|
||||
| {
|
||||
type: 'worker_stdout_chunk';
|
||||
chunk: string;
|
||||
}
|
||||
| {
|
||||
type: 'worker_stderr_chunk';
|
||||
chunk: string;
|
||||
}
|
||||
| {
|
||||
type: 'hmr_client_error';
|
||||
error: Error;
|
||||
}
|
||||
| {
|
||||
type: 'client_log';
|
||||
level:
|
||||
| 'trace'
|
||||
| 'info'
|
||||
| 'warn'
|
||||
| 'log'
|
||||
| 'group'
|
||||
| 'groupCollapsed'
|
||||
| 'groupEnd'
|
||||
| 'debug';
|
||||
data: Array<any>;
|
||||
};
|
||||
|
||||
const metroLogLevelMapping: {[key: string]: DeviceLogLevel} = {
|
||||
trace: 'verbose',
|
||||
info: 'info',
|
||||
@@ -7,6 +7,10 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
export function helloWorld() {
|
||||
return true;
|
||||
}
|
||||
export {
|
||||
FlipperServerConfig,
|
||||
getFlipperServerConfig,
|
||||
setFlipperServerConfig,
|
||||
} from './FlipperServerConfig';
|
||||
|
||||
export {FlipperServerImpl} from './FlipperServerImpl';
|
||||
|
||||
@@ -3865,7 +3865,7 @@ archiver-utils@^2.1.0:
|
||||
normalize-path "^3.0.0"
|
||||
readable-stream "^2.0.0"
|
||||
|
||||
archiver@^5.0.2:
|
||||
archiver@^5.0.2, archiver@^5.3.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/archiver/-/archiver-5.3.0.tgz#dd3e097624481741df626267564f7dd8640a45ba"
|
||||
integrity sha512-iUw+oDwK0fgNpvveEsdQ0Ase6IIKztBJU2U0E9MzszMfmVVUyv1QJhS2ITW9ZCqx8dktAxVAjWWkKehuZE8OPg==
|
||||
@@ -5829,9 +5829,9 @@ electron-publish@22.11.1:
|
||||
mime "^2.5.0"
|
||||
|
||||
electron-to-chromium@^1.3.857:
|
||||
version "1.3.862"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.862.tgz#c1c5d4382449e2c9b0e67fe1652f4fc451d6d8c0"
|
||||
integrity sha512-o+FMbCD+hAUJ9S8bfz/FaqA0gE8OpCCm58KhhGogOEqiA1BLFSoVYLi+tW+S/ZavnqBn++n0XZm7HQiBVPs8Jg==
|
||||
version "1.3.864"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.864.tgz#6a993bcc196a2b8b3df84d28d5d4dd912393885f"
|
||||
integrity sha512-v4rbad8GO6/yVI92WOeU9Wgxc4NA0n4f6P1FvZTY+jyY7JHEhw3bduYu60v3Q1h81Cg6eo4ApZrFPuycwd5hGw==
|
||||
|
||||
electron@11.2.3:
|
||||
version "11.2.3"
|
||||
@@ -10692,7 +10692,7 @@ promise@^7.1.1:
|
||||
dependencies:
|
||||
asap "~2.0.3"
|
||||
|
||||
promisify-child-process@^4.1.0:
|
||||
promisify-child-process@^4.1.0, promisify-child-process@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/promisify-child-process/-/promisify-child-process-4.1.1.tgz#290659e079f9c7bd46708404d4488a1a6b802686"
|
||||
integrity sha512-/sRjHZwoXf1rJ+8s4oWjYjGRVKNK1DUnqfRC1Zek18pl0cN6k3yJ1cCbqd0tWNe4h0Gr+SY4vR42N33+T82WkA==
|
||||
@@ -13661,7 +13661,7 @@ ws@1.1.5, ws@^1.1.5:
|
||||
options ">=0.0.5"
|
||||
ultron "1.0.x"
|
||||
|
||||
ws@^7.4.5, ws@^7.4.6, ws@^8.2.1, ws@~7.4.2:
|
||||
ws@^7.4.5, ws@^7.4.6, ws@^8.2.1, ws@^8.2.3, ws@~7.4.2:
|
||||
version "7.5.5"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.5.tgz#8b4bc4af518cfabd0473ae4f99144287b33eb881"
|
||||
integrity sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==
|
||||
|
||||
Reference in New Issue
Block a user