Use Proxy for accessing properties of remote function

This commit is contained in:
Kevin Sawicki 2016-08-16 13:54:21 -07:00
parent 8b38018ab4
commit d226b7bc6c
4 changed files with 25 additions and 28 deletions

View file

@ -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. // Convert a real value into meta data.
let valueToMeta = function (sender, value, optimizeSimpleObject = false) { let valueToMeta = function (sender, value, optimizeSimpleObject = false) {
// Determine the type of value. // Determine the type of value.
@ -102,7 +90,6 @@ let valueToMeta = function (sender, value, optimizeSimpleObject = false) {
meta.id = objectsRegistry.add(sender, value) meta.id = objectsRegistry.add(sender, value)
meta.members = getObjectMembers(value) meta.members = getObjectMembers(value)
meta.proto = getObjectPrototype(value) meta.proto = getObjectPrototype(value)
addFunctionProperties(sender, value, meta.members)
} else if (meta.type === 'buffer') { } else if (meta.type === 'buffer') {
meta.value = Array.prototype.slice.call(value, 0) meta.value = Array.prototype.slice.call(value, 0)
} else if (meta.type === 'promise') { } else if (meta.type === 'promise') {

View file

@ -99,7 +99,7 @@ const setObjectMembers = function (ref, object, metaId, members) {
let descriptor = { enumerable: member.enumerable } let descriptor = { enumerable: member.enumerable }
if (member.type === 'method') { if (member.type === 'method') {
let remoteMemberFunction = function () { const remoteMemberFunction = function () {
if (this && this.constructor === remoteMemberFunction) { if (this && this.constructor === remoteMemberFunction) {
// Constructor call. // Constructor call.
let ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', metaId, member.name, wrapArgs(arguments)) 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) 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 () { descriptor.get = function () {
remoteMemberFunction.ref = ref // The member should reference its object. descriptorFunction.ref = ref // The member should reference its object.
return remoteMemberFunction return descriptorFunction
} }
// Enable monkey-patch the method // Enable monkey-patch the method
descriptor.set = function (value) { descriptor.set = function (value) {
remoteMemberFunction = value descriptorFunction = value
return value return value
} }
descriptor.configurable = true descriptor.configurable = true
@ -135,18 +144,9 @@ const setObjectMembers = function (ref, object, metaId, members) {
} }
Object.defineProperty(object, member.name, descriptor) 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. // Populate object's prototype from descriptor.
// This matches |getObjectPrototype| in rpc-server. // This matches |getObjectPrototype| in rpc-server.
const setObjectPrototype = function (ref, object, metaId, descriptor) { const setObjectPrototype = function (ref, object, metaId, descriptor) {

View file

@ -59,9 +59,11 @@ describe('ipc module', function () {
a = remote.require(path.join(fixtures, 'module', 'function-with-properties.js')) a = remote.require(path.join(fixtures, 'module', 'function-with-properties.js'))
assert.equal(typeof a, 'object') 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.bar, 'baz')
assert.equal(a.foo.nested.prop, 'yes') 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 () { it('should work with static class members', function () {

View file

@ -1,8 +1,16 @@
function foo () {} function foo () {
return 'hello'
}
foo.bar = 'baz' foo.bar = 'baz'
foo.nested = { foo.nested = {
prop: 'yes' prop: 'yes'
} }
foo.method1 = function () {
return 'world'
}
foo.method1.prop1 = function () {
return 123
}
module.exports = { module.exports = {
foo: foo foo: foo