Restore metro functionality [4/n]

Summary: Restored Metro functionality; progress reports, metro logs, RN/Hermes debugging, reload / dev menu button

Reviewed By: passy

Differential Revision: D31055958

fbshipit-source-id: c243035c343c14718a9afe275c8f5f36a1aa3a94
This commit is contained in:
Michel Weststrate
2021-09-22 09:01:29 -07:00
committed by Facebook GitHub Bot
parent 3428ce2968
commit 4463e7ede2
6 changed files with 32 additions and 21 deletions

View File

@@ -14,6 +14,7 @@ import {
createState, createState,
DevicePluginClient, DevicePluginClient,
PluginClient, PluginClient,
sleep,
} from 'flipper-plugin'; } from 'flipper-plugin';
import {handleClientConnected} from '../dispatcher/flipperServer'; import {handleClientConnected} from '../dispatcher/flipperServer';
import {TestDevice} from '../test-utils/TestDevice'; import {TestDevice} from '../test-utils/TestDevice';
@@ -89,9 +90,7 @@ test('New device with same serial removes & cleans the old one', async () => {
}, },
}, },
); );
const {device, store, logger} = await createMockFlipperWithPlugin( const {device, store} = await createMockFlipperWithPlugin(deviceplugin);
deviceplugin,
);
const instance = device.sandyPluginStates.get(deviceplugin.id)!; const instance = device.sandyPluginStates.get(deviceplugin.id)!;
@@ -116,6 +115,7 @@ test('New device with same serial removes & cleans the old one', async () => {
store.getState().connections.enabledDevicePlugins, store.getState().connections.enabledDevicePlugins,
); );
await sleep(100);
expect(device.isArchived).toBe(false); expect(device.isArchived).toBe(false);
expect(device.connected.get()).toBe(false); expect(device.connected.get()).toBe(false);
expect(instance.instanceApi.destroy).toBeCalledTimes(1); expect(instance.instanceApi.destroy).toBeCalledTimes(1);

View File

@@ -8,24 +8,23 @@
*/ */
import React, {useCallback, useEffect, useState} from 'react'; import React, {useCallback, useEffect, useState} from 'react';
import MetroDevice, { import {MetroReportableEvent} from '../server/devices/metro/MetroDevice';
MetroReportableEvent,
} from '../server/devices/metro/MetroDevice';
import {useStore} from '../utils/useStore'; import {useStore} from '../utils/useStore';
import {Button as AntButton} from 'antd'; import {Button as AntButton} from 'antd';
import {MenuOutlined, ReloadOutlined} from '@ant-design/icons'; import {MenuOutlined, ReloadOutlined} from '@ant-design/icons';
import {theme} from 'flipper-plugin'; import {theme} from 'flipper-plugin';
import BaseDevice from '../devices/BaseDevice';
export default function MetroButton() { export default function MetroButton() {
const device = useStore((state) => const device = useStore((state) =>
state.connections.devices.find( state.connections.devices.find(
(device) => device.os === 'Metro' && device.connected.get(), (device) => device.os === 'Metro' && device.connected.get(),
), ),
) as MetroDevice | undefined; ) as BaseDevice | undefined;
const sendCommand = useCallback( const sendCommand = useCallback(
(command: string) => { (command: string) => {
device?.sendCommand(command); device?.sendMetroCommand(command);
}, },
[device], [device],
); );
@@ -50,9 +49,19 @@ export default function MetroButton() {
setProgress(event.transformedFileCount / event.totalFileCount); setProgress(event.transformedFileCount / event.totalFileCount);
} }
} }
device.metroEventEmitter.on('event', metroEventListener);
const handle = device.addLogListener((l) => {
if (l.tag !== 'client_log') {
try {
metroEventListener(JSON.parse(l.message));
} catch (e) {
console.warn('Failed to parse metro message: ', l, e);
}
}
});
return () => { return () => {
device.metroEventEmitter.off('event', metroEventListener); device.removeLogListener(handle);
}; };
}, [device]); }, [device]);

View File

@@ -229,6 +229,10 @@ export default class BaseDevice {
return this.flipperServer.exec('device-shell-exec', this.serial, command); return this.flipperServer.exec('device-shell-exec', this.serial, command);
} }
async sendMetroCommand(command: string): Promise<void> {
return this.flipperServer.exec('metro-command', this.serial, command);
}
supportsPlugin(plugin: PluginDefinition | PluginDetails) { supportsPlugin(plugin: PluginDefinition | PluginDetails) {
let pluginDetails: PluginDetails; let pluginDetails: PluginDetails;
if (plugin instanceof _SandyPluginDefinition) { if (plugin instanceof _SandyPluginDefinition) {

View File

@@ -250,7 +250,9 @@ export default (state: State = INITAL_STATE, action: Actions): State => {
`Tried to replace still connected device '${d.serial}' with a new instance`, `Tried to replace still connected device '${d.serial}' with a new instance`,
); );
} }
d.destroy(); setImmediate(() => {
d.destroy();
});
newDevices[existing] = payload; newDevices[existing] = payload;
} else { } else {
newDevices.push(payload); newDevices.push(payload);

View File

@@ -8,7 +8,6 @@
*/ */
import {LogLevel} from 'flipper-plugin'; import {LogLevel} from 'flipper-plugin';
import {EventEmitter} from 'events';
import util from 'util'; import util from 'util';
import {FlipperServerImpl} from '../../FlipperServerImpl'; import {FlipperServerImpl} from '../../FlipperServerImpl';
import {ServerDevice} from '../ServerDevice'; import {ServerDevice} from '../ServerDevice';
@@ -142,7 +141,6 @@ function getLoglevelFromMessageType(
export default class MetroDevice extends ServerDevice { export default class MetroDevice extends ServerDevice {
ws?: WebSocket; ws?: WebSocket;
metroEventEmitter = new EventEmitter();
constructor( constructor(
flipperServer: FlipperServerImpl, flipperServer: FlipperServerImpl,
@@ -190,7 +188,6 @@ export default class MetroDevice extends ServerDevice {
}); });
} }
} }
this.metroEventEmitter.emit('event', message);
}; };
sendCommand(command: string, params?: any) { sendCommand(command: string, params?: any) {

View File

@@ -30,8 +30,7 @@ const CONNECTED = 'DevTools connected';
const DEV_TOOLS_PORT = 8097; // hardcoded in RN const DEV_TOOLS_PORT = 8097; // hardcoded in RN
interface MetroDevice { interface MetroDevice {
ws?: WebSocket; sendMetroCommand(command: string, params?: any): void;
sendCommand(command: string, params?: any): void;
} }
function findGlobalDevTools(): Promise<string | undefined> { function findGlobalDevTools(): Promise<string | undefined> {
@@ -66,7 +65,7 @@ enum ConnectionStatus {
export function devicePlugin(client: DevicePluginClient) { export function devicePlugin(client: DevicePluginClient) {
const metroDevice: MetroDevice = client.device.realDevice; const metroDevice: MetroDevice = client.device.realDevice;
if (!metroDevice.sendCommand || !('ws' in metroDevice)) { if (!metroDevice.sendMetroCommand) {
throw new Error('Invalid metroDevice'); throw new Error('Invalid metroDevice');
} }
@@ -196,12 +195,12 @@ export function devicePlugin(client: DevicePluginClient) {
return; return;
// Waiting for connection, but we do have an active Metro connection, lets force a reload to enter Dev Mode on app // Waiting for connection, but we do have an active Metro connection, lets force a reload to enter Dev Mode on app
// prettier-ignore // prettier-ignore
case connectionStatus.get() === ConnectionStatus.Initializing && !!metroDevice?.ws: case connectionStatus.get() === ConnectionStatus.Initializing:
setStatus( setStatus(
ConnectionStatus.WaitingForReload, ConnectionStatus.WaitingForReload,
"Sending 'reload' to Metro to force the DevTools to connect...", "Sending 'reload' to Metro to force the DevTools to connect...",
); );
metroDevice!.sendCommand('reload'); metroDevice!.sendMetroCommand('reload');
startPollForConnection(2000); startPollForConnection(2000);
return; return;
// Waiting for initial connection, but no WS bridge available // Waiting for initial connection, but no WS bridge available
@@ -295,12 +294,12 @@ export function Component() {
<Typography.Text type="secondary">{statusMessage}</Typography.Text> <Typography.Text type="secondary">{statusMessage}</Typography.Text>
) : null} ) : null}
{(connectionStatus === ConnectionStatus.WaitingForReload && {(connectionStatus === ConnectionStatus.WaitingForReload &&
instance.metroDevice?.ws) || instance.metroDevice) ||
connectionStatus === ConnectionStatus.Error ? ( connectionStatus === ConnectionStatus.Error ? (
<Button <Button
size="small" size="small"
onClick={() => { onClick={() => {
instance.metroDevice?.sendCommand('reload'); instance.metroDevice?.sendMetroCommand('reload');
instance.bootDevTools(); instance.bootDevTools();
}}> }}>
Retry Retry