Files
flipper/desktop/flipper-plugin/src/plugin/DevicePlugin.tsx
Michel Weststrate 2d838efd4d Separate device in server and client version [2/n]
Summary:
This stack takes care of handling care of moving all device interactions over the (possible) async channel FlipperServer. The FlipperServer interface (see previous diff) allows listening to specific server events using `on`, and emit commands to be executed by the server by using `exec` (e.g. `exec('take-screenshot', serial) => Promise<buffer>`).

FlipperServerImpl implements this interface on the server side.

The device implementations are split as follows

```
server / backend process:

ServerDevice
- iOSDevice
- AndroidDevice
- MetroDevice
- DummyDevice
- Mac/Windows Device

frontend / ui:

BaseDevice: a normal connected, device, implements device apis as they already existed
- ArchivedDevice (note that this doesn't have a server counterpart)
- TestDevice (for unit tests, with stubbed backend communication)

```

All features of devices are for simplicity unified (since the deviations are small), where specific device types might not implement certain features like taking screenshots or running shell commands.

To avoid making this diff unnecessarily big, some open Todo's will be addressed later in this stack, and it shouldn't be landed alone.

Reviewed By: timur-valiev

Differential Revision: D30909346

fbshipit-source-id: cce0bee94fdd5db59bebe3577a6084219a038719
2021-09-22 09:03:32 -07:00

109 lines
2.9 KiB
TypeScript

/**
* 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 {SandyPluginDefinition} from './SandyPluginDefinition';
import {BasePluginInstance, BasePluginClient} from './PluginBase';
import {FlipperLib} from './FlipperLib';
import {Atom, ReadOnlyAtom} from '../state/atom';
import {DeviceOS, DeviceType} from '../types/server-types';
export type DeviceLogListener = (entry: DeviceLogEntry) => void;
export type DeviceLogEntry = {
readonly date: Date;
readonly type: LogLevel;
readonly message: string;
readonly pid: number;
readonly tid: number;
readonly app?: string;
readonly tag: string;
};
export type LogLevel =
| 'unknown'
| 'verbose'
| 'debug'
| 'info'
| 'warn'
| 'error'
| 'fatal';
export interface Device {
readonly realDevice: any; // TODO: temporarily, clean up T70688226
readonly isArchived: boolean;
readonly isConnected: boolean;
readonly os: DeviceOS;
readonly serial: string;
readonly deviceType: DeviceType;
onLogEntry(cb: DeviceLogListener): () => void;
}
export type DevicePluginPredicate = (device: Device) => boolean;
export type DevicePluginFactory = (client: DevicePluginClient) => object;
export interface DevicePluginClient extends BasePluginClient {
/**
* opens a different plugin by id, optionally providing a deeplink to bring the plugin to a certain state
*/
selectPlugin(pluginId: string, deeplinkPayload?: unknown): void;
readonly isConnected: boolean;
readonly connected: ReadOnlyAtom<boolean>;
}
/**
* Wrapper interface around BaseDevice in Flipper
*/
export interface RealFlipperDevice {
os: DeviceOS;
serial: string;
isArchived: boolean;
connected: Atom<boolean>;
deviceType: DeviceType;
addLogListener(callback: DeviceLogListener): Symbol;
removeLogListener(id: Symbol): void;
}
export class SandyDevicePluginInstance extends BasePluginInstance {
static is(thing: any): thing is SandyDevicePluginInstance {
return thing instanceof SandyDevicePluginInstance;
}
/** client that is bound to this instance */
readonly client: DevicePluginClient;
constructor(
flipperLib: FlipperLib,
definition: SandyPluginDefinition,
realDevice: RealFlipperDevice,
pluginKey: string,
initialStates?: Record<string, any>,
) {
super(flipperLib, definition, realDevice, pluginKey, initialStates);
this.client = {
...this.createBasePluginClient(),
selectPlugin(pluginId: string, deeplink?: unknown) {
flipperLib.selectPlugin(realDevice, null, pluginId, deeplink);
},
get isConnected() {
return realDevice.connected.get();
},
connected: realDevice.connected,
};
this.initializePlugin(() =>
definition.asDevicePluginModule().devicePlugin(this.client),
);
}
toJSON() {
return '[SandyDevicePluginInstance]';
}
}