Make the RPC stuff code more understandable.
authorCheng Zhao <zcbenz@gmail.com>
Fri, 26 Apr 2013 15:58:49 +0000 (23:58 +0800)
committerCheng Zhao <zcbenz@gmail.com>
Fri, 26 Apr 2013 15:58:49 +0000 (23:58 +0800)
browser/atom/objects_registry.coffee
browser/atom/rpc_server.coffee
renderer/api/lib/remote.coffee

index 6bb8f06..89eba86 100644 (file)
@@ -19,6 +19,7 @@ class ObjectsStore
     @objects[id]?
 
   remove: (id) ->
+    throw new Error("Invalid key #{id} for ObjectsStore") unless @has id
     delete @objects[id]
 
   get: (id) ->
@@ -30,6 +31,8 @@ class ObjectsStore
     @stores[key] = new ObjectsStore unless @stores[key]?
     @stores[key]
 
+# Objects in weak map will be not referenced (so we won't leak memory), and
+# every object created in browser will have a unique id in weak map.
 objectsWeakMap = new IDWeakMap
 objectsWeakMap.add = (obj) ->
   id = IDWeakMap::add.call this, obj
@@ -40,14 +43,18 @@ objectsWeakMap.add = (obj) ->
 process.on 'ATOM_BROWSER_INTERNAL_NEW', (obj) ->
   # It's possible that user created a object in browser side and then want to
   # get it in renderer via remote.getObject. So we must add every native object
-  # created in browser to the weak map.
+  # created in browser to the weak map even it may not be referenced by the
+  # renderer.
   objectsWeakMap.add obj
 
 exports.add = (process_id, routing_id, obj) ->
-  # Some native types may already been added to objectsWeakMap, in that case we
-  # don't add it twice.
+  # Some native objects may already been added to objectsWeakMap, be care not
+  # to add it twice.
   objectsWeakMap.add obj unless obj.id?
 
+  # Store and reference the object, then return the storeId which points to
+  # where the object is stored. The caller can later dereference the object
+  # with the storeId.
   store = ObjectsStore.forRenderView process_id, routing_id
   store.add obj
 
index ec4a854..6c0b955 100644 (file)
@@ -2,7 +2,9 @@ ipc = require 'ipc'
 path = require 'path'
 objectsRegistry = require './objects_registry.js'
 
-class PlainObject
+# Convert a real value into a POD structure which carries information of this
+# value.
+class Meta
   constructor: (process_id, routing_id, value) ->
     @type = typeof value
     @type = 'value' if value is null
@@ -10,9 +12,13 @@ class PlainObject
 
     if @type is 'array'
       @members = []
-      @members.push new PlainObject(process_id, routing_id, el) for el in value
+      @members.push new Meta(process_id, routing_id, el) for el in value
     else if @type is 'object' or @type is 'function'
       @name = value.constructor.name
+
+      # Reference the original value if it's an object, because when it's
+      # passed to renderer we would assume the renderer keeps a reference of
+      # it.
       @storeId = objectsRegistry.add process_id, routing_id, value
       @id = value.id
 
@@ -24,7 +30,7 @@ class PlainObject
 
 ipc.on 'ATOM_INTERNAL_REQUIRE', (event, process_id, routing_id, module) ->
   try
-    event.result = new PlainObject(process_id, routing_id, require(module))
+    event.result = new Meta(process_id, routing_id, require(module))
   catch e
     event.result = type: 'error', value: e.message
 
@@ -34,7 +40,7 @@ ipc.on 'ATOM_INTERNAL_CONSTRUCTOR', (event, process_id, routing_id, id, args) ->
     # Call new with array of arguments.
     # http://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible
     obj = new (Function::bind.apply(constructor, [null].concat(args)))
-    event.result = new PlainObject(process_id, routing_id, obj)
+    event.result = new Meta(process_id, routing_id, obj)
   catch e
     event.result = type: 'error', value: e.message
 
@@ -42,7 +48,7 @@ ipc.on 'ATOM_INTERNAL_FUNCTION_CALL', (event, process_id, routing_id, id, args)
   try
     func = objectsRegistry.get id
     ret = func.apply global, args
-    event.result = new PlainObject(process_id, routing_id, ret)
+    event.result = new Meta(process_id, routing_id, ret)
   catch e
     event.result = type: 'error', value: e.message
 
@@ -50,7 +56,7 @@ ipc.on 'ATOM_INTERNAL_MEMBER_CALL', (event, process_id, routing_id, id, method,
   try
     obj = objectsRegistry.get id
     ret = obj[method].apply(obj, args)
-    event.result = new PlainObject(process_id, routing_id, ret)
+    event.result = new Meta(process_id, routing_id, ret)
   catch e
     event.result = type: 'error', value: e.message
 
@@ -64,14 +70,14 @@ ipc.on 'ATOM_INTERNAL_MEMBER_SET', (event, process_id, routing_id, id, name, val
 ipc.on 'ATOM_INTERNAL_MEMBER_GET', (event, process_id, routing_id, id, name) ->
   try
     obj = objectsRegistry.get id
-    event.result = new PlainObject(process_id, routing_id, obj[name])
+    event.result = new Meta(process_id, routing_id, obj[name])
   catch e
     event.result = type: 'error', value: e.message
 
 ipc.on 'ATOM_INTERNAL_REFERENCE', (event, process_id, routing_id, id) ->
   try
     obj = objectsRegistry.get id
-    event.result = new PlainObject(process_id, routing_id, obj)
+    event.result = new Meta(process_id, routing_id, obj)
   catch e
     event.result = type: 'error', value: e.message
 
index b6ef22d..e2ef151 100644 (file)
@@ -1,63 +1,64 @@
 ipc = require 'ipc'
 v8_util = process.atom_binding 'v8_util'
 
-generateFromPainObject = (plain) ->
-  switch plain.type
-    when 'error' then throw new Error(plain.value)
-    when 'value' then plain.value
-    when 'array' then (generateFromPainObject(el) for el in plain.members)
+# Transform the description of value into a value or delegate object.
+metaToValue = (meta) ->
+  switch meta.type
+    when 'error' then throw new Error(meta.value)
+    when 'value' then meta.value
+    when 'array' then (metaToValue(el) for el in meta.members)
     else
-      if plain.type is 'function'
+      if meta.type is 'function'
         # A shadow class to represent the remote function object.
         ret =
         class RemoteFunction
           constructor: ->
             if @constructor == RemoteFunction
               # Constructor call.
-              obj = ipc.sendChannelSync 'ATOM_INTERNAL_CONSTRUCTOR', plain.id, Array::slice.call(arguments)
+              obj = ipc.sendChannelSync 'ATOM_INTERNAL_CONSTRUCTOR', meta.id, Array::slice.call(arguments)
 
               # Returning object in constructor will replace constructed object
               # with the returned object.
               # http://stackoverflow.com/questions/1978049/what-values-can-a-constructor-return-to-avoid-returning-this
-              return generateFromPainObject obj
+              return metaToValue obj
             else
               # Function call.
-              ret = ipc.sendChannelSync 'ATOM_INTERNAL_FUNCTION_CALL', plain.id, Array::slice.call(arguments)
-              return generateFromPainObject ret
+              ret = ipc.sendChannelSync 'ATOM_INTERNAL_FUNCTION_CALL', meta.id, Array::slice.call(arguments)
+              return metaToValue ret
       else
-        ret = v8_util.createObjectWithName plain.name
+        ret = v8_util.createObjectWithName meta.name
 
       # Polulate delegate members.
-      for member in plain.members
+      for member in meta.members
         do (member) ->
           if member.type is 'function'
             ret[member.name] = ->
               # Call member function.
-              ret = ipc.sendChannelSync 'ATOM_INTERNAL_MEMBER_CALL', plain.id, member.name, Array::slice.call(arguments)
-              generateFromPainObject ret
+              ret = ipc.sendChannelSync 'ATOM_INTERNAL_MEMBER_CALL', meta.id, member.name, Array::slice.call(arguments)
+              metaToValue ret
           else
             ret.__defineSetter__ member.name, (value) ->
               # Set member data.
-              ipc.sendChannelSync 'ATOM_INTERNAL_MEMBER_SET', plain.id, member.name, value
+              ipc.sendChannelSync 'ATOM_INTERNAL_MEMBER_SET', meta.id, member.name, value
 
             ret.__defineGetter__ member.name, ->
               # Get member data.
-              ret = ipc.sendChannelSync 'ATOM_INTERNAL_MEMBER_GET', plain.id, member.name
-              generateFromPainObject ret
+              ret = ipc.sendChannelSync 'ATOM_INTERNAL_MEMBER_GET', meta.id, member.name
+              metaToValue ret
 
       # Track delegate object's life time, and tell the browser to clean up
       # when the object is GCed.
       v8_util.setDestructor ret, ->
-        ipc.sendChannel 'ATOM_INTERNAL_DEREFERENCE', plain.storeId
+        ipc.sendChannel 'ATOM_INTERNAL_DEREFERENCE', meta.storeId
 
       ret
 
 # Get remote module.
 exports.require = (module) ->
-  plain = ipc.sendChannelSync 'ATOM_INTERNAL_REQUIRE', module
-  generateFromPainObject plain
+  meta = ipc.sendChannelSync 'ATOM_INTERNAL_REQUIRE', module
+  metaToValue meta
 
 # Get object with specified id.
 exports.getObject = (id) ->
-  plain = ipc.sendChannelSync 'ATOM_INTERNAL_REFERENCE', id
-  generateFromPainObject plain
+  meta = ipc.sendChannelSync 'ATOM_INTERNAL_REFERENCE', id
+  metaToValue meta