Implement sending messages from a server add-on
Reviewed By: mweststrate Differential Revision: D34074383 fbshipit-source-id: de85e7a22dc9bb780163fc5b522708e8bc976df3
This commit is contained in:
committed by
Facebook GitHub Bot
parent
842b2c810a
commit
db976d5113
@@ -125,9 +125,7 @@ export type FlipperServerEvents = {
|
|||||||
id: string;
|
id: string;
|
||||||
message: string;
|
message: string;
|
||||||
};
|
};
|
||||||
'plugins-server-add-on-message': {
|
'plugins-server-add-on-message': ExecuteMessage;
|
||||||
payload: ExecuteMessage;
|
|
||||||
};
|
|
||||||
'download-file-update': DownloadFileUpdate;
|
'download-file-update': DownloadFileUpdate;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ export class FlipperServerImpl implements FlipperServer {
|
|||||||
// given flipper-dump, it might make more sense to have the plugin command
|
// given flipper-dump, it might make more sense to have the plugin command
|
||||||
// handling (like download, install, etc) moved to flipper-server & app,
|
// handling (like download, install, etc) moved to flipper-server & app,
|
||||||
// but let's keep things simple for now
|
// but let's keep things simple for now
|
||||||
this.pluginManager = new PluginManager();
|
this.pluginManager = new PluginManager(this);
|
||||||
|
|
||||||
server.addListener('error', (err) => {
|
server.addListener('error', (err) => {
|
||||||
this.emit('server-error', err);
|
this.emit('server-error', err);
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import {
|
|||||||
installPluginFromNpm,
|
installPluginFromNpm,
|
||||||
} from 'flipper-plugin-lib';
|
} from 'flipper-plugin-lib';
|
||||||
import {ServerAddOn} from './ServerAddOn';
|
import {ServerAddOn} from './ServerAddOn';
|
||||||
|
import {FlipperServerForServerAddOn} from './ServerAddOnDesktopToModuleConnection';
|
||||||
|
|
||||||
const maxInstalledPluginVersionsToKeep = 2;
|
const maxInstalledPluginVersionsToKeep = 2;
|
||||||
|
|
||||||
@@ -50,6 +51,8 @@ const isExecuteMessage = (message: object): message is ExecuteMessage =>
|
|||||||
export class PluginManager {
|
export class PluginManager {
|
||||||
private readonly serverAddOns = new Map<string, ServerAddOn>();
|
private readonly serverAddOns = new Map<string, ServerAddOn>();
|
||||||
|
|
||||||
|
constructor(private readonly flipperServer: FlipperServerForServerAddOn) {}
|
||||||
|
|
||||||
async start() {
|
async start() {
|
||||||
// This needn't happen immediately and is (light) I/O work.
|
// This needn't happen immediately and is (light) I/O work.
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -183,8 +186,11 @@ export class PluginManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newServerAddOn = await ServerAddOn.start(pluginName, owner, () =>
|
const newServerAddOn = await ServerAddOn.start(
|
||||||
this.serverAddOns.delete(pluginName),
|
pluginName,
|
||||||
|
owner,
|
||||||
|
() => this.serverAddOns.delete(pluginName),
|
||||||
|
this.flipperServer,
|
||||||
);
|
);
|
||||||
this.serverAddOns.set(pluginName, newServerAddOn);
|
this.serverAddOns.set(pluginName, newServerAddOn);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,13 +9,17 @@
|
|||||||
|
|
||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
import {assertNotNull} from '../comms/Utilities';
|
import {assertNotNull} from '../comms/Utilities';
|
||||||
import {ServerAddOnDesktopToModuleConnection} from './ServerAddOnDesktopToModuleConnection';
|
import {
|
||||||
|
ServerAddOnDesktopToModuleConnection,
|
||||||
|
FlipperServerForServerAddOn,
|
||||||
|
} from './ServerAddOnDesktopToModuleConnection';
|
||||||
import {ServerAddOnModuleToDesktopConnection} from './ServerAddOnModuleToDesktopConnection';
|
import {ServerAddOnModuleToDesktopConnection} from './ServerAddOnModuleToDesktopConnection';
|
||||||
|
|
||||||
type ServerAddOnCleanup = () => Promise<void>;
|
type ServerAddOnCleanup = () => Promise<void>;
|
||||||
interface ServerAddOnModule {
|
interface ServerAddOnModule {
|
||||||
serverAddOn?: (
|
serverAddOn?: (
|
||||||
connection: ServerAddOnModuleToDesktopConnection,
|
connection: ServerAddOnModuleToDesktopConnection,
|
||||||
|
{flipperServer}: {flipperServer: FlipperServerForServerAddOn},
|
||||||
) => Promise<ServerAddOnCleanup>;
|
) => Promise<ServerAddOnCleanup>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,13 +38,14 @@ export class ServerAddOn {
|
|||||||
public readonly connection: ServerAddOnDesktopToModuleConnection,
|
public readonly connection: ServerAddOnDesktopToModuleConnection,
|
||||||
initialOwner: string,
|
initialOwner: string,
|
||||||
) {
|
) {
|
||||||
this.owners = new Set(initialOwner);
|
this.owners = new Set([initialOwner]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async start(
|
static async start(
|
||||||
pluginName: string,
|
pluginName: string,
|
||||||
initialOwner: string,
|
initialOwner: string,
|
||||||
onStop: () => void,
|
onStop: () => void,
|
||||||
|
flipperServer: FlipperServerForServerAddOn,
|
||||||
): Promise<ServerAddOn> {
|
): Promise<ServerAddOn> {
|
||||||
console.info('ServerAddOn.start', pluginName);
|
console.info('ServerAddOn.start', pluginName);
|
||||||
|
|
||||||
@@ -54,7 +59,9 @@ export class ServerAddOn {
|
|||||||
const serverAddOnModuleToDesktopConnection =
|
const serverAddOnModuleToDesktopConnection =
|
||||||
new ServerAddOnModuleToDesktopConnection();
|
new ServerAddOnModuleToDesktopConnection();
|
||||||
|
|
||||||
const cleanup = await serverAddOn(serverAddOnModuleToDesktopConnection);
|
const cleanup = await serverAddOn(serverAddOnModuleToDesktopConnection, {
|
||||||
|
flipperServer,
|
||||||
|
});
|
||||||
assert(
|
assert(
|
||||||
typeof cleanup === 'function',
|
typeof cleanup === 'function',
|
||||||
`ServerAddOn ${pluginName} must return a clean up function, instead it returned ${typeof cleanup}.`,
|
`ServerAddOn ${pluginName} must return a clean up function, instead it returned ${typeof cleanup}.`,
|
||||||
@@ -65,12 +72,15 @@ export class ServerAddOn {
|
|||||||
await cleanup();
|
await cleanup();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const desktopToModuleConnection = new ServerAddOnDesktopToModuleConnection(
|
||||||
|
serverAddOnModuleToDesktopConnection,
|
||||||
|
flipperServer,
|
||||||
|
);
|
||||||
|
|
||||||
return new ServerAddOn(
|
return new ServerAddOn(
|
||||||
pluginName,
|
pluginName,
|
||||||
onStopCombined,
|
onStopCombined,
|
||||||
new ServerAddOnDesktopToModuleConnection(
|
desktopToModuleConnection,
|
||||||
serverAddOnModuleToDesktopConnection,
|
|
||||||
),
|
|
||||||
initialOwner,
|
initialOwner,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,13 +8,37 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
import {ClientResponseType, ExecuteMessage} from 'flipper-common';
|
import {
|
||||||
import {ServerAddOnModuleToDesktopConnection} from './ServerAddOnModuleToDesktopConnection';
|
ClientResponseType,
|
||||||
|
ExecuteMessage,
|
||||||
|
FlipperServer,
|
||||||
|
FlipperServerEvents,
|
||||||
|
} from 'flipper-common';
|
||||||
|
import {ServerDevice} from '../devices/ServerDevice';
|
||||||
|
import {
|
||||||
|
ServerAddOnModuleToDesktopConnection,
|
||||||
|
ServerAddOnModuleToDesktopConnectionEvents,
|
||||||
|
} from './ServerAddOnModuleToDesktopConnection';
|
||||||
|
|
||||||
|
export interface FlipperServerForServerAddOn extends FlipperServer {
|
||||||
|
emit(
|
||||||
|
event: 'plugins-server-add-on-message',
|
||||||
|
payload: FlipperServerEvents['plugins-server-add-on-message'],
|
||||||
|
): void;
|
||||||
|
registerDevice(device: ServerDevice): void;
|
||||||
|
unregisterDevice(serial: string): void;
|
||||||
|
getDevice(serial: string): ServerDevice;
|
||||||
|
getDeviceSerials(): string[];
|
||||||
|
getDevices(): ServerDevice[];
|
||||||
|
}
|
||||||
|
|
||||||
export class ServerAddOnDesktopToModuleConnection {
|
export class ServerAddOnDesktopToModuleConnection {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly moduleToDesktopConnection: ServerAddOnModuleToDesktopConnection,
|
private readonly moduleToDesktopConnection: ServerAddOnModuleToDesktopConnection,
|
||||||
) {}
|
private readonly flipperServer: FlipperServerForServerAddOn,
|
||||||
|
) {
|
||||||
|
this.subscribeToMessagesFromServerAddOn();
|
||||||
|
}
|
||||||
|
|
||||||
async sendExpectResponse({
|
async sendExpectResponse({
|
||||||
method,
|
method,
|
||||||
@@ -34,4 +58,15 @@ export class ServerAddOnDesktopToModuleConnection {
|
|||||||
length,
|
length,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private subscribeToMessagesFromServerAddOn() {
|
||||||
|
const event = 'message';
|
||||||
|
const onMessage = (
|
||||||
|
message: ServerAddOnModuleToDesktopConnectionEvents[typeof event],
|
||||||
|
) => {
|
||||||
|
this.flipperServer.emit('plugins-server-add-on-message', message);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.moduleToDesktopConnection.on(event, onMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ResponseMessage, ClientErrorType} from 'flipper-common';
|
import EventEmitter from 'events';
|
||||||
|
import {ResponseMessage, ClientErrorType, ExecuteMessage} from 'flipper-common';
|
||||||
import {safeJSONStringify} from '../utils/safeJSONStringify';
|
import {safeJSONStringify} from '../utils/safeJSONStringify';
|
||||||
|
|
||||||
// TODO: Share with js-flipper? Is it worth it?
|
// TODO: Share with js-flipper? Is it worth it?
|
||||||
@@ -24,11 +25,24 @@ type FlipperPluginReceiver = (
|
|||||||
data: any,
|
data: any,
|
||||||
) => FlipperPluginReceiverRes | Promise<FlipperPluginReceiverRes>;
|
) => FlipperPluginReceiverRes | Promise<FlipperPluginReceiverRes>;
|
||||||
|
|
||||||
export class ServerAddOnModuleToDesktopConnection {
|
export type ServerAddOnModuleToDesktopConnectionEvents = {
|
||||||
|
message: ExecuteMessage;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class ServerAddOnModuleToDesktopConnection extends EventEmitter {
|
||||||
private subscriptions: Map<string, FlipperPluginReceiver> = new Map();
|
private subscriptions: Map<string, FlipperPluginReceiver> = new Map();
|
||||||
|
|
||||||
send() {
|
send(method: string, params: unknown) {
|
||||||
// TODO: Implement me
|
const event = 'message';
|
||||||
|
const message: ServerAddOnModuleToDesktopConnectionEvents[typeof event] = {
|
||||||
|
method: 'execute',
|
||||||
|
params: {
|
||||||
|
method,
|
||||||
|
params,
|
||||||
|
api: '', // TODO: Consider using here pluginId and validate it
|
||||||
|
},
|
||||||
|
};
|
||||||
|
this.emit('message', message);
|
||||||
}
|
}
|
||||||
|
|
||||||
receive(method: string, receiver: FlipperPluginReceiver) {
|
receive(method: string, receiver: FlipperPluginReceiver) {
|
||||||
|
|||||||
Reference in New Issue
Block a user