Files
flipper/src/dispatcher/iOSDevice.js
Pritesh Nandgaonkar 9d4bb45dbc Refactor CrashReporter plugin
Summary: This diff refactors CrashReporter Plugin. The business logic of crash reporter plugin was placed in the `iOSDevice.js` as it gets the hook to the initialisation of iOSDevice. This diff moves the business logic to the Crash Reporter plugin files under the plugins folder. To get the hook, so that we can add our watcher, I have added a static function over `FlipperBasePlugin`, which if exists, will be called once `REGISTER_PLUGIN` event is dispatched

Reviewed By: danielbuechele

Differential Revision: D13529035

fbshipit-source-id: 28216b273b4032727859107d8a6751c6465af9ac
2018-12-21 07:03:21 -08:00

145 lines
4.4 KiB
JavaScript

/**
* Copyright 2018-present Facebook.
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
* @format
*/
import type {ChildProcess} from 'child_process';
import type {Store} from '../reducers/index.js';
import type Logger from '../fb-stubs/Logger.js';
import type {DeviceType} from '../devices/BaseDevice';
import {RecurringError} from '../utils/errors';
import {promisify} from 'util';
import path from 'path';
import child_process from 'child_process';
const execFile = child_process.execFile;
import IOSDevice from '../devices/IOSDevice';
import iosUtil from '../fb-stubs/iOSContainerUtility';
import isProduction from '../utils/isProduction.js';
import GK from '../fb-stubs/GK';
type iOSSimulatorDevice = {|
state: 'Booted' | 'Shutdown' | 'Shutting Down',
availability?: string,
isAvailable?: 'YES' | 'NO',
name: string,
udid: string,
|};
type IOSDeviceParams = {udid: string, type: DeviceType, name: string};
const portforwardingClient = isProduction()
? path.resolve(
__dirname,
'PortForwardingMacApp.app/Contents/MacOS/PortForwardingMacApp',
)
: 'PortForwardingMacApp.app/Contents/MacOS/PortForwardingMacApp';
function forwardPort(port: number, multiplexChannelPort: number) {
return execFile(portforwardingClient, [
`-portForward=${port}`,
`-multiplexChannelPort=${multiplexChannelPort}`,
]);
}
// start port forwarding server for real device connections
const portForwarders: Array<ChildProcess> = GK.get('flipper_ios_device_support')
? [forwardPort(8089, 8079), forwardPort(8088, 8078)]
: [];
window.addEventListener('beforeunload', () => {
portForwarders.forEach(process => process.kill());
});
function queryDevices(store: Store, logger: Logger): Promise<void> {
const {connections} = store.getState();
const currentDeviceIDs: Set<string> = new Set(
connections.devices
.filter(device => device instanceof IOSDevice)
.map(device => device.serial),
);
return Promise.all([getActiveSimulators(), getActiveDevices()])
.then(([a, b]) => a.concat(b))
.then(activeDevices => {
for (const {udid, type, name} of activeDevices) {
if (currentDeviceIDs.has(udid)) {
currentDeviceIDs.delete(udid);
} else {
logger.track('usage', 'register-device', {
os: 'iOS',
type: type,
name: name,
serial: udid,
});
store.dispatch({
type: 'REGISTER_DEVICE',
payload: new IOSDevice(udid, type, name),
});
}
}
if (currentDeviceIDs.size > 0) {
currentDeviceIDs.forEach(id =>
logger.track('usage', 'unregister-device', {os: 'iOS', serial: id}),
);
store.dispatch({
type: 'UNREGISTER_DEVICES',
payload: currentDeviceIDs,
});
}
});
}
function getActiveSimulators(): Promise<Array<IOSDeviceParams>> {
return promisify(execFile)('xcrun', ['simctl', 'list', 'devices', '--json'], {
encoding: 'utf8',
})
.then(({stdout}) => JSON.parse(stdout).devices)
.then(simulatorDevices => {
const simulators: Array<iOSSimulatorDevice> = Object.values(
simulatorDevices,
// $FlowFixMe
).reduce((acc, cv) => acc.concat(cv), []);
return simulators
.filter(
simulator =>
simulator.state === 'Booted' &&
// For some users "availability" is set, for others it's "isAvailable"
// It's not clear which key is set, so we are checking both.
(simulator.availability === '(available)' ||
simulator.isAvailable === 'YES'),
)
.map(simulator => {
return {
udid: simulator.udid,
type: 'emulator',
name: simulator.name,
};
});
});
}
function getActiveDevices(): Promise<Array<IOSDeviceParams>> {
return iosUtil.targets().catch(e => {
console.error(new RecurringError(e.message));
return [];
});
}
export default (store: Store, logger: Logger) => {
// monitoring iOS devices only available on MacOS.
if (process.platform !== 'darwin') {
return;
}
queryDevices(store, logger)
.then(() => {
const simulatorUpdateInterval = setInterval(() => {
queryDevices(store, logger).catch(err => {
console.error(err);
clearInterval(simulatorUpdateInterval);
});
}, 3000);
})
.catch(console.error);
};