Move common types to flipper-plugin [1/n]

Summary: This is the first diff in a stack of many where server and UI logic is further decoupled to be only communication through an event listener / emitting commands, where all data going over these media is json serializable. In this diff we extract the common interfaces that are to be used by both server and UI layer.

Reviewed By: passy

Differential Revision: D30899609

fbshipit-source-id: dc3c783707d47671f1d0f5dbf99cde17a8f69062
This commit is contained in:
Michel Weststrate
2021-09-22 09:01:29 -07:00
committed by Facebook GitHub Bot
parent d5aaa0034d
commit 845d0755f1
23 changed files with 136 additions and 82 deletions

View File

@@ -11,7 +11,7 @@
/* eslint-disable node/no-sync */
import {PluginDefinition} from './plugin';
import BaseDevice, {OS} from './server/devices/BaseDevice';
import BaseDevice from './server/devices/BaseDevice';
import {Logger} from './fb-interfaces/Logger';
import {Store} from './reducers/index';
import {performance} from 'perf_hooks';
@@ -31,6 +31,7 @@ import {
_SandyPluginInstance,
getFlipperLib,
timeout,
ClientQuery,
} from 'flipper-plugin';
import {freeze} from 'immer';
import GK from './fb-stubs/GK';
@@ -48,14 +49,6 @@ import {
type Plugins = Set<string>;
type PluginsArr = Array<string>;
export type ClientQuery = {
app: string;
os: OS;
device: string;
device_id: string;
sdk_version?: number;
};
export type ClientExport = {
id: string;
query: ClientQuery;

View File

@@ -14,6 +14,7 @@ import {FlipperServer} from '../server/FlipperServer';
import {selectClient, selectDevice} from '../reducers/connections';
import Client from '../Client';
import {notification} from 'antd';
import BaseDevice from '../server/devices/BaseDevice';
export default async (store: Store, logger: Logger) => {
const {enableAndroid, androidHome, idbPath, enableIOS, enablePhysicalIOS} =
@@ -75,14 +76,16 @@ export default async (store: Store, logger: Logger) => {
serial: device.serial,
});
device.loadDevicePlugins(
// TODO: fixed later in this stack
(device as BaseDevice).loadDevicePlugins(
store.getState().plugins.devicePlugins,
store.getState().connections.enabledDevicePlugins,
);
store.dispatch({
type: 'REGISTER_DEVICE',
payload: device,
// TODO: fixed later in this stack
payload: device as any,
});
});
@@ -95,7 +98,8 @@ export default async (store: Store, logger: Logger) => {
});
server.on('client-connected', (payload) =>
handleClientConnected(store, payload),
// TODO: fixed later in this stack
handleClientConnected(store, payload as any),
);
if (typeof window !== 'undefined') {

View File

@@ -7,7 +7,7 @@
* @format
*/
import {OS} from '../server/devices/BaseDevice';
import {DeviceOS} from 'flipper-plugin';
export default Object.freeze({
GRAPH_APP_ID: '',
@@ -36,7 +36,7 @@ export default Object.freeze({
workplaceGroupID: 0,
requiredPlugins: ['Inspector'],
defaultPlugins: ['DeviceLogs'],
supportedOS: ['Android'] as Array<OS>,
supportedOS: ['Android'] as Array<DeviceOS>,
deeplinkSuffix: 'default',
papercuts: '',
},

View File

@@ -42,7 +42,7 @@ export {default as AndroidDevice} from './server/devices/android/AndroidDevice';
export {default as ArchivedDevice} from './server/devices/ArchivedDevice';
export {default as IOSDevice} from './server/devices/ios/IOSDevice';
export {default as KaiOSDevice} from './server/devices/android/KaiOSDevice';
export {OS} from './server/devices/BaseDevice';
export {DeviceOS as OS} from 'flipper-plugin';
export {default as Button} from './ui/components/Button';
export {default as ToggleButton} from './ui/components/ToggleSwitch';
export {default as ButtonGroup} from './ui/components/ButtonGroup';

View File

@@ -18,8 +18,8 @@ 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 '../server/devices/BaseDevice';
import {getExportablePlugins} from '../selectors/connections';
import {DeviceOS} from 'flipper-plugin';
const {DEFAULT_SUPPORT_GROUP} = constants;
@@ -42,7 +42,7 @@ export class Group {
workplaceGroupID: number,
requiredPlugins: Array<string>,
defaultPlugins: Array<string>,
supportedOS: Array<OS>,
supportedOS: Array<DeviceOS>,
deeplinkSuffix: string,
papercuts?: string,
) {
@@ -58,7 +58,7 @@ export class Group {
requiredPlugins: Array<string>;
defaultPlugins: Array<string>;
workplaceGroupID: number;
supportedOS: Array<OS>;
supportedOS: Array<DeviceOS>;
deeplinkSuffix: string;
papercuts?: string;
@@ -70,7 +70,7 @@ export class Group {
getValidationMessage(
selectedPlugins: Array<string>,
selectedOS: OS | null,
selectedOS: DeviceOS | null,
): GroupValidationErrors {
const nonSelectedPlugin: Array<string> = [];
for (const plugin of this.requiredPlugins) {

View File

@@ -16,7 +16,7 @@ import {
CaretDownOutlined,
} from '@ant-design/icons';
import {Glyph, Layout, styled} from '../../ui';
import {theme, useTrackedCallback, useValue} from 'flipper-plugin';
import {DeviceOS, theme, useTrackedCallback, useValue} from 'flipper-plugin';
import {batch} from 'react-redux';
import {useDispatch, useStore} from '../../utils/useStore';
import {
@@ -25,7 +25,7 @@ import {
selectClient,
selectDevice,
} from '../../reducers/connections';
import BaseDevice, {OS} from '../../server/devices/BaseDevice';
import BaseDevice from '../../server/devices/BaseDevice';
import Client from '../../Client';
import {State} from '../../reducers';
import {brandColors, brandIcons, colors} from '../../ui/components/colors';
@@ -34,7 +34,7 @@ import GK from '../../fb-stubs/GK';
const {Text} = Typography;
function getOsIcon(os?: OS) {
function getOsIcon(os?: DeviceOS) {
switch (os) {
case 'iOS':
return <AppleOutlined />;

View File

@@ -28,19 +28,7 @@ import {IOSDeviceManager} from './devices/ios/iOSDeviceManager';
import metroDevice from './devices/metro/metroDeviceManager';
import desktopDevice from './devices/desktop/desktopDeviceManager';
import BaseDevice from './devices/BaseDevice';
type FlipperServerEvents = {
'server-state': {state: ServerState; error?: Error};
'server-error': any;
notification: {
type: 'error';
title: string;
description: string;
};
'device-connected': BaseDevice;
'device-disconnected': BaseDevice;
'client-connected': Client;
};
import {FlipperServerEvents, FlipperServerState} from 'flipper-plugin';
export interface FlipperServerConfig {
enableAndroid: boolean;
@@ -51,8 +39,6 @@ export interface FlipperServerConfig {
serverPorts: ServerPorts;
}
type ServerState = 'pending' | 'starting' | 'started' | 'error' | 'closed';
// defaultConfig should be used for testing only, and disables by default all features
const defaultConfig: FlipperServerConfig = {
androidHome: '',
@@ -82,7 +68,7 @@ export class FlipperServer {
readonly server: ServerController;
readonly disposers: ((() => void) | void)[] = [];
private readonly devices = new Map<string, BaseDevice>();
state: ServerState = 'pending';
state: FlipperServerState = 'pending';
android: AndroidDeviceManager;
ios: IOSDeviceManager;
@@ -171,7 +157,7 @@ export class FlipperServer {
);
}
setServerState(state: ServerState, error?: Error) {
setServerState(state: FlipperServerState, error?: Error) {
this.state = state;
this.emit('server-state', {state, error});
}

View File

@@ -11,9 +11,10 @@ import {
CertificateExchangeMedium,
SecureServerConfig,
} from '../utils/CertificateProvider';
import Client, {ClientQuery} from '../../Client';
import Client from '../../Client';
import {ClientConnection} from './ClientConnection';
import {transformCertificateExchangeMediumToType} from './Utilities';
import {ClientQuery} from 'flipper-plugin';
/**
* ClientCsrQuery defines a client query with CSR

View File

@@ -9,7 +9,7 @@
import {CertificateExchangeMedium} from '../utils/CertificateProvider';
import {Logger} from '../../fb-interfaces/Logger';
import {ClientQuery} from '../../Client';
import {ClientQuery} from 'flipper-plugin';
import {Store, State} from '../../reducers/index';
import CertificateProvider from '../utils/CertificateProvider';
import Client from '../../Client';
@@ -345,18 +345,21 @@ class ServerController extends EventEmitter implements ServerEventsListener {
const app_name = await this.certificateProvider.extractAppNameFromCSR(
csr,
);
query.device_id = await this.certificateProvider.getTargetDeviceId(
query.os,
app_name,
csr_path,
csr,
);
// TODO: allocate new object, kept now as is to keep changes minimal
(query as any).device_id =
await this.certificateProvider.getTargetDeviceId(
query.os,
app_name,
csr_path,
csr,
);
console.log(
`[conn] Detected ${app_name} on ${query.device_id} in certificate`,
);
}
query.app = appNameWithUpdateHint(query);
// TODO: allocate new object, kept now as is to keep changes minimal
(query as any).app = appNameWithUpdateHint(query);
const id = buildClientId({
app: query.app,

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 from '../../Client';
import {Single} from 'rsocket-flowable';
import {
ClientConnection,
@@ -25,6 +25,7 @@ import {
ConnectionStatus,
ResponseType,
} from './ClientConnection';
import {ClientQuery} from 'flipper-plugin';
/**
* RSocket based server. RSocket uses its own protocol for communication between

View File

@@ -12,8 +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 {OS} from '../devices/BaseDevice';
import Client from '../../Client';
import {
ClientConnection,
ConnectionStatus,
@@ -21,6 +20,7 @@ import {
ErrorType,
} from './ClientConnection';
import {IncomingMessage} from 'http';
import {ClientQuery, DeviceOS} from 'flipper-plugin';
/**
* WebSocket-based server.
@@ -182,7 +182,7 @@ class ServerWebSocket extends ServerWebSocketBase {
* Validates a string as being one of those defined as valid OS.
* @param str An input string.
*/
private isOS(str: string): str is OS {
private isOS(str: string): str is DeviceOS {
return (
str === 'iOS' ||
str === 'Android' ||
@@ -224,7 +224,7 @@ class ServerWebSocket extends ServerWebSocketBase {
return;
}
let os: OS | undefined;
let os: DeviceOS | undefined;
if (typeof query.os === 'string' && this.isOS(query.os)) {
os = query.os;
} else {
@@ -241,7 +241,8 @@ class ServerWebSocket extends ServerWebSocketBase {
if (typeof query.sdk_version === 'string') {
const sdk_version = parseInt(query.sdk_version, 10);
if (sdk_version) {
clientQuery.sdk_version = sdk_version;
// TODO: allocate new object, kept now as is to keep changes minimal
(clientQuery as any).sdk_version = sdk_version;
}
}

View File

@@ -10,12 +10,13 @@
import ServerWebSocketBase from './ServerWebSocketBase';
import WebSocket from 'ws';
import querystring from 'querystring';
import Client, {ClientQuery} from '../../Client';
import Client from '../../Client';
import {BrowserClientFlipperConnection} from './BrowserClientFlipperConnection';
import {ServerEventsListener} from './ServerAdapter';
import constants from '../../fb-stubs/constants';
import ws from 'ws';
import {IncomingMessage} from 'http';
import {ClientQuery} from 'flipper-plugin';
/**
* WebSocket-based server which uses a connect/disconnect handshake over an insecure channel.

View File

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

View File

@@ -8,8 +8,8 @@
*/
import BaseDevice from './BaseDevice';
import type {DeviceType} from 'flipper-plugin';
import {OS, DeviceShell} from './BaseDevice';
import type {DeviceOS, DeviceType} from 'flipper-plugin';
import {DeviceShell} from './BaseDevice';
import {SupportFormRequestDetailsState} from '../../reducers/supportForm';
export default class ArchivedDevice extends BaseDevice {
@@ -19,7 +19,7 @@ export default class ArchivedDevice extends BaseDevice {
serial: string;
deviceType: DeviceType;
title: string;
os: OS;
os: DeviceOS;
screenshotHandle?: string | null;
source?: string;
supportRequestDetails?: SupportFormRequestDetailsState;

View File

@@ -17,8 +17,9 @@ import {
Idler,
createState,
getFlipperLib,
DeviceOS,
} from 'flipper-plugin';
import {DeviceSpec, OS as PluginOS, PluginDetails} from 'flipper-plugin-lib';
import {DeviceSpec, PluginDetails} from 'flipper-plugin-lib';
import {getPluginKey} from '../../utils/pluginKey';
export type DeviceShell = {
@@ -27,13 +28,11 @@ export type DeviceShell = {
stdin: stream.Writable;
};
export type OS = PluginOS | 'Windows' | 'MacOS';
type PluginDefinition = _SandyPluginDefinition;
type PluginMap = Map<string, PluginDefinition>;
export type DeviceExport = {
os: OS;
os: DeviceOS;
title: string;
deviceType: DeviceType;
serial: string;
@@ -48,7 +47,7 @@ export default class BaseDevice {
serial: string,
deviceType: DeviceType,
title: string,
os: OS,
os: DeviceOS,
specs: DeviceSpec[] = [],
) {
this.serial = serial;
@@ -59,7 +58,7 @@ export default class BaseDevice {
}
// operating system of this device
os: OS;
os: DeviceOS;
// human readable name for this device
title: string;
@@ -89,7 +88,7 @@ export default class BaseDevice {
_SandyDevicePluginInstance
>();
supportsOS(os: OS) {
supportsOS(os: DeviceOS) {
return os.toLowerCase() === this.os.toLowerCase();
}

View File

@@ -7,13 +7,14 @@
* @format
*/
import BaseDevice, {OS} from './BaseDevice';
import {DeviceOS} from 'flipper-plugin';
import BaseDevice from './BaseDevice';
/**
* Use this device when you do not have the actual uuid of the device. For example, it is currently used in the case when, we do certificate exchange through WWW mode. In this mode we do not know the device id of the app and we generate a fake one.
*/
export default class DummyDevice extends BaseDevice {
constructor(serial: string, title: string, os: OS) {
constructor(serial: string, title: string, os: DeviceOS) {
super(serial, 'dummy', title, os);
}
}

View File

@@ -8,10 +8,10 @@
*/
import {createStore} from 'redux';
import BaseDevice, {OS} from '../server/devices/BaseDevice';
import BaseDevice from '../server/devices/BaseDevice';
import {createRootReducer} from '../reducers';
import {Store} from '../reducers/index';
import Client, {ClientQuery} from '../Client';
import Client from '../Client';
import {
ClientConnection,
ConnectionStatusChange,
@@ -25,6 +25,7 @@ import {initializeFlipperLibImplementation} from '../utils/flipperLibImplementat
import pluginManager from '../dispatcher/pluginManager';
import {PluginDetails} from 'flipper-plugin-lib';
import ArchivedDevice from '../server/devices/ArchivedDevice';
import {ClientQuery, DeviceOS} from 'flipper-plugin';
export interface AppOptions {
plugins?: PluginDefinition[];
@@ -43,7 +44,7 @@ export interface DeviceOptions {
serial?: string;
isSupportedByPlugin?: (p: PluginDetails) => boolean;
archived?: boolean;
os?: OS;
os?: DeviceOS;
}
export default class MockFlipper {

View File

@@ -24,7 +24,7 @@ import {
import BaseDevice from '../server/devices/BaseDevice';
import {Store} from '../reducers/index';
import Client, {ClientQuery} from '../Client';
import Client from '../Client';
import {Logger} from '../fb-interfaces/Logger';
import {FlipperDevicePlugin, FlipperPlugin, PluginDefinition} from '../plugin';
@@ -36,7 +36,7 @@ import MockFlipper from './MockFlipper';
import {switchPlugin} from '../reducers/pluginManager';
import {createSandyPluginFromClassicPlugin} from '../dispatcher/plugins';
import {createMockActivatablePluginDetails} from '../utils/testUtils';
import {_SandyPluginDefinition} from 'flipper-plugin';
import {ClientQuery, _SandyPluginDefinition} from 'flipper-plugin';
export type MockFlipperResult = {
client: Client;

View File

@@ -15,7 +15,7 @@ import {Store, MiddlewareAPI} from '../reducers';
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 Client, {ClientExport} from '../Client';
import {getAppVersion} from './info';
import {pluginKey} from '../utils/pluginKey';
import {DevicePluginMap, ClientPluginMap} from '../plugin';
@@ -40,7 +40,7 @@ import {processMessageQueue} from './messageQueue';
import {getPluginTitle} from './pluginUtils';
import {capture} from './screenshot';
import {uploadFlipperMedia} from '../fb-stubs/user';
import {Idler} from 'flipper-plugin';
import {ClientQuery, Idler} from 'flipper-plugin';
export const IMPORT_FLIPPER_TRACE_EVENT = 'import-flipper-trace';
export const EXPORT_FLIPPER_TRACE_EVENT = 'export-flipper-trace';

View File

@@ -85,7 +85,6 @@ test('Correct top level API exposed', () => {
"DeviceLogEntry",
"DeviceLogListener",
"DevicePluginClient",
"DeviceType",
"Draft",
"ElementAttribute",
"ElementData",

View File

@@ -25,7 +25,6 @@ export {
DevicePluginClient,
LogLevel,
SandyDevicePluginInstance as _SandyDevicePluginInstance,
DeviceType,
} from './plugin/DevicePlugin';
export {SandyPluginDefinition as _SandyPluginDefinition} from './plugin/SandyPluginDefinition';
export {SandyPluginRenderer as _SandyPluginRenderer} from './plugin/PluginRenderer';
@@ -142,3 +141,5 @@ export {textContent} from './utils/textContent';
// Probably we should make sure that testing-library doesn't end up in our final Flipper bundle (which packages flipper-plugin)
// T69106962
export const TestUtils = TestUtilites;
export * from './types/server-types';

View File

@@ -10,8 +10,8 @@
import {SandyPluginDefinition} from './SandyPluginDefinition';
import {BasePluginInstance, BasePluginClient} from './PluginBase';
import {FlipperLib} from './FlipperLib';
import {DeviceType as PluginDeviceType} from 'flipper-plugin-lib';
import {Atom, ReadOnlyAtom} from '../state/atom';
import {DeviceOS, DeviceType} from '../types/server-types';
export type DeviceLogListener = (entry: DeviceLogEntry) => void;
@@ -38,14 +38,12 @@ export interface Device {
readonly realDevice: any; // TODO: temporarily, clean up T70688226
readonly isArchived: boolean;
readonly isConnected: boolean;
readonly os: string;
readonly os: DeviceOS;
readonly serial: string;
readonly deviceType: DeviceType;
onLogEntry(cb: DeviceLogListener): () => void;
}
export type DeviceType = PluginDeviceType;
export type DevicePluginPredicate = (device: Device) => boolean;
export type DevicePluginFactory = (client: DevicePluginClient) => object;
@@ -64,7 +62,7 @@ export interface DevicePluginClient extends BasePluginClient {
* Wrapper interface around BaseDevice in Flipper
*/
export interface RealFlipperDevice {
os: string;
os: DeviceOS;
serial: string;
isArchived: boolean;
connected: Atom<boolean>;

View File

@@ -0,0 +1,65 @@
/**
* 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 {
DeviceType as PluginDeviceType,
OS as PluginOS,
} from 'flipper-plugin-lib';
// In the future, this file would deserve it's own package, as it doesn't really relate to plugins.
// Since flipper-plugin however is currently shared among server, client and defines a lot of base types, leaving it here for now.
export type FlipperServerState =
| 'pending'
| 'starting'
| 'started'
| 'error'
| 'closed';
export type DeviceType = PluginDeviceType;
export type DeviceOS = PluginOS | 'Windows' | 'MacOS';
export type DeviceDescription = {
readonly os: DeviceOS;
readonly title: string;
readonly deviceType: DeviceType;
readonly serial: string;
};
export type ClientQuery = {
readonly app: string;
readonly os: DeviceOS;
readonly device: string;
readonly device_id: string;
readonly sdk_version?: number;
};
export type ClientDescription = {
readonly id: string;
readonly query: ClientQuery;
readonly sdkVersion: number;
};
export type FlipperServerEvents = {
'server-state': {state: FlipperServerState; error?: Error};
'server-error': any;
notification: {
type: 'error';
title: string;
description: string;
};
'device-connected': DeviceDescription;
'device-disconnected': DeviceDescription;
'client-connected': ClientDescription;
};
export type FlipperServerCommands = {
// TODO
};