[Utils] Helper for comunnication between JS and CPP
authorMaciek Blim <m.blim@samsung.com>
Mon, 15 Dec 2014 09:17:14 +0000 (10:17 +0100)
committerJerzy Pabich <j.pabich@samsung.com>
Mon, 15 Dec 2014 11:24:54 +0000 (12:24 +0100)
Change-Id: Ib7ec9c783c2242c0ecc6871f49dd63265972c86d
Signed-off-by: Maciek Blim <m.blim@samsung.com>
src/common/extension.cc
src/utils/utils_api.js

index 5b9d36d8df5ef83d22aa07b23a430d4722d96a3b..43f40c8ece3b78e734624c8101e35f97f3f6fdf6 100644 (file)
@@ -283,7 +283,7 @@ void ParsedInstance::HandleMessage(const char* msg, bool is_sync) {
     }
 
     picojson::value result = picojson::value(picojson::object());
-    func(args, result.get<picojson::object>());
+    func(value, result.get<picojson::object>());
 
     if (is_sync)
       SendSyncReply(result.serialize().c_str());
index fc60ff0b1f1414e4c4e4c3b6404a023dbbf8c34a..84004a72e4052655413651726254ab74d2af9bae 100644 (file)
@@ -809,10 +809,222 @@ NativeManager.prototype.getErrorObject = function(result) {
   return new tizen.WebAPIException(result.error.code, result.error.message, result.error.name);
 };
 
+/*
+ *bridge is a two way communication interface
+ *Example usage:
+ *var bridge = new NativeBridge(extension);
+ *    To send sync method:
+ *    var result = bridge.sync({
+ *        cmd: 'my_cpp_function_symbol',
+ *        args: {
+ *            name: 'My name',
+ *            age: 28
+ *        }
+ *    });
+ *    console.log(result);
+ *
+ *    To send async method and handle response:
+ *    bridge.async({
+ *        cmd: 'my_cpp_function_symbol',
+ *        args: {
+ *            name: 'My name'
+ *        }
+ *    }).then({
+ *        success: function (data) {
+ *            var age = data.age;
+ *            args.successCallback(age);
+ *        },
+ *        error: function (e) {...},
+ *        someCallback: function (data) {...}
+ *    });
+ *bridge.async will add special param to passed data called cid
+ *that param need to be kept and returned with respons
+ *To determine which callback should be invoked, response should
+ *contain "action" param. Value of "action" param indicates name of
+ *triggered callback.
+ *Callbask are removed from listenr by defoult to prevent that behaviour
+ *param "keep" should be assigned to value true
+ *Example of c++ async response:
+ *    Simple succes with data:
+ *    {
+ *        cid: 23,
+ *        action: 'success',
+ *        args: {
+ *            age: 23
+ *        }
+ *    }
+ *    More complicated example:
+ *    {
+ *        cid: 23,
+ *        action: 'progress',
+ *        keep: true,
+ *        args: {
+ *            age: 23
+ *        }
+ *    }
+ */
+var NativeBridge = (function (extension, debug) {
+    debug = !!debug;
+    var Callbacks = (function () {
+        var _collection = {};
+        var _cid = 0;
+        var _next = function () {
+            return (_cid += 1);
+        };
+
+        var CallbackManager = function () {};
+
+        CallbackManager.prototype = {
+            add: function (/*callbacks, cid?*/) {
+                if (debug) console.log('bridge', 'CallbackManager', 'add');
+                var args = Array.prototype.slice.call(arguments);
+                var c = args.shift();
+                var cid = args.pop();
+                if (cid) {
+                    if (c !== null && typeof c === 'object') {
+                        for (var key in c) {
+                            if (c.hasOwnProperty(key)) _collection[cid][key] = c[key];
+                        }
+                    }
+                } else {
+                    cid = _next();
+                    _collection[cid] = c;
+                }
+                return cid;
+            },
+            remove: function (cid) {
+                if (debug)  console.log('bridge', 'CallbackManager', 'remove', cid);
+                if (_collection[cid]) delete _collection[cid];
+            },
+            call: function (cid, key, args, keep) {
+                if (debug) console.log('bridge', 'CallbackManager', 'call', cid, key);
+                var callbacks = _collection[cid];
+                keep = !!keep;
+                if (callbacks) {
+                    var fn = callbacks[key];
+                    if (fn) {
+                        fn.apply(null, args);
+                        if (!keep) this.remove(cid)
+                    }
+                }
+            }
+        };
+
+        return {
+            getInstance: function () {
+                return this.instance || (this.instance = new CallbackManager);
+            }
+        };
+    })();
+
+
+    var Listeners = (function () {
+        var _listeners = {};
+        var _id = 0;
+        var _next = function () {
+            return (_id += 1);
+        };
+
+        var ListenerManager = function () {};
+
+        ListenerManager.prototype = {
+            add: function (l) {
+                if (debug) console.log('bridge', 'ListenerManager', 'add');
+                var id = _next();
+                _listeners[id] = l;
+                return id;
+            },
+            resolve: function (id, action, data, keep) {
+                if (debug) console.log('bridge', 'ListenerManager', 'resolve', id, action);
+                keep = !!keep;
+                var l = _listeners[id];
+                if (l) {
+                    var cm = Callbacks.getInstance();
+                    cm.call(l.cid, action, [data], keep);
+                }
+                return l;
+            },
+            remove: function (id) {
+                if (debug) console.log('bridge', 'ListenerManager', 'remove', id);
+                var l = _listeners[id];
+                if (l) {
+                    var cm = Callbacks.getInstance();
+                    if (l.cid) cm.remove(l.cid);
+                    delete _listeners[id];
+                }
+            }
+        }
+
+        return {
+            getInstance: function () {
+                return this.instance || (this.instance = new ListenerManager);
+            }
+        };
+    })();
+
+    var Listener = function () {
+        if (debug) console.log('bridge', 'Listener constructor');
+        this.cid = null;
+    };
+    Listener.prototype = {
+        then: function (c) {
+            if (debug) console.log('bridge', 'Listener', 'then');
+            var cm = Callbacks.getInstance();
+            this.cid = cm.add(c, this.cid);
+            return this;
+        }
+    };
+
+    var Bridge = function () {};
+    Bridge.prototype = {
+        sync: function (data) {
+            var json = JSON.stringify(data);
+            if (debug) console.log('bridge', 'sync', json);
+            var result = extension.internal.sendSyncMessage(json);
+            var obj = JSON.parse(result);
+            if (obj.error)
+                throw new tizen.WebAPIException(obj.code, obj.name, obj.message);
+            return obj.result;
+        },
+        async: function (data) {
+            var l = new Listener();
+            data.cid = Listeners.getInstance().add(l);
+            var json = JSON.stringify(data);
+            if (debug) console.log('bridge', 'async', json);
+            setTimeout(function () {
+                extension.postMessage(json);
+            });
+            return l;
+        }
+    };
+
+    extension.setMessageListener(function (json) {
+        /*
+         *Expected response:
+         *{
+         *    cid: 23,                        // callback id
+         *    action: 'success',              // expected callback action
+         *    keep: false                     // optional param
+         *    args: {...}                     // data pased to callback
+         *}
+         */
+
+        if (debug) console.log('bridge', 'setMessageListener', json);
+        var data = JSON.parse(json);
+        if (data.cid && data.action) {
+            Listeners.getInstance().resolve(data.cid, data.action, data.args, data.keep);
+        }
+    });
+
+    return new Bridge;
+});
+
+
 
 Utils.prototype.type = _type;
 Utils.prototype.converter = _converter;
 Utils.prototype.validator = _validator;
 Utils.prototype.NativeManager = NativeManager;
+Utils.prototype.NativeBridge = NativeBridge;
 
 exports = new Utils();