Browse Source

Use Proxy for accessing properties of remote function

Kevin Sawicki 8 years ago
parent
commit
d226b7bc6c

+ 0 - 13
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') {

+ 13 - 13
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) {

+ 3 - 1
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 () {

+ 9 - 1
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