From d226b7bc6cee1f37fae5e940fe90e2764e676253 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 16 Aug 2016 13:54:21 -0700 Subject: [PATCH] Use Proxy for accessing properties of remote function --- lib/browser/rpc-server.js | 13 ---------- lib/renderer/api/remote.js | 26 +++++++++---------- spec/api-ipc-spec.js | 4 ++- .../module/function-with-properties.js | 10 ++++++- 4 files changed, 25 insertions(+), 28 deletions(-) diff --git a/lib/browser/rpc-server.js b/lib/browser/rpc-server.js index 5bcd6bf07db..d240561837e 100644 --- a/lib/browser/rpc-server.js +++ b/lib/browser/rpc-server.js @@ -51,18 +51,6 @@ let getObjectPrototype = function (object) { } } -// Include properties on member methods -const addFunctionProperties = (sender, value, members) => { - members.forEach((member) => { - if (member.type !== 'method') return - const method = value[member.name] - member.members = getObjectMembers(method) - if (member.members.length > 0) { - member.id = objectsRegistry.add(sender, method) - } - }) -} - // Convert a real value into meta data. let valueToMeta = function (sender, value, optimizeSimpleObject = false) { // Determine the type of value. @@ -102,7 +90,6 @@ let valueToMeta = function (sender, value, optimizeSimpleObject = false) { meta.id = objectsRegistry.add(sender, value) meta.members = getObjectMembers(value) meta.proto = getObjectPrototype(value) - addFunctionProperties(sender, value, meta.members) } else if (meta.type === 'buffer') { meta.value = Array.prototype.slice.call(value, 0) } else if (meta.type === 'promise') { diff --git a/lib/renderer/api/remote.js b/lib/renderer/api/remote.js index 2bbcefa2026..22f5674e84d 100644 --- a/lib/renderer/api/remote.js +++ b/lib/renderer/api/remote.js @@ -99,7 +99,7 @@ const setObjectMembers = function (ref, object, metaId, members) { let descriptor = { enumerable: member.enumerable } if (member.type === 'method') { - let remoteMemberFunction = function () { + const remoteMemberFunction = function () { if (this && this.constructor === remoteMemberFunction) { // Constructor call. let ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', metaId, member.name, wrapArgs(arguments)) @@ -110,13 +110,22 @@ const setObjectMembers = function (ref, object, metaId, members) { return metaToValue(ret) } } + + // Wrap function in proxy for accessing remote properties + let descriptorFunction = new Proxy(remoteMemberFunction, { + get: (target, property, receiver) => { + if (target.hasOwnProperty(property)) return target[property] + return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_GET', metaId, member.name))[property] + } + }) + descriptor.get = function () { - remoteMemberFunction.ref = ref // The member should reference its object. - return remoteMemberFunction + descriptorFunction.ref = ref // The member should reference its object. + return descriptorFunction } // Enable monkey-patch the method descriptor.set = function (value) { - remoteMemberFunction = value + descriptorFunction = value return value } descriptor.configurable = true @@ -135,18 +144,9 @@ const setObjectMembers = function (ref, object, metaId, members) { } Object.defineProperty(object, member.name, descriptor) - addFunctionProperties(object, member) } } -// Include properties on member methods -const addFunctionProperties = (object, member) => { - if (member.type !== 'method') return - if (member.members == null || member.members.length === 0) return - const method = object[member.name] - setObjectMembers(method, method, member.id, member.members) -} - // Populate object's prototype from descriptor. // This matches |getObjectPrototype| in rpc-server. const setObjectPrototype = function (ref, object, metaId, descriptor) { diff --git a/spec/api-ipc-spec.js b/spec/api-ipc-spec.js index b91e6db21db..88e7af7a854 100644 --- a/spec/api-ipc-spec.js +++ b/spec/api-ipc-spec.js @@ -59,9 +59,11 @@ describe('ipc module', function () { a = remote.require(path.join(fixtures, 'module', 'function-with-properties.js')) assert.equal(typeof a, 'object') - assert.equal(typeof a.foo, 'function') + assert.equal(a.foo(), 'hello') assert.equal(a.foo.bar, 'baz') assert.equal(a.foo.nested.prop, 'yes') + assert.equal(a.foo.method1(), 'world') + assert.equal(a.foo.method1.prop1(), 123) }) it('should work with static class members', function () { diff --git a/spec/fixtures/module/function-with-properties.js b/spec/fixtures/module/function-with-properties.js index 22c9f2d19bd..3ae617133e7 100644 --- a/spec/fixtures/module/function-with-properties.js +++ b/spec/fixtures/module/function-with-properties.js @@ -1,8 +1,16 @@ -function foo () {} +function foo () { + return 'hello' +} foo.bar = 'baz' foo.nested = { prop: 'yes' } +foo.method1 = function () { + return 'world' +} +foo.method1.prop1 = function () { + return 123 +} module.exports = { foo: foo