diff --git a/packages/controllers/src/index.ts b/packages/controllers/src/index.ts index 5d9be9cce3..4a1f01cd2d 100644 --- a/packages/controllers/src/index.ts +++ b/packages/controllers/src/index.ts @@ -1,3 +1,3 @@ -export * from './workers/WorkerController'; +export * from './services/WebWorkerExecutionEnvironmentService'; export * from './plugins/PluginController'; export * from './resource/ExternalResourceController'; diff --git a/packages/controllers/src/plugins/PluginController.test.ts b/packages/controllers/src/plugins/PluginController.test.ts index ad7a1102a2..34c01512ba 100644 --- a/packages/controllers/src/plugins/PluginController.test.ts +++ b/packages/controllers/src/plugins/PluginController.test.ts @@ -1,6 +1,7 @@ import fs from 'fs'; import { ControllerMessenger } from '@metamask/controllers/dist/ControllerMessenger'; -import { WorkerController } from '../workers/WorkerController'; +import { WebWorkerExecutionEnvironmentService } from '../services/WebWorkerExecutionEnvironmentService'; +import { ExecutionEnvironmentService } from '../services/ExecutionEnvironmentService'; import { PluginController } from './PluginController'; const workerCode = fs.readFileSync( @@ -10,20 +11,25 @@ const workerCode = fs.readFileSync( describe('PluginController Controller', () => { it('can create a worker and plugin controller', async () => { - const workerController = new WorkerController({ - setupWorkerConnection: jest.fn(), - workerUrl: new URL(URL.createObjectURL(new Blob([workerCode]))), - }); + const workerExecutionEnvironment = new WebWorkerExecutionEnvironmentService( + { + setupWorkerConnection: jest.fn(), + workerUrl: new URL(URL.createObjectURL(new Blob([workerCode]))), + }, + ); const pluginController = new PluginController({ - command: workerController.command.bind(workerController), - createPluginWorker: workerController.createPluginWorker.bind( - workerController, + terminateAllPlugins: workerExecutionEnvironment.terminateAllPlugins.bind( + workerExecutionEnvironment, + ), + terminatePlugin: workerExecutionEnvironment.terminatePlugin.bind( + workerExecutionEnvironment, + ), + executePlugin: workerExecutionEnvironment.executePlugin.bind( + workerExecutionEnvironment, ), - terminateAll: workerController.terminateAll.bind(workerController), - terminateWorkerOf: workerController.terminateWorkerOf.bind( - workerController, + getRpcMessageHandler: workerExecutionEnvironment.getRpcMessageHandler.bind( + workerExecutionEnvironment, ), - startPlugin: workerController.startPlugin.bind(workerController), removeAllPermissionsFor: jest.fn(), getPermissions: jest.fn(), hasPermission: jest.fn(), @@ -41,21 +47,26 @@ describe('PluginController Controller', () => { expect(pluginController).toBeDefined(); }); - it('can add a plugin and use its JSON-RPC api', async () => { - const workerController = new WorkerController({ - setupWorkerConnection: jest.fn(), - workerUrl: new URL(URL.createObjectURL(new Blob([workerCode]))), - }); + it('can add a plugin and use its JSON-RPC api with a WebWorkerExecutionEnvironmentService', async () => { + const webWorkerExecutionEnvironment = new WebWorkerExecutionEnvironmentService( + { + setupWorkerConnection: jest.fn(), + workerUrl: new URL(URL.createObjectURL(new Blob([workerCode]))), + }, + ); const pluginController = new PluginController({ - command: workerController.command.bind(workerController), - createPluginWorker: workerController.createPluginWorker.bind( - workerController, + terminateAllPlugins: webWorkerExecutionEnvironment.terminateAllPlugins.bind( + webWorkerExecutionEnvironment, + ), + terminatePlugin: webWorkerExecutionEnvironment.terminatePlugin.bind( + webWorkerExecutionEnvironment, + ), + executePlugin: webWorkerExecutionEnvironment.executePlugin.bind( + webWorkerExecutionEnvironment, ), - terminateAll: workerController.terminateAll.bind(workerController), - terminateWorkerOf: workerController.terminateWorkerOf.bind( - workerController, + getRpcMessageHandler: webWorkerExecutionEnvironment.getRpcMessageHandler.bind( + webWorkerExecutionEnvironment, ), - startPlugin: workerController.startPlugin.bind(workerController), removeAllPermissionsFor: jest.fn(), getPermissions: jest.fn(), hasPermission: jest.fn(), @@ -87,7 +98,89 @@ describe('PluginController Controller', () => { }, }); await pluginController.startPlugin(plugin.name); - const handle = pluginController.getRpcMessageHandler(plugin.name); + const handle = await pluginController.getRpcMessageHandler(plugin.name); + if (!handle) { + throw Error('rpc handler not found'); + } + const result = await handle('foo.com', { + jsonrpc: '2.0', + method: 'test', + params: {}, + id: 1, + }); + expect(result).toEqual('test1'); + }); + + it('can add a plugin and use its JSON-RPC api with a stub execution env service', async () => { + class ExecutionEnvironmentStub implements ExecutionEnvironmentService { + async terminateAllPlugins() { + // empty stub + } + + async getRpcMessageHandler() { + return (_: any, request: Record) => { + return new Promise((resolve) => { + const results = `${request.method}${request.id}`; + resolve(results); + }); + }; + } + + async executePlugin() { + return 'some-unique-id'; + } + + async terminatePlugin() { + // empty stub + } + } + + const executionEnvironmentStub = new ExecutionEnvironmentStub(); + + const pluginController = new PluginController({ + terminateAllPlugins: executionEnvironmentStub.terminateAllPlugins.bind( + executionEnvironmentStub, + ), + terminatePlugin: executionEnvironmentStub.terminatePlugin.bind( + executionEnvironmentStub, + ), + executePlugin: executionEnvironmentStub.executePlugin.bind( + executionEnvironmentStub, + ), + getRpcMessageHandler: executionEnvironmentStub.getRpcMessageHandler.bind( + executionEnvironmentStub, + ), + removeAllPermissionsFor: jest.fn(), + getPermissions: jest.fn(), + hasPermission: jest.fn(), + requestPermissions: jest.fn(), + closeAllConnections: jest.fn(), + messenger: new ControllerMessenger().getRestricted({ + name: 'PluginController', + }), + state: { + inlinePluginIsRunning: false, + pluginStates: {}, + plugins: {}, + }, + }); + const plugin = await pluginController.add({ + name: 'TestPlugin', + sourceCode: ` + wallet.registerRpcMessageHandler(async (origin, request) => { + const {method, params, id} = request; + return method + id; + }); + `, + manifest: { + web3Wallet: { + initialPermissions: {}, + }, + version: '0.0.0-development', + }, + }); + await pluginController.startPlugin(plugin.name); + const handle = await pluginController.getRpcMessageHandler(plugin.name); if (!handle) { throw Error('rpc handler not found'); } diff --git a/packages/controllers/src/plugins/PluginController.ts b/packages/controllers/src/plugins/PluginController.ts index 16ca8f2ecb..c73d7ce4ee 100644 --- a/packages/controllers/src/plugins/PluginController.ts +++ b/packages/controllers/src/plugins/PluginController.ts @@ -1,13 +1,17 @@ import { ethErrors, serializeError } from 'eth-rpc-errors'; import { IOcapLdCapability } from 'rpc-cap/dist/src/@types/ocap-ld'; -import { nanoid } from 'nanoid'; import { BaseControllerV2 as BaseController, RestrictedControllerMessenger, } from '@metamask/controllers'; -import { Json, JsonRpcRequest } from 'json-rpc-engine'; +import { Json } from 'json-rpc-engine'; import { PluginData } from '@mm-snap/types'; -import { PluginWorkerMetadata } from '../workers/WorkerController'; +import { + GetRpcMessageHandler, + ExecutePlugin, + TerminateAll, + TerminatePlugin, +} from '../services/ExecutionEnvironmentService'; import { INLINE_PLUGINS } from './inlinePlugins'; export const PLUGIN_PREFIX = 'wallet_plugin_'; @@ -34,12 +38,6 @@ export interface Plugin extends SerializablePlugin { sourceCode: string; } -// The plugin is the callee -export type PluginRpcHook = ( - origin: string, - request: Record, -) => Promise; - export type ProcessPluginReturnType = | SerializablePlugin | { error: ReturnType }; @@ -59,18 +57,6 @@ type HasPermissionFunction = ( permissionName: string, ) => boolean; type GetPermissionsFunction = (domain: string) => IOcapLdCapability[]; -type TerminateWorkerOf = (pluginName: string) => void; -type Command = ( - workerId: string, - message: JsonRpcRequest, -) => Promise; -type TerminateAll = () => void; -type CreatePluginWorker = (metadate: PluginWorkerMetadata) => Promise; -type StartPlugin = ( - workerId: string, - pluginData: PluginData, -) => Promise; - type PluginId = string; type StoredPlugins = Record; @@ -90,11 +76,10 @@ interface PluginControllerArgs { requestPermissions: RequestPermissionsFunction; getPermissions: GetPermissionsFunction; hasPermission: HasPermissionFunction; - terminateWorkerOf: TerminateWorkerOf; - command: Command; - terminateAll: TerminateAll; - createPluginWorker: CreatePluginWorker; - startPlugin: StartPlugin; + terminatePlugin: TerminatePlugin; + terminateAllPlugins: TerminateAll; + executePlugin: ExecutePlugin; + getRpcMessageHandler: GetRpcMessageHandler; } interface AddPluginBase { @@ -139,8 +124,6 @@ export class PluginController extends BaseController< > { private _removeAllPermissionsFor: RemoveAllPermissionsFunction; - private _pluginRpcHooks: Map; - private _closeAllConnections: CloseAllConnectionsFunction; private _requestPermissions: RequestPermissionsFunction; @@ -149,15 +132,13 @@ export class PluginController extends BaseController< private _hasPermission: HasPermissionFunction; - private _terminateWorkerOf: TerminateWorkerOf; + private _terminatePlugin: TerminatePlugin; - private _command: Command; + private _terminateAllPlugins: TerminateAll; - private _terminateAll: TerminateAll; + private _executePlugin: ExecutePlugin; - private _createPluginWorker: CreatePluginWorker; - - private _startPlugin: StartPlugin; + private _getRpcMessageHandler: GetRpcMessageHandler; private _pluginsBeingAdded: Map>; @@ -166,12 +147,11 @@ export class PluginController extends BaseController< closeAllConnections, requestPermissions, getPermissions, - terminateWorkerOf, - terminateAll, + terminatePlugin, + terminateAllPlugins, hasPermission, - createPluginWorker, - startPlugin, - command, + executePlugin, + getRpcMessageHandler, messenger, state, }: PluginControllerArgs) { @@ -207,13 +187,11 @@ export class PluginController extends BaseController< this._getPermissions = getPermissions; this._hasPermission = hasPermission; - this._terminateWorkerOf = terminateWorkerOf; - this._terminateAll = terminateAll; - this._createPluginWorker = createPluginWorker; - this._startPlugin = startPlugin; - this._command = command; + this._terminatePlugin = terminatePlugin; + this._terminateAllPlugins = terminateAllPlugins; + this._executePlugin = executePlugin; + this._getRpcMessageHandler = getRpcMessageHandler; - this._pluginRpcHooks = new Map(); this._pluginsBeingAdded = new Map(); } @@ -236,7 +214,10 @@ export class PluginController extends BaseController< console.log(`Starting: ${pluginName}`); try { - await this._startPluginInWorker(pluginName, sourceCode); + await this._startPlugin({ + pluginName, + sourceCode, + }); } catch (err) { console.warn(`Failed to start "${pluginName}", deleting it.`, err); // Clean up failed plugins: @@ -262,7 +243,10 @@ export class PluginController extends BaseController< } try { - await this._startPluginInWorker(pluginName, plugin.sourceCode); + await this._startPlugin({ + pluginName, + sourceCode: plugin.sourceCode, + }); } catch (err) { console.error(`Failed to start "${pluginName}".`, err); } @@ -296,9 +280,8 @@ export class PluginController extends BaseController< * Should only be set to false if the plugin is about to be deleted. */ private _stopPlugin(pluginName: string, setNotRunning = true): void { - this._removePluginHooks(pluginName); this._closeAllConnections(pluginName); - this._terminateWorkerOf(pluginName); + this._terminatePlugin(pluginName); if (setNotRunning) { this._setPluginToNotRunning(pluginName); } @@ -391,12 +374,11 @@ export class PluginController extends BaseController< * handlers, event listeners, and permissions; tear down all plugin providers. */ clearState() { - this._pluginRpcHooks.clear(); const pluginNames = Object.keys(this.state.plugins); pluginNames.forEach((pluginName) => { this._closeAllConnections(pluginName); }); - this._terminateAll(); + this._terminateAllPlugins(); this._removeAllPermissionsFor(pluginNames); this.update((state: any) => { state.inlinePluginIsRunning = false; @@ -525,7 +507,10 @@ export class PluginController extends BaseController< await this.authorize(pluginName); - await this._startPluginInWorker(pluginName, sourceCode); + await this._startPlugin({ + pluginName, + sourceCode, + }); return this.getSerializable(pluginName) as SerializablePlugin; } catch (err) { @@ -565,6 +550,12 @@ export class PluginController extends BaseController< return this._pluginsBeingAdded.get(pluginName) as Promise; } + private async _startPlugin(pluginData: PluginData) { + const result = await this._executePlugin(pluginData); + this._setPluginToRunning(pluginData.pluginName); + return result; + } + /** * Internal method. See the "add" method. * @@ -691,7 +682,10 @@ export class PluginController extends BaseController< * Test method. */ runInlinePlugin(inlinePluginName: keyof typeof INLINE_PLUGINS = 'IDLE') { - this._startPluginInWorker('inlinePlugin', INLINE_PLUGINS[inlinePluginName]); + this._startPlugin({ + pluginName: 'inlinePlugin', + sourceCode: INLINE_PLUGINS[inlinePluginName], + }); this.update((state: any) => { state.inlinePluginIsRunning = true; }); @@ -707,49 +701,13 @@ export class PluginController extends BaseController< this.removePlugin('inlinePlugin'); } - private async _startPluginInWorker(pluginName: string, sourceCode: string) { - const workerId = await this._createPluginWorker({ - hostname: pluginName, - }); - this._createPluginHooks(pluginName, workerId); - await this._startPlugin(workerId, { - pluginName, - sourceCode, - }); - this._setPluginToRunning(pluginName); - } - /** * Gets the RPC message handler for the given plugin. * * @param pluginName - The name of the plugin whose message handler to get. */ - getRpcMessageHandler(pluginName: string): PluginRpcHook | undefined { - return this._pluginRpcHooks.get(pluginName); - } - - private _createPluginHooks(pluginName: string, workerId: string) { - const rpcHook = async ( - origin: string, - request: Record, - ) => { - return await this._command(workerId, { - id: nanoid(), - jsonrpc: '2.0', - method: 'pluginRpc', - params: { - origin, - request, - target: pluginName, - }, - }); - }; - - this._pluginRpcHooks.set(pluginName, rpcHook); - } - - private _removePluginHooks(pluginName: string) { - this._pluginRpcHooks.delete(pluginName); + async getRpcMessageHandler(pluginName: string) { + return this._getRpcMessageHandler(pluginName); } private _setPluginToRunning(pluginName: string): void { diff --git a/packages/controllers/src/services/ExecutionEnvironmentService.ts b/packages/controllers/src/services/ExecutionEnvironmentService.ts new file mode 100644 index 0000000000..69444b868d --- /dev/null +++ b/packages/controllers/src/services/ExecutionEnvironmentService.ts @@ -0,0 +1,28 @@ +import { JsonRpcRequest } from 'json-rpc-engine'; +import { PluginData } from '@mm-snap/types'; +import { PluginRpcHook } from './WebWorkerExecutionEnvironmentService'; + +export interface PluginMetadata { + hostname: string; +} + +export type TerminatePlugin = (pluginName: string) => Promise; +export type Command = ( + pluginName: string, + message: JsonRpcRequest, +) => Promise; +export type TerminateAll = () => Promise; +export type CreatePluginEnvironment = ( + metadata: PluginMetadata, +) => Promise; +export type ExecutePlugin = (pluginData: PluginData) => Promise; +export type GetRpcMessageHandler = ( + pluginName: string, +) => Promise; + +export interface ExecutionEnvironmentService { + terminatePlugin: TerminatePlugin; + terminateAllPlugins: TerminateAll; + executePlugin: ExecutePlugin; + getRpcMessageHandler: GetRpcMessageHandler; +} diff --git a/packages/controllers/src/services/WebWorkerExecutionEnvironmentService.test.ts b/packages/controllers/src/services/WebWorkerExecutionEnvironmentService.test.ts new file mode 100644 index 0000000000..b9d46143fa --- /dev/null +++ b/packages/controllers/src/services/WebWorkerExecutionEnvironmentService.test.ts @@ -0,0 +1,39 @@ +import fs from 'fs'; +import { WebWorkerExecutionEnvironmentService } from './WebWorkerExecutionEnvironmentService'; + +const workerCode = fs.readFileSync( + require.resolve('@mm-snap/workers/dist/PluginWorker.js'), + 'utf8', +); + +describe('Worker Controller', () => { + it('can boot', async () => { + const webWorkerExecutionEnvironmentService = new WebWorkerExecutionEnvironmentService( + { + setupWorkerConnection: () => { + // do nothing + }, + workerUrl: new URL('https://foo.bar.baz'), + }, + ); + expect(webWorkerExecutionEnvironmentService).toBeDefined(); + }); + it('can create a plugin worker and start the plugin', async () => { + const webWorkerExecutionEnvironmentService = new WebWorkerExecutionEnvironmentService( + { + setupWorkerConnection: () => { + // do nothing + }, + workerUrl: new URL(URL.createObjectURL(new Blob([workerCode]))), + }, + ); + const pluginName = 'foo.bar.baz'; + const response = await webWorkerExecutionEnvironmentService.executePlugin({ + pluginName, + sourceCode: ` + console.log('foo'); + `, + }); + expect(response).toEqual('OK'); + }); +}); diff --git a/packages/controllers/src/workers/WorkerController.ts b/packages/controllers/src/services/WebWorkerExecutionEnvironmentService.ts similarity index 74% rename from packages/controllers/src/workers/WorkerController.ts rename to packages/controllers/src/services/WebWorkerExecutionEnvironmentService.ts index 0adaef0837..6a7a40c304 100644 --- a/packages/controllers/src/workers/WorkerController.ts +++ b/packages/controllers/src/services/WebWorkerExecutionEnvironmentService.ts @@ -2,7 +2,6 @@ import { Duplex } from 'stream'; import { nanoid } from 'nanoid'; import pump from 'pump'; import { ObservableStore } from '@metamask/obs-store'; -import SafeEventEmitter from '@metamask/safe-event-emitter'; import ObjectMultiplex from '@metamask/object-multiplex'; import { WorkerParentPostMessageStream } from '@metamask/post-message-stream'; import { PLUGIN_STREAM_NAMES } from '@mm-snap/workers'; @@ -13,12 +12,10 @@ import { JsonRpcRequest, PendingJsonRpcResponse, } from 'json-rpc-engine'; +import { ExecutionEnvironmentService } from '../services/ExecutionEnvironmentService'; -export type SetupWorkerConnection = (metadata: any, stream: Duplex) => void; +export type SetupWorkerConnection = (stream: Duplex) => void; -export interface PluginWorkerMetadata { - hostname: string; -} interface WorkerControllerArgs { setupWorkerConnection: SetupWorkerConnection; workerUrl: URL; @@ -30,6 +27,12 @@ interface WorkerStreams { _connection: WorkerParentPostMessageStream; } +// The plugin is the callee +export type PluginRpcHook = ( + origin: string, + request: Record, +) => Promise; + interface WorkerWrapper { workerId: string; streams: WorkerStreams; @@ -37,9 +40,12 @@ interface WorkerWrapper { worker: Worker; } -export class WorkerController extends SafeEventEmitter { +export class WebWorkerExecutionEnvironmentService + implements ExecutionEnvironmentService { public store: ObservableStore<{ workers: Record }>; + private _pluginRpcHooks: Map; + private workerUrl: URL; private workers: Map; @@ -51,13 +57,13 @@ export class WorkerController extends SafeEventEmitter { private workerToPluginMap: Map; constructor({ setupWorkerConnection, workerUrl }: WorkerControllerArgs) { - super(); this.workerUrl = workerUrl; this.setupWorkerConnection = setupWorkerConnection; this.store = new ObservableStore({ workers: {} }); this.workers = new Map(); this.pluginToWorkerMap = new Map(); this.workerToPluginMap = new Map(); + this._pluginRpcHooks = new Map(); } _setWorker(workerId: string, workerObj: WorkerWrapper): void { @@ -80,7 +86,7 @@ export class WorkerController extends SafeEventEmitter { this.store.updateState({ workers: newWorkerState }); } - async command( + private async _command( workerId: string, message: JsonRpcRequest, ): Promise { @@ -103,15 +109,17 @@ export class WorkerController extends SafeEventEmitter { return response.result; } - terminateAll(): void { + async terminateAllPlugins() { for (const workerId of this.workers.keys()) { this.terminate(workerId); } + this._pluginRpcHooks.clear(); } - terminateWorkerOf(pluginName: string): void { + async terminatePlugin(pluginName: string) { const workerId = this.pluginToWorkerMap.get(pluginName); workerId && this.terminate(workerId); + this._removePluginHooks(pluginName); } terminate(workerId: string): void { @@ -134,30 +142,57 @@ export class WorkerController extends SafeEventEmitter { console.log(`worker:${workerId} terminated`); } - async startPlugin( - workerId: string, - pluginData: PluginData, - ): Promise { - const _workerId: string = workerId || this.workers.keys().next()?.value(); - if (!_workerId) { - throw new Error('No workers available.'); + /** + * Gets the RPC message handler for the given plugin. + * + * @param pluginName - The name of the plugin whose message handler to get. + */ + async getRpcMessageHandler(pluginName: string) { + return this._pluginRpcHooks.get(pluginName); + } + + private _removePluginHooks(pluginName: string) { + this._pluginRpcHooks.delete(pluginName); + } + + private _createPluginHooks(pluginName: string, workerId: string) { + const rpcHook = async ( + origin: string, + request: Record, + ) => { + return await this._command(workerId, { + id: nanoid(), + jsonrpc: '2.0', + method: 'pluginRpc', + params: { + origin, + request, + target: pluginName, + }, + }); + }; + + this._pluginRpcHooks.set(pluginName, rpcHook); + } + + async executePlugin(pluginData: PluginData): Promise { + if (this.pluginToWorkerMap.has(pluginData.pluginName)) { + throw new Error( + `Plugin "${pluginData.pluginName}" is already being executed.`, + ); } - this._mapPluginAndWorker(pluginData.pluginName, workerId); + const _workerId = await this._initWorker(); + this._mapPluginAndWorker(pluginData.pluginName, _workerId); - return this.command(_workerId, { + const result = await this._command(_workerId, { jsonrpc: '2.0', method: 'installPlugin', params: pluginData, id: nanoid(), }); - } - - /** - * @returns The ID of the newly created worker. - */ - async createPluginWorker(metadata: PluginWorkerMetadata): Promise { - return this._initWorker(metadata); + this._createPluginHooks(pluginData.pluginName, _workerId); + return result; } _mapPluginAndWorker(pluginName: string, workerId: string): void { @@ -189,14 +224,14 @@ export class WorkerController extends SafeEventEmitter { this.pluginToWorkerMap.delete(pluginName); } - async _initWorker(metadata: PluginWorkerMetadata): Promise { + async _initWorker(): Promise { console.log('_initWorker'); const workerId = nanoid(); const worker = new Worker(this.workerUrl, { name: workerId, }); - const streams = this._initWorkerStreams(worker, workerId, metadata); + const streams = this._initWorkerStreams(worker, workerId); const rpcEngine = new JsonRpcEngine(); const jsonRpcConnection = createStreamMiddleware(); @@ -211,7 +246,7 @@ export class WorkerController extends SafeEventEmitter { rpcEngine, worker, }); - await this.command(workerId, { + await this._command(workerId, { jsonrpc: '2.0', method: 'ping', id: nanoid(), @@ -219,11 +254,7 @@ export class WorkerController extends SafeEventEmitter { return workerId; } - _initWorkerStreams( - worker: Worker, - workerId: string, - metadata: PluginWorkerMetadata, - ): WorkerStreams { + _initWorkerStreams(worker: Worker, workerId: string): WorkerStreams { const workerStream = new WorkerParentPostMessageStream({ worker }); // Typecast justification: stream type mismatch const mux = setupMultiplex( @@ -234,7 +265,7 @@ export class WorkerController extends SafeEventEmitter { const commandStream = mux.createStream(PLUGIN_STREAM_NAMES.COMMAND); const rpcStream = mux.createStream(PLUGIN_STREAM_NAMES.JSON_RPC); - this.setupWorkerConnection(metadata, (rpcStream as unknown) as Duplex); + this.setupWorkerConnection((rpcStream as unknown) as Duplex); // Typecast justification: stream type mismatch return { diff --git a/packages/controllers/src/workers/WorkerController.test.ts b/packages/controllers/src/workers/WorkerController.test.ts deleted file mode 100644 index 3b07ff0744..0000000000 --- a/packages/controllers/src/workers/WorkerController.test.ts +++ /dev/null @@ -1,51 +0,0 @@ -import fs from 'fs'; -import { WorkerController } from './WorkerController'; - -const workerCode = fs.readFileSync( - require.resolve('@mm-snap/workers/dist/PluginWorker.js'), - 'utf8', -); - -describe('Worker Controller', () => { - it('can boot', async () => { - const workerController = new WorkerController({ - setupWorkerConnection: () => { - // do nothing - }, - workerUrl: new URL('https://foo.bar.baz'), - }); - expect(workerController).toBeDefined(); - }); - it('can create a plugin worker and get the workerId back', async () => { - const workerController = new WorkerController({ - setupWorkerConnection: () => { - // do nothing - }, - workerUrl: new URL(URL.createObjectURL(new Blob([workerCode]))), - }); - expect( - typeof (await workerController.createPluginWorker({ - hostname: 'foobarbaz', - })), - ).toEqual('string'); - }); - it('can create a plugin worker and start the plugin', async () => { - const workerController = new WorkerController({ - setupWorkerConnection: () => { - // do nothing - }, - workerUrl: new URL(URL.createObjectURL(new Blob([workerCode]))), - }); - const pluginName = 'foo.bar.baz'; - const workerId = await workerController.createPluginWorker({ - hostname: pluginName, - }); - const response = await workerController.startPlugin(workerId, { - pluginName, - sourceCode: ` - console.log('foo'); - `, - }); - expect(response).toEqual('OK'); - }); -}); diff --git a/packages/rpc-methods/src/restricted/invokePlugin.ts b/packages/rpc-methods/src/restricted/invokePlugin.ts index 1570d59459..872c790976 100644 --- a/packages/rpc-methods/src/restricted/invokePlugin.ts +++ b/packages/rpc-methods/src/restricted/invokePlugin.ts @@ -64,7 +64,7 @@ function getInvokePluginHandlerGetter({ }); } - const handler = getPluginRpcHandler(pluginOriginString); + const handler = await getPluginRpcHandler(pluginOriginString); if (!handler) { return end( ethErrors.rpc.methodNotFound({