Expose more meta information for plugins
Summary: expose `appName`, `appId` and `device` to Sandy plugins. Will be used in next diff to migrate navigation plugin Reviewed By: cekkaewnumchai Differential Revision: D24857253 fbshipit-source-id: 03ac3d376d5d1950bcf3d78386a65ce167b517e3
This commit is contained in:
committed by
Facebook GitHub Bot
parent
9b4e7e873c
commit
1157976eef
@@ -67,6 +67,8 @@ export function plugin(client: PluginClient<Events, Methods>) {
|
|||||||
return client.send('currentState', {since: 0});
|
return client.send('currentState', {since: 0});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expect(client.device).not.toBeNull();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
activateStub,
|
activateStub,
|
||||||
deactivateStub,
|
deactivateStub,
|
||||||
@@ -75,6 +77,8 @@ export function plugin(client: PluginClient<Events, Methods>) {
|
|||||||
disconnectStub,
|
disconnectStub,
|
||||||
getCurrentState,
|
getCurrentState,
|
||||||
state,
|
state,
|
||||||
|
appId: client.appId,
|
||||||
|
appName: client.appName,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ test('it can start a plugin and lifecycle events', () => {
|
|||||||
expect(instance.deactivateStub).toBeCalledTimes(2);
|
expect(instance.deactivateStub).toBeCalledTimes(2);
|
||||||
expect(instance.destroyStub).toBeCalledTimes(1);
|
expect(instance.destroyStub).toBeCalledTimes(1);
|
||||||
|
|
||||||
|
expect(instance.appName).toBe('TestApplication');
|
||||||
|
expect(instance.appId).toBe('TestApplication#Android#TestDevice#serial-000');
|
||||||
|
|
||||||
// cannot interact with destroyed plugin
|
// cannot interact with destroyed plugin
|
||||||
expect(() => {
|
expect(() => {
|
||||||
p.connect();
|
p.connect();
|
||||||
|
|||||||
@@ -46,15 +46,14 @@ export type DevicePluginPredicate = (device: Device) => boolean;
|
|||||||
|
|
||||||
export type DevicePluginFactory = (client: DevicePluginClient) => object;
|
export type DevicePluginFactory = (client: DevicePluginClient) => object;
|
||||||
|
|
||||||
export interface DevicePluginClient extends BasePluginClient {
|
export interface DevicePluginClient extends BasePluginClient {}
|
||||||
readonly device: Device;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper interface around BaseDevice in Flipper
|
* Wrapper interface around BaseDevice in Flipper
|
||||||
*/
|
*/
|
||||||
export interface RealFlipperDevice {
|
export interface RealFlipperDevice {
|
||||||
os: string;
|
os: string;
|
||||||
|
serial: string;
|
||||||
isArchived: boolean;
|
isArchived: boolean;
|
||||||
deviceType: DeviceType;
|
deviceType: DeviceType;
|
||||||
addLogListener(callback: DeviceLogListener): Symbol;
|
addLogListener(callback: DeviceLogListener): Symbol;
|
||||||
@@ -76,25 +75,8 @@ export class SandyDevicePluginInstance extends BasePluginInstance {
|
|||||||
realDevice: RealFlipperDevice,
|
realDevice: RealFlipperDevice,
|
||||||
initialStates?: Record<string, any>,
|
initialStates?: Record<string, any>,
|
||||||
) {
|
) {
|
||||||
super(flipperLib, definition, initialStates);
|
super(flipperLib, definition, realDevice, initialStates);
|
||||||
const device: Device = {
|
this.client = this.createBasePluginClient();
|
||||||
realDevice, // TODO: temporarily, clean up T70688226
|
|
||||||
// N.B. we model OS as string, not as enum, to make custom device types possible in the future
|
|
||||||
os: realDevice.os,
|
|
||||||
isArchived: realDevice.isArchived,
|
|
||||||
deviceType: realDevice.deviceType,
|
|
||||||
|
|
||||||
onLogEntry(cb) {
|
|
||||||
const handle = realDevice.addLogListener(cb);
|
|
||||||
return () => {
|
|
||||||
realDevice.removeLogListener(handle);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
this.client = {
|
|
||||||
...this.createBasePluginClient(),
|
|
||||||
device,
|
|
||||||
};
|
|
||||||
this.initializePlugin(() =>
|
this.initializePlugin(() =>
|
||||||
definition.asDevicePluginModule().devicePlugin(this.client),
|
definition.asDevicePluginModule().devicePlugin(this.client),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
import {SandyPluginDefinition} from './SandyPluginDefinition';
|
import {SandyPluginDefinition} from './SandyPluginDefinition';
|
||||||
import {BasePluginInstance, BasePluginClient} from './PluginBase';
|
import {BasePluginInstance, BasePluginClient} from './PluginBase';
|
||||||
import {FlipperLib} from './FlipperLib';
|
import {FlipperLib} from './FlipperLib';
|
||||||
|
import {RealFlipperDevice} from './DevicePlugin';
|
||||||
|
|
||||||
type EventsContract = Record<string, any>;
|
type EventsContract = Record<string, any>;
|
||||||
type MethodsContract = Record<string, (params: any) => Promise<any>>;
|
type MethodsContract = Record<string, (params: any) => Promise<any>>;
|
||||||
@@ -26,6 +27,16 @@ export interface PluginClient<
|
|||||||
Events extends EventsContract = {},
|
Events extends EventsContract = {},
|
||||||
Methods extends MethodsContract = {}
|
Methods extends MethodsContract = {}
|
||||||
> extends BasePluginClient {
|
> extends BasePluginClient {
|
||||||
|
/**
|
||||||
|
* Identifier that uniquely identifies the connected application
|
||||||
|
*/
|
||||||
|
readonly appId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registered name for the connected application
|
||||||
|
*/
|
||||||
|
readonly appName: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the onConnect event is fired whenever the plugin is connected to it's counter part on the device.
|
* the onConnect event is fired whenever the plugin is connected to it's counter part on the device.
|
||||||
* For most plugins this event is fired if the user selects the plugin,
|
* For most plugins this event is fired if the user selects the plugin,
|
||||||
@@ -71,6 +82,14 @@ export interface PluginClient<
|
|||||||
* Plugin Factory. For internal purposes only
|
* Plugin Factory. For internal purposes only
|
||||||
*/
|
*/
|
||||||
export interface RealFlipperClient {
|
export interface RealFlipperClient {
|
||||||
|
id: string;
|
||||||
|
query: {
|
||||||
|
app: string;
|
||||||
|
os: string;
|
||||||
|
device: string;
|
||||||
|
device_id: string;
|
||||||
|
};
|
||||||
|
deviceSync: RealFlipperDevice;
|
||||||
isBackgroundPlugin(pluginId: string): boolean;
|
isBackgroundPlugin(pluginId: string): boolean;
|
||||||
initPlugin(pluginId: string): void;
|
initPlugin(pluginId: string): void;
|
||||||
deinitPlugin(pluginId: string): void;
|
deinitPlugin(pluginId: string): void;
|
||||||
@@ -108,11 +127,17 @@ export class SandyPluginInstance extends BasePluginInstance {
|
|||||||
realClient: RealFlipperClient,
|
realClient: RealFlipperClient,
|
||||||
initialStates?: Record<string, any>,
|
initialStates?: Record<string, any>,
|
||||||
) {
|
) {
|
||||||
super(flipperLib, definition, initialStates);
|
super(flipperLib, definition, realClient.deviceSync, initialStates);
|
||||||
this.realClient = realClient;
|
this.realClient = realClient;
|
||||||
this.definition = definition;
|
this.definition = definition;
|
||||||
this.client = {
|
this.client = {
|
||||||
...this.createBasePluginClient(),
|
...this.createBasePluginClient(),
|
||||||
|
get appId() {
|
||||||
|
return realClient.id;
|
||||||
|
},
|
||||||
|
get appName() {
|
||||||
|
return realClient.query.app;
|
||||||
|
},
|
||||||
onConnect: (cb) => {
|
onConnect: (cb) => {
|
||||||
this.events.on('connect', cb);
|
this.events.on('connect', cb);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -12,8 +12,11 @@ import {EventEmitter} from 'events';
|
|||||||
import {Atom} from '../state/atom';
|
import {Atom} from '../state/atom';
|
||||||
import {MenuEntry, NormalizedMenuEntry, normalizeMenuEntry} from './MenuEntry';
|
import {MenuEntry, NormalizedMenuEntry, normalizeMenuEntry} from './MenuEntry';
|
||||||
import {FlipperLib} from './FlipperLib';
|
import {FlipperLib} from './FlipperLib';
|
||||||
|
import {Device, RealFlipperDevice} from './DevicePlugin';
|
||||||
|
|
||||||
export interface BasePluginClient {
|
export interface BasePluginClient {
|
||||||
|
readonly device: Device;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the onDestroy event is fired whenever a device is unloaded from Flipper, or a plugin is disabled.
|
* the onDestroy event is fired whenever a device is unloaded from Flipper, or a plugin is disabled.
|
||||||
*/
|
*/
|
||||||
@@ -65,6 +68,8 @@ export abstract class BasePluginInstance {
|
|||||||
definition: SandyPluginDefinition;
|
definition: SandyPluginDefinition;
|
||||||
/** the plugin instance api as used inside components and such */
|
/** the plugin instance api as used inside components and such */
|
||||||
instanceApi: any;
|
instanceApi: any;
|
||||||
|
/** the device owning this plugin */
|
||||||
|
device: Device;
|
||||||
|
|
||||||
activated = false;
|
activated = false;
|
||||||
destroyed = false;
|
destroyed = false;
|
||||||
@@ -82,11 +87,29 @@ export abstract class BasePluginInstance {
|
|||||||
constructor(
|
constructor(
|
||||||
flipperLib: FlipperLib,
|
flipperLib: FlipperLib,
|
||||||
definition: SandyPluginDefinition,
|
definition: SandyPluginDefinition,
|
||||||
|
realDevice: RealFlipperDevice,
|
||||||
initialStates?: Record<string, any>,
|
initialStates?: Record<string, any>,
|
||||||
) {
|
) {
|
||||||
this.flipperLib = flipperLib;
|
this.flipperLib = flipperLib;
|
||||||
this.definition = definition;
|
this.definition = definition;
|
||||||
this.initialStates = initialStates;
|
this.initialStates = initialStates;
|
||||||
|
if (!realDevice) {
|
||||||
|
throw new Error('Illegal State: Device has not yet been loaded');
|
||||||
|
}
|
||||||
|
this.device = {
|
||||||
|
realDevice, // TODO: temporarily, clean up T70688226
|
||||||
|
// N.B. we model OS as string, not as enum, to make custom device types possible in the future
|
||||||
|
os: realDevice.os,
|
||||||
|
isArchived: realDevice.isArchived,
|
||||||
|
deviceType: realDevice.deviceType,
|
||||||
|
|
||||||
|
onLogEntry(cb) {
|
||||||
|
const handle = realDevice.addLogListener(cb);
|
||||||
|
return () => {
|
||||||
|
realDevice.removeLogListener(handle);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected initializePlugin(factory: () => any) {
|
protected initializePlugin(factory: () => any) {
|
||||||
@@ -102,6 +125,7 @@ export abstract class BasePluginInstance {
|
|||||||
|
|
||||||
protected createBasePluginClient(): BasePluginClient {
|
protected createBasePluginClient(): BasePluginClient {
|
||||||
return {
|
return {
|
||||||
|
device: this.device,
|
||||||
onActivate: (cb) => {
|
onActivate: (cb) => {
|
||||||
this.events.on('activate', cb);
|
this.events.on('activate', cb);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -180,7 +180,18 @@ export function startPlugin<Module extends FlipperPluginModule<any>>(
|
|||||||
|
|
||||||
const sendStub = jest.fn();
|
const sendStub = jest.fn();
|
||||||
const flipperUtils = createMockFlipperLib();
|
const flipperUtils = createMockFlipperLib();
|
||||||
|
const testDevice = createMockDevice(options);
|
||||||
|
const appName = 'TestApplication';
|
||||||
|
const deviceName = 'TestDevice';
|
||||||
const fakeFlipperClient: RealFlipperClient = {
|
const fakeFlipperClient: RealFlipperClient = {
|
||||||
|
id: `${appName}#${testDevice.os}#${deviceName}#${testDevice.serial}`,
|
||||||
|
query: {
|
||||||
|
app: appName,
|
||||||
|
device: deviceName,
|
||||||
|
device_id: testDevice.serial,
|
||||||
|
os: testDevice.serial,
|
||||||
|
},
|
||||||
|
deviceSync: testDevice,
|
||||||
isBackgroundPlugin(_pluginId: string) {
|
isBackgroundPlugin(_pluginId: string) {
|
||||||
return !!options?.isBackgroundPlugin;
|
return !!options?.isBackgroundPlugin;
|
||||||
},
|
},
|
||||||
@@ -381,6 +392,7 @@ function createMockDevice(options?: StartPluginOptions): RealFlipperDevice {
|
|||||||
return {
|
return {
|
||||||
os: 'Android',
|
os: 'Android',
|
||||||
deviceType: 'emulator',
|
deviceType: 'emulator',
|
||||||
|
serial: 'serial-000',
|
||||||
isArchived: !!options?.isArchived,
|
isArchived: !!options?.isArchived,
|
||||||
addLogListener(cb) {
|
addLogListener(cb) {
|
||||||
logListeners.push(cb);
|
logListeners.push(cb);
|
||||||
|
|||||||
@@ -36,6 +36,20 @@ export function plugin(client: PluginClient<Events, Methods>) {
|
|||||||
|
|
||||||
The `PluginClient` received by the `plugin` exposes the following members:
|
The `PluginClient` received by the `plugin` exposes the following members:
|
||||||
|
|
||||||
|
### Properties
|
||||||
|
|
||||||
|
#### `device`
|
||||||
|
|
||||||
|
Returns the [`Device`](#device) this plugin is connected to.
|
||||||
|
|
||||||
|
#### `appName`
|
||||||
|
|
||||||
|
The name of the application, for example 'Facebook', 'Instagram' or 'Slack'.
|
||||||
|
|
||||||
|
#### `appId`
|
||||||
|
|
||||||
|
A string that uniquely identifies the current application, is based on a combination of the application name and device serial on which the application is running.
|
||||||
|
|
||||||
### Events listeners
|
### Events listeners
|
||||||
|
|
||||||
#### `onMessage`
|
#### `onMessage`
|
||||||
|
|||||||
Reference in New Issue
Block a user