[bluemonkey] - added websocket module.
authorKevron Rees <tripzero.kev@gmail.com>
Thu, 19 Feb 2015 07:43:45 +0000 (23:43 -0800)
committerKevron Rees <tripzero.kev@gmail.com>
Thu, 19 Feb 2015 07:43:45 +0000 (23:43 -0800)
README.md
plugins/bluemonkey/CMakeLists.txt
plugins/bluemonkey/bluemonkey.cpp
plugins/bluemonkey/bluemonkey.h
plugins/bluemonkey/bmconfig.js
plugins/bluemonkey/bmws.cpp [new file with mode: 0644]
plugins/bluemonkey/bmws.h [new file with mode: 0644]
xwalk/vehicle_api.js

index f3373a6..5f35649 100644 (file)
--- a/README.md
+++ b/README.md
@@ -60,7 +60,7 @@ You will also need to edit your config to enable the Qt-based mainloop:
 
 ~~~~~~~~~~~~~{.json}
 {
-       "mainloop" : "/usr/lib/i386-linux-gnu/automotive-message-broker/qtmainloopplugin.so",
+       "mainloop" : "/usr/lib/x86_64-linux-gnu/automotive-message-broker/qtmainloopplugin.so",
        "plugins" : "/etc/ambd/plugins.d"
 }
 ~~~~~~~~~~~~~
index fc06e64..62b7a09 100644 (file)
@@ -22,6 +22,17 @@ endif(Qt5Core_FOUND)
 
 set(CMAKE_AUTOMOC ON)
 
+find_package(Qt5WebSockets QUIET)
+if(Qt5WebSockets_FOUND)
+       message(STATUS "enabling bluemonkey websocket module")
+       add_executable(bluemonkeyWsModule bmws.cpp)
+       set_target_properties(bluemonkeyWsModule PROPERTIES PREFIX "")
+       set_target_properties(bluemonkeyWsModule PROPERTIES SUFFIX ".so")
+       target_link_libraries(bluemonkeyWsModule ${link_libraries} ${QT_LIBRARIES} ${Qt5WebSockets_LIBRARIES})
+       set(QT_INCLUDE_DIRS ${QT_INCLUDE_DIRS} ${Qt5WebSockets_LIBRARIES})
+       install(TARGETS bluemonkeyWsModule RUNTIME DESTINATION ${PLUGIN_INSTALL_PATH})
+endif()
+
 find_library(communi NAMES Communi)
 
 if(communi)
@@ -36,7 +47,7 @@ if(communi)
        install(TARGETS bluemonkeyIrcModule LIBRARY DESTINATION ${PLUGIN_INSTALL_PATH})
 endif(communi)
 
-find_package(Qt5Sql)
+find_package(Qt5Sql QUIET)
 
 if(Qt5Sql_FOUND)
        message(STATUS "enabling database bluemonkey module")
@@ -46,7 +57,7 @@ if(Qt5Sql_FOUND)
        install(TARGETS bluemonkeyDbModule LIBRARY DESTINATION ${PLUGIN_INSTALL_PATH})
 endif()
 
-find_package(Qt5DBus)
+find_package(Qt5DBus QUIET)
 
 if(Qt5DBus_FOUND)
        message(STATUS "enabling dbus bluemonkey module")
@@ -58,7 +69,7 @@ if(Qt5DBus_FOUND)
        install(TARGETS bluemonkeyDBusModule RUNTIME DESTINATION ${PLUGIN_INSTALL_PATH})
 endif()
 
-find_package(Qt5Bluetooth)
+find_package(Qt5Bluetooth QUIET)
 
 if(Qt5Bluetooth_FOUND)
        message(STATUS "enabling bluetooth LE bluemonkey module")
index b19afc6..01b7375 100644 (file)
 
 typedef void create_bluemonkey_module_t(std::map<std::string, std::string> config, std::map<std::string, QObject*> &exports, QString &javascript, QObject* parent);
 
+QString bmJS = (""
+                               "console = { };"
+                               "console.log = function(msg)"
+                               "{"
+                               "  bluemonkey.log(msg);"
+                               "}"
+                               "");
+
+
 Bluemonkey::Bluemonkey(std::map<std::string, std::string> config, QObject *parent)
        :QObject(parent), engine(nullptr), configuration(config)
 {
@@ -116,7 +125,15 @@ bool Bluemonkey::loadModule(QString path)
                loadModule(i.first.c_str(), obj);
        }
 
-       engine->evaluate(js);
+       QJSValue val = engine->evaluate(js);
+
+       qDebug() << "evalutating module js result: " << val.toString();
+
+       if(val.isError())
+       {
+               qDebug() << "Script: " << js;
+               qCritical() << "Error in module javascript: " << val.toString();
+       }
 
        return true;
 }
@@ -131,6 +148,12 @@ void Bluemonkey::reloadEngine()
        QJSValue value = engine->newQObject(this);
        engine->globalObject().setProperty("bluemonkey", value);
 
+       if(engine->evaluate(bmJS).isError())
+       {
+               qCritical() << "Failed to load bluemonkey javascript extensions";
+               return;
+       }
+
        ready();
 
        loadConfig(configuration["config"].c_str());
@@ -162,9 +185,9 @@ void Bluemonkey::writeProgram(QString program)
        file.close();
 }
 
-void Bluemonkey::log(QString str)
+void Bluemonkey::log(QJSValue str)
 {
-       qDebug()<< str;
+       qDebug()<< str.toString();
 }
 
 QObject *Bluemonkey::createTimer()
index 6aed204..ed607f4 100644 (file)
@@ -52,7 +52,7 @@ public Q_SLOTS:
 
        void writeProgram(QString program);
 
-       void log(QString str);
+       void log(QJSValue str);
 
        QObject* createTimer();
        QObject* createQObject();
index 3d88905..194d90a 100644 (file)
@@ -1,8 +1,9 @@
-bluemonkey.log("hello world!");
+console.log("hello world!");
 
 bluemonkey.loadModule("@PLUGIN_INSTALL_PATH@/bluemonkeyDbModule.so");
 bluemonkey.loadModule("@PLUGIN_INSTALL_PATH@/bluemonkeyDBusModule.so");
 bluemonkey.loadModule("@PLUGIN_INSTALL_PATH@/bluemonkeyBleModule.so");
+bluemonkey.loadModule("@PLUGIN_INSTALL_PATH@/bluemonkeyWsModule.so");
 
 exportObj = {};
 exportObj.foo = function() { return "bar"; }
@@ -10,50 +11,86 @@ exportObj.bar = true;
 
 if(dbus !== undefined)
 {
-       try
-       {
-               var dbusIface = dbus.createInterface("org.freedesktop.DBus", "/", "org.freedesktop.DBus", dbus.Session);
+    try
+    {
+        var dbusIface = dbus.createInterface("org.freedesktop.DBus", "/", "org.freedesktop.DBus", dbus.Session);
 
-               var reply = dbusIface.GetId();
+        var reply = dbusIface.GetId();
 
-               bluemonkey.log("org.freedesktop.DBus.GetId() response: " + reply);
+        console.log("org.freedesktop.DBus.GetId() response: " + reply);
 
-               var registered = dbus.registerService("org.bluemonkey", dbus.Session)
+        var registered = dbus.registerService("org.bluemonkey", dbus.Session)
 
-               bluemonkey.assertIsTrue(registered, "could not register service: " + dbus.errorMessage(dbus.Session));
+        bluemonkey.assertIsTrue(registered, "could not register service: " + dbus.errorMessage(dbus.Session));
 
-               /* TODO: Uncomment this when dbus export works
-               var exported = dbus.exportObject("/one", "org.awesome.interface", dbus.Session, exportObj);
-               bluemonkey.log("exported: " + exported)
+        /* TODO: Uncomment this when dbus export works
+        var exported = dbus.exportObject("/one", "org.awesome.interface", dbus.Session, exportObj);
+        console.log("exported: " + exported)
 
-               bluemonkey.assertIsTrue(exported, "Failed to export custom dbus object: " + dbus.errorMessage(dbus.Session));
+        bluemonkey.assertIsTrue(exported, "Failed to export custom dbus object: " + dbus.errorMessage(dbus.Session));
 
-               var exported2 = dbus.exportObject("/two", "org.awesome.interface2", dbus.Session, testExport)
-               bluemonkey.log("exported2: " + exported2)
+        var exported2 = dbus.exportObject("/two", "org.awesome.interface2", dbus.Session, testExport)
+        console.log("exported2: " + exported2)
 
-               bluemonkey.assertIsTrue(exported2, "failed to export testExport: " + dbus.errorMessage());*/
-       }
-       catch(error)
-       {
-               bluemonkey.log("nasty dbus errors");
-       }
+        bluemonkey.assertIsTrue(exported2, "failed to export testExport: " + dbus.errorMessage());*/
+    }
+    catch(error)
+    {
+        console.log("nasty dbus errors");
+    }
 }
 
 if(ble !== undefined)
 {
-       serviceUuid = "5faaf494-d4c6-483e-b592-d1a6ffd436c9";
-       device = ble.addService(serviceUuid, "5faaf495-d4c6-483e-b592-d1a6ffd436c9", "5faaf496-d4c6-483e-b592-d1a6ffd436c9");
-       ble.scanningChanged.connect(function ()
-       {
-               if(!ble.scan)
-               {
-                       bluemonkey.log("scan finished");
-               }
-       });
-
-       ble.scan = true;
-       ble.devicesChanged.connect(function ()
-       {
-               bluemonkey.log("devices that match the service uuid: " + ble.devices(serviceUuid))
-       });
+    serviceUuid = "5faaf494-d4c6-483e-b592-d1a6ffd436c9";
+    device = ble.addService(serviceUuid, "5faaf495-d4c6-483e-b592-d1a6ffd436c9", "5faaf496-d4c6-483e-b592-d1a6ffd436c9");
+    ble.scanningChanged.connect(function ()
+    {
+        if(!ble.scan)
+        {
+            console.log("scan finished");
+        }
+    });
+
+    ble.scan = true;
+    ble.devicesChanged.connect(function ()
+    {
+        console.log("devices that match the service uuid: " + ble.devices(serviceUuid))
+    });
+}
+
+var shndl
+
+if(websockets !== undefined)
+{
+    console.log("can has websockets!");
+
+    socket = new WebSocket("ws://echo.websocket.org");
+
+    socket.onmessage = function(msg)
+    {
+        console.log("msg: "+ msg);
+    };
+
+    socket.onopen = function()
+    {
+        console.log("opened!");
+        socket.send("ping");
+    };
+
+    socket.onclose = function()
+    {
+        console.log("closed");
+    };
+
+    socket.onerror = function(err)
+    {
+        console.log("error: " + err);
+    }
+
+    shndl = socket;
+}
+else
+{
+    console.log("no websocket support :(");
 }
diff --git a/plugins/bluemonkey/bmws.cpp b/plugins/bluemonkey/bmws.cpp
new file mode 100644 (file)
index 0000000..7a0e8d4
--- /dev/null
@@ -0,0 +1,182 @@
+#include "bmws.h"
+
+#include <map>
+#include <string>
+#include <QObject>
+#include <QString>
+#include <QtWebSockets/QWebSocket>
+#include <QtWebSockets/QWebSocketServer>
+
+#include <QCoreApplication>
+
+extern "C" void create(std::map<std::string, std::string> config, std::map<std::string, QObject*> &exports, QString &js, QObject* parent)
+{
+       exports["websockets"] = new Websockets(nullptr);
+
+       js.append("function WebSocket(url, protocols)"
+                         "{"
+                         "  this.client = websockets.createClient(url, protocols);"
+                         "  this._binaryType = 'blob';"
+                         "  Object.defineProperty(this, 'binaryType', { enumerable : false, get : function() { return this._binaryType; }, set : function (val)"
+                         "  {"
+                         "    if(val !=='blob' || val !== 'arraybuffer')"
+                         "      throw \"Invalid binaryType.  Must be 'blob' or 'arraybuffer'\";"
+                         "    this._binaryType = val;"
+                         "  } });"
+                         "  Object.defineProperty(this, 'bufferedAmount', { value : 0 });"
+                         "  Object.defineProperty(this, 'extensions', { value : ''});"
+                         "  Object.defineProperty(this, 'protocol', { value : ''});"
+                         "  Object.defineProperty(this, 'readyState', { enumberable : false, get : function ()"
+                         "  { "
+                         "    ready = this.client.readyState; "
+                         "    if(ready == -1)"
+                         "      return undefined;"
+                         "    return ready;"
+                         "  } });"
+                         "  Object.defineProperty(this, 'url', { get : function() { return this.client.url; }});"
+                         "  temporaryMe = this;"
+                         "  this.client.connected.connect(function()"
+                         "  {"
+                         "    if(temporaryMe.onopen !== undefined)"
+                         "      temporaryMe.onopen();"
+                         "    else"
+                         "      console.log('onopen is like, totally undefined');"
+                         "  });"
+                         ""
+                         "  this.client.disconnected.connect(function()"
+                         "  {"
+                         "    if(temporaryMe.onclose !== undefined)"
+                         "      temporaryMe.onclose()"
+                         "  });"
+                         ""
+                         "  this.client.error.connect(function(err)"
+                         "  {"
+                         "    if(temporaryMe.onerror !== undefined)"
+                         "      temporaryMe.onerror(temporaryMe.client.getErrorString());"
+                         "  });"
+                         ""
+                         "  this.client.textMessageReceived.connect(function(msg)"
+                         "  {"
+                         "    if(temporaryMe.onmessage !== undefined)"
+                         "    {"
+                         "      temporaryMe._binaryType = 'blob';"
+                         "      temporaryMe.onmessage(msg);"
+                         "    }"
+                         "  });"
+                         ""
+                         "  this.client.binaryMessageReceived.connect(function(msg)"
+                         "  {"
+                         "    if(temporaryMe.onmessage !== undefined)"
+                         "    {"
+                         "      temporaryMe._binaryType = 'arraybuffer';"
+                         "      temporaryMe.onmessage(msg);"
+                         "    }"
+                         "  });"
+                         "}"
+                         ""
+                         "WebSocket.prototype.send = function(msg)"
+                         "{"
+                         "  if(this._binaryType === 'blob')"
+                         "    this.client._sendTextMessage(msg);"
+                         "  else if(this._binaryType === 'arraybuffer')"
+                         "    this.client._sendBinaryMessage(msg);"
+                         "};"
+                         ""
+                         "WebSocket.prototype.close = function() { this.client.close(); };"
+                         "");
+
+}
+
+
+
+
+Websockets::Websockets(QObject *parent)
+       :QObject(parent)
+{
+
+}
+
+QObject *Websockets::createClient(const QString &url, const QStringList &protocols)
+{
+       return new WebsocketClient(url, nullptr);
+}
+
+QObject *Websockets::createServer()
+{
+
+}
+
+
+WebsocketClient::WebsocketClient(const QString &url, QObject *parent)
+       :QWebSocket(QString(), QWebSocketProtocol::VersionLatest, parent), mUrl(url)
+{
+       qDebug() << "Constructed websocket client";
+
+       connect(this, &WebsocketClient::connected, []()
+       {
+               qDebug() << "connected";
+       });
+
+       connect(this, &WebsocketClient::disconnected, []()
+       {
+               qDebug() << "disconnected";
+       });
+
+       connect(this, &WebsocketClient::stateChanged, [](QAbstractSocket::SocketState state)
+       {
+               qDebug() << "state changed: " << state;
+       });
+
+       open(QUrl(url));
+}
+
+int WebsocketClient::readyState()
+{
+       if(state() == QAbstractSocket::UnconnectedState)
+       {
+               return 3;
+       }
+       else if(state() == QAbstractSocket::ConnectingState)
+       {
+               return 0;
+       }
+       else if(state() == QAbstractSocket::ClosingState)
+       {
+               return 2;
+       }
+       else if(state() == QAbstractSocket::ConnectedState)
+       {
+               return 1;
+       }
+       return -1;
+}
+
+int main(int argc, char** argv)
+{
+       QCoreApplication app(argc, argv);
+       WebsocketClient client("ws://echo.websocket.org");
+
+       QObject::connect(&client, &WebsocketClient::connected, [&client]()
+       {
+               qDebug() << "Can has connection!";
+
+               client.sendTextMessage("Hello world!");
+       });
+
+       QObject::connect(&client, &WebsocketClient::textMessageReceived, [](const QString & msg)
+       {
+               qDebug() << "Can has message: " << msg;
+       });
+
+       /*QObject::connect(&client, &WebsocketClient::error, [&client](QAbstractSocket::SocketError)
+       {
+               qDebug() << "Error: " << client.errorString();
+       });*/
+
+       QObject::connect(&client, &WebsocketClient::disconnected, []()
+       {
+               qDebug() << "has disconnected :(";
+       });
+
+       return app.exec();
+}
diff --git a/plugins/bluemonkey/bmws.h b/plugins/bluemonkey/bmws.h
new file mode 100644 (file)
index 0000000..90b2d02
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef BM_WS_H_
+#define BM_WS_H_
+
+#include <QObject>
+#include <QtWebSockets/QWebSocket>
+
+class Websockets : public QObject
+{
+       Q_OBJECT
+public:
+       Websockets(QObject* parent = nullptr);
+
+public Q_SLOTS:
+       QObject * createClient(const QString & url, const QStringList  &protocols);
+       QObject * createServer();
+};
+
+class WebsocketClient : public QWebSocket
+{
+       Q_OBJECT
+       Q_PROPERTY(int readyState READ readyState)
+       Q_PROPERTY(QString url READ getUrl)
+public:
+       WebsocketClient(const QString & url, QObject* parent = nullptr);
+
+       int readyState();
+       QString getUrl() { return mUrl; }
+
+public Q_SLOTS:
+
+       QString getErrorString() { return errorString(); }
+       void _sendTextMessage(const QString & msg) { sendTextMessage(msg); }
+       void _sendBinaryMessage(const QByteArray & msg) { sendBinaryMessage(msg); }
+
+private:
+       QString mUrl;
+};
+
+#endif
index ec14a9c..3ed9c09 100644 (file)
@@ -8,309 +8,309 @@ var async_calls = {};
 var subscriptions = [];
 
 function makeCall(call, msg) {
-       async_calls[next_async_call_id] = call;
-       msg.asyncCallId = next_async_call_id;
-       ++next_async_call_id;
+    async_calls[next_async_call_id] = call;
+    msg.asyncCallId = next_async_call_id;
+    ++next_async_call_id;
 
-       extension.postMessage(JSON.stringify(msg));
+    extension.postMessage(JSON.stringify(msg));
 }
 
 function vehicleInterfaceCommonContructor(obj, attname) {
-       obj.attributeName = attname;
+    obj.attributeName = attname;
 
-       var msg = {};
-       msg['method'] = 'zones';
-       msg['name'] = obj.attributeName;
+    var msg = {};
+    msg['method'] = 'zones';
+    msg['name'] = obj.attributeName;
 
-       obj._zones = new Zone;
-       obj._supported = false;
+    obj._zones = new Zone;
+    obj._supported = false;
 
-       var call = new AsyncCall(function(data) {
-               obj._zones = data;
-       });
+    var call = new AsyncCall(function(data) {
+        obj._zones = data;
+    });
 
-       makeCall(call, msg);
+    makeCall(call, msg);
 
-       var supportedMessage = {};
-       supportedMessage['method'] = 'supported';
-       supportedMessage['name'] = obj.attributeName;
+    var supportedMessage = {};
+    supportedMessage['method'] = 'supported';
+    supportedMessage['name'] = obj.attributeName;
 
-       var supportedCall = new AsyncCall(function(data) {
-               obj._supported = data;
-       });
+    var supportedCall = new AsyncCall(function(data) {
+        obj._supported = data;
+    });
 
-       makeCall(supportedCall, supportedMessage);
+    makeCall(supportedCall, supportedMessage);
 
-       Object.defineProperty(obj, 'zones', { get: function() { return obj._zones } });
-       Object.defineProperty(obj, 'supported', { get: function() { return obj._supported; } });
+    Object.defineProperty(obj, 'zones', { get: function() { return obj._zones } });
+    Object.defineProperty(obj, 'supported', { get: function() { return obj._supported; } });
 }
 
 function VehicleInterface(attname) {
-       vehicleInterfaceCommonContructor(this, attname);
+    vehicleInterfaceCommonContructor(this, attname);
 }
 
 VehicleInterface.prototype.get = function(zone) {
-       var msg = {};
-       msg['method'] = 'get';
-       msg['name'] = this.attributeName;
-       msg['zone'] = zone;
+    var msg = {};
+    msg['method'] = 'get';
+    msg['name'] = this.attributeName;
+    msg['zone'] = zone;
 
-       return createPromise(msg);
+    return createPromise(msg);
 };
 
 VehicleInterface.prototype.availableForRetrieval = function(attName) {
-       return isAvailable(this, attName);
-}
+    return isAvailable(this, attName);
+};
 
 VehicleInterface.prototype.availabilityChangedListener = function(callback) {
-       if(this.changedListenerCount) {
-               this.changedListenerCount++;
-       }
-       else {
-               this.changedListenerCount = 0;
-       }
-       return this.changedListenerCount;
-}
+    if(this.changedListenerCount) {
+        this.changedListenerCount++;
+    }
+    else {
+        this.changedListenerCount = 0;
+    }
+    return this.changedListenerCount;
+};
 
 VehicleInterface.prototype.removeAvailabilityChangedListener = function(handle) {
 
-}
+};
 
 function VehicleSignalInterface(attname) {
-       vehicleInterfaceCommonContructor(this, attname);
+    vehicleInterfaceCommonContructor(this, attname);
 }
 
 VehicleSignalInterface.prototype = VehicleInterface.prototype;
 
 VehicleSignalInterface.prototype.subscribe = function(callback, zone) {
-       if (!zone) zone = new Zone();
+    if (!zone) zone = new Zone();
 
-       var msg = {};
-       msg['method'] = 'subscribe';
-       msg['name'] = this.attributeName;
-       msg['zone'] = zone;
+    var msg = {};
+    msg['method'] = 'subscribe';
+    msg['name'] = this.attributeName;
+    msg['zone'] = zone;
 
-       extension.postMessage(JSON.stringify(msg));
+    extension.postMessage(JSON.stringify(msg));
 
-       msg['callback'] = callback;
+    msg['callback'] = callback;
 
-       subscriptions.push(msg);
+    subscriptions.push(msg);
 
-       return subscriptions.length - 1;
+    return subscriptions.length - 1;
 };
 
 VehicleSignalInterface.prototype.unsubscribe = function(handle) {
-       var obj = subscriptions[handle];
-       subscriptions.splice(handle, 1);
+    var obj = subscriptions[handle];
+    subscriptions.splice(handle, 1);
 
-       var unsubscribe = true;
+    var unsubscribe = true;
 
-       for (var i = 0; i < subscriptions.length; i++) {
-               var testObj = subscriptions[i];
+    for (var i = 0; i < subscriptions.length; i++) {
+        var testObj = subscriptions[i];
 
-               if (testObj.name === obj.name && testObj.zone.equals(obj.zone)) {
-                       unsubscribe = false;
-                       break;
-               }
-       }
+        if (testObj.name === obj.name && testObj.zone.equals(obj.zone)) {
+            unsubscribe = false;
+            break;
+        }
+    }
 
-       if (unsubscribe) {
-               var msg = {};
-               msg['method'] = 'unsubscribe';
-               msg['name'] = this.attributeName;
-               msg['zone'] = obj.zone;
+    if (unsubscribe) {
+        var msg = {};
+        msg['method'] = 'unsubscribe';
+        msg['name'] = this.attributeName;
+        msg['zone'] = obj.zone;
 
-               extension.postMessage(JSON.stringify(msg));
-       }
+        extension.postMessage(JSON.stringify(msg));
+    }
 };
 
 VehicleSignalInterface.prototype.set = function (value, zone) {
-       var msg = {};
-       msg['method'] = 'set';
-       msg['name'] = this.attributeName;
-       msg['zone'] = zone;
-       msg['value'] = value;
+    var msg = {};
+    msg['method'] = 'set';
+    msg['name'] = this.attributeName;
+    msg['zone'] = zone;
+    msg['value'] = value;
 
-       return createPromise(msg);
-}
+    return createPromise(msg);
+};
 
 VehicleSignalInterface.prototype.availableForSubscription = function(attName) {
-       return isAvailable(this, attName);
-}
+    return isAvailable(this, attName);
+};
 
 VehicleSignalInterface.prototype.availableForSetting = function(attName) {
-       return isAvailable(this, attName);
-}
+    return isAvailable(this, attName);
+};
 
 function isAvailable(obj, attName)
 {
-       var msg = {};
-       msg["method"] = 'availableForRetrieval';
-       msg["name"] = obj.attributeName;
-       msg["attName"] = attName;
-
-       var reply = extension.internal.sendSyncMessage(JSON.stringify(msg));
-
-       if (reply === "true") {
-               return "available";
-       } else {
-               return "not_supported";
-       }
+    var msg = {};
+    msg["method"] = 'availableForRetrieval';
+    msg["name"] = obj.attributeName;
+    msg["attName"] = attName;
+
+    var reply = extension.internal.sendSyncMessage(JSON.stringify(msg));
+
+    if (reply === "true") {
+        return "available";
+    } else {
+        return "not_supported";
+    }
 }
 
 function AsyncCall(resolve, reject) {
-       this.resolve = resolve;
-       this.reject = reject;
+    this.resolve = resolve;
+    this.reject = reject;
 }
 
 function createPromise(msg) {
-       var promise = new Promise(function(resolve, reject) {
-               async_calls[next_async_call_id] = new AsyncCall(resolve, reject);
-       });
+    var promise = new Promise(function(resolve, reject) {
+        async_calls[next_async_call_id] = new AsyncCall(resolve, reject);
+    });
 
-       msg.asyncCallId = next_async_call_id;
-       extension.postMessage(JSON.stringify(msg));
-       ++next_async_call_id;
+    msg.asyncCallId = next_async_call_id;
+    extension.postMessage(JSON.stringify(msg));
+    ++next_async_call_id;
 
-       return promise;
+    return promise;
 }
 
 window.Zone = function(zone) {
-       this.value = zone ? zone : [];
+    this.value = zone ? zone : [];
 
-       Object.defineProperty(this, 'driver',
-                                                 { enumerable: false, get: function() {
-                                                         return new Zone(['Front', 'Left']);
-                                                 } });
+    Object.defineProperty(this, 'driver',
+                          { enumerable: false, get: function() {
+                              return new Zone(['Front', 'Left']);
+                          } });
 };
 
 window.Zone.prototype.equals = function(zone) {
-       var is_equal = true;
+    var is_equal = true;
 
-       for (var i = 0; i < zone.value.length; i++) {
-               is_equal = is_equal && this.value.indexOf(zone.value[i]) !== -1;
-       }
+    for (var i = 0; i < zone.value.length; i++) {
+        is_equal = is_equal && this.value.indexOf(zone.value[i]) !== -1;
+    }
 
-       for (var i = 0; i < this.value.length; i++) {
-               is_equal = is_equal && zone.value.indexOf(this.value[i]) !== -1;
-       }
+    for (var i = 0; i < this.value.length; i++) {
+        is_equal = is_equal && zone.value.indexOf(this.value[i]) !== -1;
+    }
 
-       return is_equal;
+    return is_equal;
 };
 
 function _defineVehicleProperty(obj, prop) {
-       Object.defineProperty(obj, prop, { enumerable: true, value: new VehicleInterface(prop) });
+    Object.defineProperty(obj, prop, { enumerable: true, value: new VehicleInterface(prop) });
 }
 
 function _defineVehicleSignalProperty(obj, prop) {
-       Object.defineProperty(obj, prop, { enumerable: true, value: new VehicleSignalInterface(prop) });
+    Object.defineProperty(obj, prop, { enumerable: true, value: new VehicleSignalInterface(prop) });
 }
 
 extension.setMessageListener(function(json) {
-       try {
-               var msg = JSON.parse(json);
-
-               switch (msg.method) {
-               case 'get':
-                       handlePromiseReply(msg);
-                       break;
-               case 'zones':
-                       handleZonesReply(msg);
-                       break;
-               case 'subscribe':
-                       handleSubscribeReply(msg);
-                       break;
-               case 'set':
-                       handlePromiseReply(msg);
-                       break;
-               case 'supported':
-                       handleSupportedReply(msg)
-                       break;
-               case 'vehicleSupportedAttributes':
-                       handleVehicleSupported(msg);
-                       break;
-               default:
-                       break;
-               }
-       } catch (error) {
-               console.log('Error in message listener: ' + error);
-               console.log("msg: " + JSON.stringify(msg))
-       }
+    try {
+        var msg = JSON.parse(json);
+
+        switch (msg.method) {
+        case 'get':
+            handlePromiseReply(msg);
+            break;
+        case 'zones':
+            handleZonesReply(msg);
+            break;
+        case 'subscribe':
+            handleSubscribeReply(msg);
+            break;
+        case 'set':
+            handlePromiseReply(msg);
+            break;
+        case 'supported':
+            handleSupportedReply(msg)
+            break;
+        case 'vehicleSupportedAttributes':
+            handleVehicleSupported(msg);
+            break;
+        default:
+            break;
+        }
+    } catch (error) {
+        console.log('Error in message listener: ' + error);
+        console.log("msg: " + JSON.stringify(msg))
+    }
 });
 
 function handlePromiseReply(msg) {
-       var cbobj = async_calls[msg.asyncCallId];
-
-       if (msg.error) {
-               var error = {};
-               error.error = msg.value;
-               switch (msg.value) {
-               case 'permission_denied':
-                       error.message = 'Permission denied';
-                       break;
-               case 'invalid_operation':
-                       error.message = 'Invalid operation';
-                       break;
-               case 'timeout':
-                       error.message = 'Operation timed out';
-                       break;
-               case 'invalid_zone':
-                       error.message = 'Zone invalid or not found';
-                       break;
-               case 'unknown':
-                       error.message = 'An unknown error occured';
-                       break;
-               default:
-                       error.message = 'Unknown';
-                       break;
-               }
-
-               cbobj.reject(error);
-       } else {
-               if (msg.value && msg.value.zone) {
-                       msg.value.zone = new Zone(msg.value.zone);
-               }
-               cbobj.resolve(msg.value);
-       }
-
-       delete async_calls[msg.asyncCallId];
+    var cbobj = async_calls[msg.asyncCallId];
+
+    if (msg.error) {
+        var error = {};
+        error.error = msg.value;
+        switch (msg.value) {
+        case 'permission_denied':
+            error.message = 'Permission denied';
+            break;
+        case 'invalid_operation':
+            error.message = 'Invalid operation';
+            break;
+        case 'timeout':
+            error.message = 'Operation timed out';
+            break;
+        case 'invalid_zone':
+            error.message = 'Zone invalid or not found';
+            break;
+        case 'unknown':
+            error.message = 'An unknown error occured';
+            break;
+        default:
+            error.message = 'Unknown';
+            break;
+        }
+
+        cbobj.reject(error);
+    } else {
+        if (msg.value && msg.value.zone) {
+            msg.value.zone = new Zone(msg.value.zone);
+        }
+        cbobj.resolve(msg.value);
+    }
+
+    delete async_calls[msg.asyncCallId];
 }
 
 function handleZonesReply(msg) {
-       var cbobj = async_calls[msg.asyncCallId];
+    var cbobj = async_calls[msg.asyncCallId];
 
-       if (cbobj)
-               cbobj.resolve(new Zone(msg.value));
+    if (cbobj)
+        cbobj.resolve(new Zone(msg.value));
 }
 
 function handleSupportedReply(msg) {
-       var cbobj = async_calls[msg.asyncCallId];
+    var cbobj = async_calls[msg.asyncCallId];
 
-       if (cbobj)
-               cbobj.resolve(msg.value);
+    if (cbobj)
+        cbobj.resolve(msg.value);
 }
 
 function handleSubscribeReply(msg) {
-       delete async_calls[msg.asyncCallId];
-       var value = msg.value;
-       value.zone = new Zone(value.zone);
-
-       for (var i = 0; i < subscriptions.length; i++) {
-               var itr = subscriptions[i];
-               var ifaceIs = (value.interfaceName.toLowerCase() === itr.name.toLowerCase());
-               if (ifaceIs === true && value.zone.equals(itr.zone)) {
-                       itr.callback(value);
-               }
-       }
+    delete async_calls[msg.asyncCallId];
+    var value = msg.value;
+    value.zone = new Zone(value.zone);
+
+    for (var i = 0; i < subscriptions.length; i++) {
+        var itr = subscriptions[i];
+        var ifaceIs = (value.interfaceName.toLowerCase() === itr.name.toLowerCase());
+        if (ifaceIs === true && value.zone.equals(itr.zone)) {
+            itr.callback(value);
+        }
+    }
 }
 
 function handleVehicleSupported(msg) {
-       var value = msg.value;
-       for(i in value) {
-               if(exports[i] !== undefined) {
-                       _defineVehicleSignalProperty(exports, i);
-               }
-       }
+    var value = msg.value;
+    for(i in value) {
+        if(exports[i] !== undefined) {
+            _defineVehicleSignalProperty(exports, i);
+        }
+    }
 }
 
 /// Runningstatus attributes: