Implement receiving messages from add-on on the client
Reviewed By: mweststrate Differential Revision: D34249101 fbshipit-source-id: 07297b84ed8640e3b41599726ba613b6b4e2b62e
This commit is contained in:
committed by
Facebook GitHub Bot
parent
4067f5bd88
commit
b4b9c0ab28
@@ -21,6 +21,17 @@ export interface ServerAddOnControls {
|
|||||||
method: string,
|
method: string,
|
||||||
params?: unknown,
|
params?: unknown,
|
||||||
) => Promise<object | string | number | boolean | null>;
|
) => Promise<object | string | number | boolean | null>;
|
||||||
|
receiveMessage: (
|
||||||
|
pluginName: string,
|
||||||
|
method: string,
|
||||||
|
receiver: (data: unknown) => void,
|
||||||
|
) => void;
|
||||||
|
receiveAnyMessage: (
|
||||||
|
pluginName: string,
|
||||||
|
receiver: (method: string, data: unknown) => void,
|
||||||
|
) => void;
|
||||||
|
unsubscribePlugin: (pluginName: string) => void;
|
||||||
|
unsubscribe: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Share with js-flipper? Is it worth it?
|
// TODO: Share with js-flipper? Is it worth it?
|
||||||
|
|||||||
@@ -386,11 +386,18 @@ export abstract class BasePluginInstance {
|
|||||||
method as string,
|
method as string,
|
||||||
params,
|
params,
|
||||||
),
|
),
|
||||||
onServerAddOnMessage: (_event, _cb) => {
|
onServerAddOnMessage: (event, cb) => {
|
||||||
// TODO: Implement me
|
this.serverAddOnControls.receiveMessage(
|
||||||
|
this.definition.packageName,
|
||||||
|
event as string,
|
||||||
|
batched(cb),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
onServerAddOnUnhandledMessage: (_cb) => {
|
onServerAddOnUnhandledMessage: (cb) => {
|
||||||
// TODO: Implement me
|
this.serverAddOnControls.receiveAnyMessage(
|
||||||
|
this.definition.packageName,
|
||||||
|
batched(cb),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -436,6 +443,7 @@ export abstract class BasePluginInstance {
|
|||||||
this.crashListeners.splice(0).forEach((handle) => {
|
this.crashListeners.splice(0).forEach((handle) => {
|
||||||
this.device.removeCrashListener(handle);
|
this.device.removeCrashListener(handle);
|
||||||
});
|
});
|
||||||
|
this.serverAddOnControls.unsubscribePlugin(this.definition.packageName);
|
||||||
this.events.emit('destroy');
|
this.events.emit('destroy');
|
||||||
this.destroyed = true;
|
this.destroyed = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -648,5 +648,9 @@ function createServerAddOnControlsMock(): ServerAddOnControls {
|
|||||||
start: createStubFunction(),
|
start: createStubFunction(),
|
||||||
stop: createStubFunction(),
|
stop: createStubFunction(),
|
||||||
sendMessage: createStubFunction(),
|
sendMessage: createStubFunction(),
|
||||||
|
receiveMessage: createStubFunction(),
|
||||||
|
receiveAnyMessage: createStubFunction(),
|
||||||
|
unsubscribePlugin: createStubFunction(),
|
||||||
|
unsubscribe: createStubFunction(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ export default class Client extends EventEmitter {
|
|||||||
> = {};
|
> = {};
|
||||||
sandyPluginStates = new Map<string /*pluginID*/, _SandyPluginInstance>();
|
sandyPluginStates = new Map<string /*pluginID*/, _SandyPluginInstance>();
|
||||||
private readonly serverAddOnControls: ServerAddOnControls;
|
private readonly serverAddOnControls: ServerAddOnControls;
|
||||||
private readonly flipperServer: Pick<FlipperServer, 'exec'>;
|
private readonly flipperServer: FlipperServer;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
id: string,
|
id: string,
|
||||||
@@ -136,7 +136,7 @@ export default class Client extends EventEmitter {
|
|||||||
store: Store,
|
store: Store,
|
||||||
plugins: Plugins | null | undefined,
|
plugins: Plugins | null | undefined,
|
||||||
device: BaseDevice,
|
device: BaseDevice,
|
||||||
flipperServer: Pick<FlipperServer, 'exec'>,
|
flipperServer: FlipperServer,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.connected.set(!!conn);
|
this.connected.set(!!conn);
|
||||||
@@ -281,6 +281,7 @@ export default class Client extends EventEmitter {
|
|||||||
destroy() {
|
destroy() {
|
||||||
this.disconnect();
|
this.disconnect();
|
||||||
this.plugins.forEach((pluginId) => this.stopPluginIfNeeded(pluginId, true));
|
this.plugins.forEach((pluginId) => this.stopPluginIfNeeded(pluginId, true));
|
||||||
|
this.serverAddOnControls.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
// gets a plugin by pluginId
|
// gets a plugin by pluginId
|
||||||
|
|||||||
@@ -226,13 +226,12 @@ test('new clients replace old ones', async () => {
|
|||||||
|
|
||||||
const client2 = await createClient(device, 'AnotherApp', client.query, true);
|
const client2 = await createClient(device, 'AnotherApp', client.query, true);
|
||||||
await handleClientConnected(
|
await handleClientConnected(
|
||||||
{
|
TestUtils.createFlipperServerMock({
|
||||||
exec: (async () => {
|
'client-request-response': async () => ({
|
||||||
return {
|
success: [],
|
||||||
success: {}, // {plugins: []},
|
length: 0,
|
||||||
};
|
}),
|
||||||
}) as any,
|
}),
|
||||||
},
|
|
||||||
store,
|
store,
|
||||||
logger,
|
logger,
|
||||||
client2,
|
client2,
|
||||||
|
|||||||
@@ -390,5 +390,6 @@ export default class BaseDevice implements Device {
|
|||||||
instance.destroy();
|
instance.destroy();
|
||||||
});
|
});
|
||||||
this.sandyPluginStates.clear();
|
this.sandyPluginStates.clear();
|
||||||
|
this.serverAddOnControls.unsubscribe();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -240,7 +240,7 @@ function handleDeviceConnected(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function handleClientConnected(
|
export async function handleClientConnected(
|
||||||
server: Pick<FlipperServer, 'exec'>,
|
server: FlipperServer,
|
||||||
store: Store,
|
store: Store,
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
{id, query}: ClientDescription,
|
{id, query}: ClientDescription,
|
||||||
|
|||||||
@@ -8,35 +8,87 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
ExecuteMessage,
|
||||||
FlipperServer,
|
FlipperServer,
|
||||||
ServerAddOnControls,
|
ServerAddOnControls,
|
||||||
deserializeRemoteError,
|
deserializeRemoteError,
|
||||||
} from 'flipper-common';
|
} from 'flipper-common';
|
||||||
|
|
||||||
export const createServerAddOnControls = (
|
type PluginName = string;
|
||||||
flipperServer: Pick<FlipperServer, 'exec'>,
|
type Method = string;
|
||||||
): ServerAddOnControls => ({
|
|
||||||
start: (pluginName, owner) =>
|
|
||||||
flipperServer.exec('plugins-server-add-on-start', pluginName, owner),
|
|
||||||
stop: (pluginName, owner) =>
|
|
||||||
flipperServer.exec('plugins-server-add-on-stop', pluginName, owner),
|
|
||||||
sendMessage: async (pluginName, method, params) => {
|
|
||||||
const res = await flipperServer.exec(
|
|
||||||
'plugins-server-add-on-request-response',
|
|
||||||
{
|
|
||||||
method: 'execute',
|
|
||||||
params: {
|
|
||||||
method,
|
|
||||||
api: pluginName,
|
|
||||||
params,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (res.error) {
|
export const createServerAddOnControls = (
|
||||||
throw deserializeRemoteError(res.error);
|
flipperServer: FlipperServer,
|
||||||
|
): ServerAddOnControls => {
|
||||||
|
const methodHandlers = new Map<
|
||||||
|
PluginName,
|
||||||
|
Map<Method, (data: unknown) => void>
|
||||||
|
>();
|
||||||
|
const catchAllHandlers = new Map<
|
||||||
|
PluginName,
|
||||||
|
(method: string, data: unknown) => void
|
||||||
|
>();
|
||||||
|
|
||||||
|
let subscribed = false;
|
||||||
|
const subscriptionCb = ({params}: ExecuteMessage) => {
|
||||||
|
const pluginName = params.api;
|
||||||
|
|
||||||
|
const methodHandler = methodHandlers.get(pluginName)?.get(params.method);
|
||||||
|
|
||||||
|
if (methodHandler) {
|
||||||
|
methodHandler(params.params);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.success;
|
const catchAllHandler = catchAllHandlers.get(pluginName);
|
||||||
},
|
catchAllHandler?.(params.method, params.params);
|
||||||
});
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
start: (pluginName, owner) =>
|
||||||
|
flipperServer.exec('plugins-server-add-on-start', pluginName, owner),
|
||||||
|
stop: (pluginName, owner) =>
|
||||||
|
flipperServer.exec('plugins-server-add-on-stop', pluginName, owner),
|
||||||
|
sendMessage: async (pluginName, method, params) => {
|
||||||
|
const res = await flipperServer.exec(
|
||||||
|
'plugins-server-add-on-request-response',
|
||||||
|
{
|
||||||
|
method: 'execute',
|
||||||
|
params: {
|
||||||
|
method,
|
||||||
|
api: pluginName,
|
||||||
|
params,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res.error) {
|
||||||
|
throw deserializeRemoteError(res.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.success;
|
||||||
|
},
|
||||||
|
receiveMessage: (pluginName, method, receiver) => {
|
||||||
|
if (!methodHandlers.has(pluginName)) {
|
||||||
|
methodHandlers.set(pluginName, new Map());
|
||||||
|
}
|
||||||
|
methodHandlers.get(pluginName)!.set(method, receiver);
|
||||||
|
|
||||||
|
// Subscribe client/device to messages from flipper server only when the first plugin subscribes to them
|
||||||
|
if (!subscribed) {
|
||||||
|
subscribed = true;
|
||||||
|
flipperServer.on('plugins-server-add-on-message', subscriptionCb);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
receiveAnyMessage: (pluginName, receiver) => {
|
||||||
|
catchAllHandlers.set(pluginName, receiver);
|
||||||
|
},
|
||||||
|
unsubscribePlugin: (pluginName) => {
|
||||||
|
methodHandlers.delete(pluginName);
|
||||||
|
catchAllHandlers.delete(pluginName);
|
||||||
|
},
|
||||||
|
unsubscribe: () => {
|
||||||
|
flipperServer.off('plugins-server-add-on-message', subscriptionCb);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user