From 3c6668a8b963d13e648ffdaba60e5a38568cb629 Mon Sep 17 00:00:00 2001 From: Michel Weststrate Date: Wed, 8 Dec 2021 04:25:28 -0800 Subject: [PATCH] Make sure devices and clients are registered on session startup Summary: This diff makes sure that when the client starts, it fetches all known devices and clients first, as it might have missed the 'connect' events for those. For Electron this wasn't needed, since the server starts with the UI, but this makes sure that a browser reload or a second connection sees the same devices & apps Reviewed By: aigoncharov Differential Revision: D32881589 fbshipit-source-id: 7b1cb3d296044f83dedcf3f3d8d02864690b6666 --- desktop/flipper-common/src/server-types.tsx | 2 + .../src/FlipperServerImpl.tsx | 6 ++ .../src/dispatcher/flipperServer.tsx | 90 ++++++++++++------- 3 files changed, 67 insertions(+), 31 deletions(-) diff --git a/desktop/flipper-common/src/server-types.tsx b/desktop/flipper-common/src/server-types.tsx index 19b9824d5..dfe37ba61 100644 --- a/desktop/flipper-common/src/server-types.tsx +++ b/desktop/flipper-common/src/server-types.tsx @@ -134,6 +134,7 @@ export type IOSDeviceParams = { export type FlipperServerCommands = { 'get-config': () => Promise; 'get-changelog': () => Promise; + 'device-list': () => Promise; 'device-start-logging': (serial: string) => Promise; 'device-stop-logging': (serial: string) => Promise; 'device-supports-screenshot': (serial: string) => Promise; @@ -153,6 +154,7 @@ export type FlipperServerCommands = { 'device-clear-logs': (serial: string) => Promise; 'device-navigate': (serial: string, location: string) => Promise; 'metro-command': (serial: string, command: string) => Promise; + 'client-list': () => Promise; 'client-request': (clientId: string, payload: any) => Promise; 'client-request-response': ( clientId: string, diff --git a/desktop/flipper-server-core/src/FlipperServerImpl.tsx b/desktop/flipper-server-core/src/FlipperServerImpl.tsx index fe295dd0b..89623349f 100644 --- a/desktop/flipper-server-core/src/FlipperServerImpl.tsx +++ b/desktop/flipper-server-core/src/FlipperServerImpl.tsx @@ -214,6 +214,9 @@ export class FlipperServerImpl implements FlipperServer { private commandHandler: FlipperServerCommands = { 'get-config': async () => this.config, 'get-changelog': getChangelog, + 'device-list': async () => { + return Array.from(this.devices.values()).map((d) => d.info); + }, 'device-start-logging': async (serial: string) => this.getDevice(serial).startLogging(), 'device-stop-logging': async (serial: string) => @@ -242,6 +245,9 @@ export class FlipperServerImpl implements FlipperServer { } device.sendCommand(command); }, + 'client-list': async () => { + return Array.from(this.server.connections.values()).map((c) => c.client); + }, 'client-request': async (clientId, payload) => { this.server.connections.get(clientId)?.connection?.send(payload); }, diff --git a/desktop/flipper-ui-core/src/dispatcher/flipperServer.tsx b/desktop/flipper-ui-core/src/dispatcher/flipperServer.tsx index 5b8427d86..9ee7269ba 100644 --- a/desktop/flipper-ui-core/src/dispatcher/flipperServer.tsx +++ b/desktop/flipper-ui-core/src/dispatcher/flipperServer.tsx @@ -14,6 +14,7 @@ import { Logger, NoLongerConnectedToClientError, isTest, + DeviceDescription, } from 'flipper-common'; import Client from '../Client'; import {notification} from 'antd'; @@ -64,37 +65,7 @@ export function connectFlipperServerToStore( }); server.on('device-connected', (deviceInfo) => { - logger.track('usage', 'register-device', { - os: deviceInfo.os, - name: deviceInfo.title, - serial: deviceInfo.serial, - }); - - const existing = store - .getState() - .connections.devices.find( - (device) => device.serial === deviceInfo.serial, - ); - // handled outside reducer, as it might emit new redux actions... - if (existing) { - if (existing.connected.get()) { - console.warn( - `Tried to replace still connected device '${existing.serial}' with a new instance.`, - ); - } - existing.destroy(); - } - - const device = new BaseDevice(server, deviceInfo); - device.loadDevicePlugins( - store.getState().plugins.devicePlugins, - store.getState().connections.enabledDevicePlugins, - ); - - store.dispatch({ - type: 'REGISTER_DEVICE', - payload: device, - }); + handleDeviceConnected(server, store, logger, deviceInfo); }); server.on('device-disconnected', (device) => { @@ -141,6 +112,26 @@ export function connectFlipperServerToStore( 'Flipper server started and accepting device / client connections', ); + server + .exec('device-list') + .then((devices) => { + // register all devices + devices.forEach((device) => { + handleDeviceConnected(server, store, logger, device); + }); + }) + .then(() => { + return server.exec('client-list'); + }) + .then((clients) => { + clients.forEach((client) => { + handleClientConnected(server, store, logger, client); + }); + }) + .catch((e) => { + console.error('Failed to get initial device/client list: ', e); + }); + return () => { sideEffectDisposer?.(); server.close(); @@ -182,6 +173,43 @@ function startSideEffects(store: Store, server: FlipperServer) { }; } +function handleDeviceConnected( + server: FlipperServer, + store: Store, + logger: Logger, + deviceInfo: DeviceDescription, +) { + logger.track('usage', 'register-device', { + os: deviceInfo.os, + name: deviceInfo.title, + serial: deviceInfo.serial, + }); + + const existing = store + .getState() + .connections.devices.find((device) => device.serial === deviceInfo.serial); + // handled outside reducer, as it might emit new redux actions... + if (existing) { + if (existing.connected.get()) { + console.warn( + `Tried to replace still connected device '${existing.serial}' with a new instance.`, + ); + } + existing.destroy(); + } + + const device = new BaseDevice(server, deviceInfo); + device.loadDevicePlugins( + store.getState().plugins.devicePlugins, + store.getState().connections.enabledDevicePlugins, + ); + + store.dispatch({ + type: 'REGISTER_DEVICE', + payload: device, + }); +} + export async function handleClientConnected( server: Pick, store: Store,