From e7622c8558e7087f2b92d16bea761d24ec460229 Mon Sep 17 00:00:00 2001 From: Timothy Farrell Date: Wed, 28 Dec 2016 08:29:04 -0600 Subject: [PATCH] Support nested methods. --- packages/portal/src/index.js | 38 ++++++++++++++++++++++++++++++------ packages/portal/test.js | 13 ++++++++++-- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/packages/portal/src/index.js b/packages/portal/src/index.js index ab3f88e..110deb9 100644 --- a/packages/portal/src/index.js +++ b/packages/portal/src/index.js @@ -21,10 +21,37 @@ function tryJSON(type, destination, id, data) { } } +function getPaths(obj, prefix = '') { + return Object.keys(obj) + .map(key => { + const prop = obj[key]; + const path = `${prefix}${key}`; + if (typeof prop === 'function') { + return path; + } + return getPaths(prop, path + '.'); + }) + .reduce((a, b) => a.concat(b), []); +} + +function traverseObj(obj, pathStr, assignValue) { + const path = pathStr.split('.'); + const last = path.pop(); + const ptr = path.reduce( + (acc, next) => (acc[next] === undefined ? (acc[next] = {}) : acc[next]), + obj + ); + if (assignValue) { + return (ptr[last] = assignValue); + } + return ptr[last]; +} + export function WorkerPortal(context, worker, isSlave, serialize) { const responseMap = new Map(); const _worker = worker || self; - const contextIndex = Object.keys(context); + const contextIndex = getPaths(context); + const methods = contextIndex.map(path => traverseObj(context, path)); const _serialize = serialize ? (type, destination, id, params) => serialize(type, destination, id, params, tryJSON) : tryJSON; @@ -66,7 +93,7 @@ export function WorkerPortal(context, worker, isSlave, serialize) { // If we have received an RPC call, execute and respond. let thennable; try { - thennable = context[contextIndex[destination]].apply(null, params); + thennable = methods[destination].apply(null, params); } catch (e) { _reject(e); } @@ -94,8 +121,8 @@ export function WorkerPortal(context, worker, isSlave, serialize) { function resolveExternalInterfaceFactory(resolve) { return (linkedFunctionNames, ...rest) => { const externalInterface = {}; - linkedFunctionNames.forEach((fnName, index) => { - externalInterface[fnName] = injectionPointFactory(index); + linkedFunctionNames.forEach((pathStr, index) => { + traverseObj(externalInterface, pathStr, injectionPointFactory(index)); }); enabled = true; resolve(externalInterface); @@ -118,8 +145,7 @@ export function WorkerPortal(context, worker, isSlave, serialize) { if (isSlave) { return new Promise(resolve => { contextIndex.splice(0, 0, '__init', '__cleanupSlave'); - context.__init = resolveExternalInterfaceFactory(resolve); - context.__cleanupSlave = cleanup; + methods.splice(0, 0, resolveExternalInterfaceFactory(resolve), cleanup); }); } diff --git a/packages/portal/test.js b/packages/portal/test.js index c0e23e0..2f40f43 100644 --- a/packages/portal/test.js +++ b/packages/portal/test.js @@ -42,7 +42,13 @@ test('Workers can call and respond equally', async t => { const slave = WorkerPortal( { - slaveAdd: (a, b) => a + b + slaveAdd: (a, b) => a + b, + math: { + multiply: (a, b) => a * b, + lib: { + pow: (a, b) => Math.pow(a, b) + } + } }, a, true @@ -58,11 +64,14 @@ test('Workers can call and respond equally', async t => { const masterApi = await master; const slaveApi = await slave; - t.deepEqual(Object.keys(masterApi), ['__init', '__cleanupSlave', 'slaveAdd', '_cleanup']); + t.deepEqual(Object.keys(masterApi), ['__init', '__cleanupSlave', 'slaveAdd', 'math', '_cleanup']); + t.deepEqual(Object.keys(masterApi.math), ['multiply', 'lib']); t.deepEqual(Object.keys(slaveApi), ['masterSubtract']); t.is(await slaveApi.masterSubtract(9, 2), 7); t.is(await masterApi.slaveAdd(9, 2), 11); + t.is(await masterApi.math.multiply(9, 2), 18); + t.is(await masterApi.math.lib.pow(9, 2), 81); t.is(await masterApi.slaveAdd(5, 2), 7); t.is(await slaveApi.masterSubtract(2, 2), 0);