[bluemonkey] websocket server implemented
authorKevron Rees <kevron.m.rees@intel.com>
Thu, 19 Feb 2015 23:12:38 +0000 (15:12 -0800)
committerKevron Rees <kevron.m.rees@intel.com>
Thu, 19 Feb 2015 23:12:38 +0000 (15:12 -0800)
15 files changed:
README.md
plugins/bluemonkey/CMakeLists.txt
plugins/bluemonkey/amb.cpp
plugins/bluemonkey/ble.cpp
plugins/bluemonkey/bluemonkey.cpp
plugins/bluemonkey/bluemonkey.h
plugins/bluemonkey/bluemonkeynode.cpp
plugins/bluemonkey/bmconfig.js [changed mode: 0644->0755]
plugins/bluemonkey/bmdbus.cpp
plugins/bluemonkey/bmws.cpp
plugins/bluemonkey/bmws.h
plugins/bluemonkey/bmws.js [new file with mode: 0644]
tools/CMakeLists.txt
tools/generate_api.py [moved from xwalk/generate_api.py with 100% similarity]
xwalk/CMakeLists.txt

index 5f35649..f3373a6 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/x86_64-linux-gnu/automotive-message-broker/qtmainloopplugin.so",
+       "mainloop" : "/usr/lib/i386-linux-gnu/automotive-message-broker/qtmainloopplugin.so",
        "plugins" : "/etc/ambd/plugins.d"
 }
 ~~~~~~~~~~~~~
index 62b7a09..61f6cd0 100644 (file)
@@ -25,12 +25,17 @@ set(CMAKE_AUTOMOC ON)
 find_package(Qt5WebSockets QUIET)
 if(Qt5WebSockets_FOUND)
        message(STATUS "enabling bluemonkey websocket module")
-       add_executable(bluemonkeyWsModule bmws.cpp)
+       add_executable(bluemonkeyWsModule bmws.cpp ${CMAKE_CURRENT_BINARY_DIR}/bmws_api.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})
+       configure_file(${CMAKE_CURRENT_SOURCE_DIR}/bmws.js ${CMAKE_CURRENT_SOURCE_DIR}/bmws.js @ONLY)
+       add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/bmws_api.cpp
+                                  COMMAND python ${CMAKE_SOURCE_DIR}/tools/generate_api.py ${CMAKE_CURRENT_SOURCE_DIR}/bmws.js bmws_api ${CMAKE_CURRENT_BINARY_DIR}/bmws_api.cpp )
+       add_custom_target(bmwsjs2cpp DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/bmws_api.cpp)
+       add_dependencies(bluemonkeyWsModule bmwsjs2cpp)
 endif()
 
 find_library(communi NAMES Communi)
index beaa98e..ffba26a 100644 (file)
@@ -126,7 +126,7 @@ public:
 BluemonkeySink::BluemonkeySink(AbstractRoutingEngine* e, map<string, string> config, AbstractSource &parent)
        : QObject(0), AmbPluginImpl(e, config, parent), mSilentMode(false)
 {
-       bluemonkey = new Bluemonkey(config, this);
+       bluemonkey = new Bluemonkey(this);
        auth = new Authenticate(config, this);
 }
 
@@ -136,7 +136,11 @@ BluemonkeySink::~BluemonkeySink()
 
 void BluemonkeySink::init()
 {
-       connect(bluemonkey, &Bluemonkey::ready,[this](){bluemonkey->loadModule("amb", this);});
+       connect(bluemonkey, &Bluemonkey::ready,[this]()
+       {
+               bluemonkey->loadModule("amb", this);
+               bluemonkey->loadScript(configuration["config"].c_str());
+       });
 }
 
 
index afd5fc6..b6b836c 100644 (file)
@@ -70,7 +70,6 @@ void Ble::addService(const QString &serviceUuid, const QString &rxUuid, const QS
 
 void Ble::startScan(bool scan)
 {
-       qDebug() << "Scanning: " << (scan ? "true":"false");
        scan ? mDeviceDiscoveryAgent->start() : mDeviceDiscoveryAgent->stop();
 }
 
@@ -83,14 +82,14 @@ void Ble::deviceDiscovered(const QBluetoothDeviceInfo &device)
 {
        if(device.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration)
        {
-               qDebug() << "BLE device found: " << device.address().toString();
+               //qDebug() << "BLE device found: " << device.address().toString();
 
                ///We have a device.  Let's scan to see if it supports the service Uuid's we want
                auto control = new QLowEnergyController(device.address(), this);
 
                connect(control, &QLowEnergyController::stateChanged, [control, this](QLowEnergyController::ControllerState state)
                {
-                       qDebug() << "Controller state changed for device: " << control->remoteAddress().toString() << state;
+                       //qDebug() << "Controller state changed for device: " << control->remoteAddress().toString() << state;
                        if(state == QLowEnergyController::DiscoveredState)
                        {
                                devicesChanged();
@@ -99,14 +98,14 @@ void Ble::deviceDiscovered(const QBluetoothDeviceInfo &device)
                connect(control, &QLowEnergyController::disconnected, control, &QLowEnergyController::deleteLater); // if we disconnect, clean up.
                connect(control, &QLowEnergyController::connected, [&control]()
                {
-                       qDebug() << "Device connected. Discovering services...";
+                       //qDebug() << "Device connected. Discovering services...";
                        control->discoverServices();
                });
                connect(control, &QLowEnergyController::serviceDiscovered, [&control, this, device](const QBluetoothUuid & uuid)
                {
                        Q_FOREACH(ServiceIdentifier * service, services)
                        {
-                               qDebug() << "checking if service uuid (" << uuid.toString() << ") matches the one we want (" << service->serviceUuid << ")";
+                               //qDebug() << "checking if service uuid (" << uuid.toString() << ") matches the one we want (" << service->serviceUuid << ")";
                                if(service->serviceUuid == uuid.toString())
                                {
                                        service->service = control->createServiceObject(uuid, service);
@@ -115,7 +114,7 @@ void Ble::deviceDiscovered(const QBluetoothDeviceInfo &device)
 
                                        if(!service->service)
                                        {
-                                               qDebug() << "Could not get service object on device with address: " << control->remoteAddress().toString();
+                                               qWarning() << "Could not get service object on device with address: " << control->remoteAddress().toString();
                                                return;
                                        }
 
@@ -127,9 +126,9 @@ void Ble::deviceDiscovered(const QBluetoothDeviceInfo &device)
 
                                                        if(!rx.isValid())
                                                        {
-                                                               qDebug() << "rx characteristic not found in service.";
-                                                               qDebug() << "Characteristic: " << service->rxUuid;
-                                                               qDebug() << "Service: " << service->serviceUuid;
+                                                               qWarning() << "rx characteristic not found in service.";
+                                                               qWarning() << "Characteristic: " << service->rxUuid;
+                                                               qWarning() << "Service: " << service->serviceUuid;
                                                                service->isValid = false;
                                                                return;
                                                        }
@@ -138,9 +137,9 @@ void Ble::deviceDiscovered(const QBluetoothDeviceInfo &device)
 
                                                        if(!tx.isValid())
                                                        {
-                                                               qDebug() << "rx characteristic not found in service.";
-                                                               qDebug() << "Characteristic: " << service->rxUuid;
-                                                               qDebug() << "Service: " << service->serviceUuid;
+                                                               qWarning() << "rx characteristic not found in service.";
+                                                               qWarning() << "Characteristic: " << service->rxUuid;
+                                                               qWarning() << "Service: " << service->serviceUuid;
                                                                service->isValid = false;
                                                                return;
                                                        }
@@ -151,7 +150,6 @@ void Ble::deviceDiscovered(const QBluetoothDeviceInfo &device)
                                }
                        }
                });
-               qDebug() << "attempting to connect to device: " << device.address().toString();
                control->connectToDevice();
        }
 }
index 01b7375..17fd64b 100644 (file)
@@ -39,13 +39,64 @@ QString bmJS = (""
                                "{"
                                "  bluemonkey.log(msg);"
                                "}"
-                               "");
+                               ""
+                               "function Application(args)"
+                               "{"
+                               "  this.app = bluemonkey.createCoreApplication();"
+                               "  bluemonkey.assertIsTrue(this.app !== undefined, 'Need to instantiate QCoreApplication in the bluemonkey app before calling createCoreApplication()');"
+                               "  this._connectEverything(this);"
+                               ""
+                               "  this.startTimer = bluemonkey.createTimer();"
+                               "  this.startTimer.singleShot = true;"
+                               "  this.startTimer.timeout.connect(bluemonkey.ready);"
+                               "  this.startTimer.start(1);"
+                               "}"
+                               "Application.prototype._connectEverything = function(obj)"
+                               "{"
+                               "  bluemonkey.ready.connect(function()"
+                               "  {"
+                               "    if(obj.main !== undefined)"
+                               "      obj.main();"
+                               "  });"
+                               "};"
+                               "Application.prototype.run = function()"
+                               "{"
+                               "  return bluemonkey.run(this.app);"
+                               "};");
 
 
-Bluemonkey::Bluemonkey(std::map<std::string, std::string> config, QObject *parent)
-       :QObject(parent), engine(nullptr), configuration(config)
+Bluemonkey::Bluemonkey(QObject *parent)
+       :QObject(parent), engine(nullptr), configuration(std::map<std::string, std::string>())
 {
-       QTimer::singleShot(1,this,SLOT(reloadEngine()));
+       engine = new QJSEngine(this);
+
+       QJSValue value = engine->newQObject(this);
+       engine->globalObject().setProperty("bluemonkey", value);
+
+       QJSValue val = engine->evaluate(bmJS);
+
+       if(val.isError())
+       {
+               qCritical() << "Failed to load bluemonkey javascript extensions";
+               qCritical() << "Error: ";
+               qCritical() <<  val.property("name").toString();
+               qCritical() <<  val.property("message").toString();
+               qCritical() << "line: " << val.property("lineNumber").toString();
+
+               int line = val.property("lineNumber").toInt();
+               QStringList lines = bmJS.split("\n");
+
+               if(line - 1 >= 0)
+                       qWarning() << lines.at(line-1);
+
+               qWarning() << lines.at(line) << "<--";
+
+               if(lines.size() > line + 1)
+                       qWarning() << lines.at(line+1);
+
+               qCritical() << "Aborting";
+               throw std::runtime_error("Die die die");
+       }
 }
 
 Bluemonkey::~Bluemonkey()
@@ -58,7 +109,7 @@ Bluemonkey::~Bluemonkey()
        engine->deleteLater();
 }
 
-void Bluemonkey::loadConfig(QString str)
+void Bluemonkey::loadScript(QString str)
 {
        QFile file(str);
        if(!file.open(QIODevice::ReadOnly))
@@ -67,21 +118,36 @@ void Bluemonkey::loadConfig(QString str)
                return;
        }
 
-       QString script = file.readAll();
+       QString firstLine = file.readLine();
 
-       file.close();
+       if(firstLine.startsWith("#!"))
+               firstLine = "";
 
-       qDebug() << "evaluating script: "<< script;
+       QString script = firstLine + "\n" + file.readAll();
 
-       QJSValue val = engine->evaluate(script);
+       file.close();
 
-       qDebug()<< val.toString();
+       QJSValue val = engine->evaluate(script);
 
        if(val.isError())
        {
-               qDebug() <<  val.property("name").toString() <<  endl;
-               qDebug() <<  val.property("message").toString() <<  endl;
-               qDebug() <<  str <<  ":" << val.property("lineNumber").toString() <<  endl;
+               qDebug() << "Error: ";
+               qDebug() <<  val.property("name").toString();
+               qDebug() <<  val.property("message").toString();
+               qDebug() <<  str <<  ":" << val.property("lineNumber").toString();
+
+               int line = val.property("lineNumber").toInt();
+               QStringList lines = script.split("\n");
+
+               if(line - 1 >= 0)
+                       qWarning() << lines.at(line-1);
+
+               qWarning() << lines.at(line) << "<--";
+
+               if(lines.size() > line + 1)
+                       qWarning() << lines.at(line+1);
+
+               throw std::runtime_error("JavaScript Error");
        }
 }
 
@@ -117,7 +183,7 @@ bool Bluemonkey::loadModule(QString path)
 
        std::map<std::string, QObject*> exports;
        QString js;
-       create(configuration, exports, js, nullptr);
+       create(configuration, exports, js, this);
 
        for(auto i : exports)
        {
@@ -127,37 +193,29 @@ bool Bluemonkey::loadModule(QString path)
 
        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();
-       }
+               qWarning() << "Error running script in module: " << path;
+               qWarning() <<  val.property("name").toString();
+               qWarning() <<  val.property("message").toString();
+               qWarning() << "line: " << val.property("lineNumber").toString();
 
-       return true;
-}
+               int line = val.property("lineNumber").toInt();
+               QStringList lines = js.split("\n");
 
-void Bluemonkey::reloadEngine()
-{
-       if(engine)
-               engine->deleteLater();
+               if(line - 1 >= 0)
+                       qWarning() << lines.at(line-1);
 
-       engine = new QJSEngine();
+               qWarning() << lines.at(line) << "<--";
 
-       QJSValue value = engine->newQObject(this);
-       engine->globalObject().setProperty("bluemonkey", value);
+               if(lines.size() > line + 1)
+                       qWarning() << lines.at(line+1);
 
-       if(engine->evaluate(bmJS).isError())
-       {
-               qCritical() << "Failed to load bluemonkey javascript extensions";
-               return;
+               qCritical() << "Aborting";
+               throw std::runtime_error("Failed to load module");
        }
 
-       ready();
-
-       loadConfig(configuration["config"].c_str());
-
+       return true;
 }
 
 void Bluemonkey::writeProgram(QString program)
@@ -200,6 +258,11 @@ QObject *Bluemonkey::createQObject()
        return new QObject(this);
 }
 
+QObject *Bluemonkey::createCoreApplication()
+{
+       return QCoreApplication::instance();
+}
+
 
 bool Bluemonkey::loadModule(const QString &name, QObject *module)
 {
@@ -210,6 +273,16 @@ bool Bluemonkey::loadModule(const QString &name, QObject *module)
        }
 }
 
+void Bluemonkey::setArguments(int len, char **args)
+{
+       QStringList a;
+       for(int i = 0; i < len; i++)
+       {
+               a.append(args[i]);
+       }
+
+       setArguments(a);
+}
 
 void Bluemonkey::assertIsTrue(bool isTrue, const QString & msg)
 {
@@ -218,3 +291,9 @@ void Bluemonkey::assertIsTrue(bool isTrue, const QString & msg)
 
        Q_ASSERT(isTrue);
 }
+
+
+int Bluemonkey::run(QCoreApplication *app)
+{
+       return app->exec();
+}
index ed607f4..d788122 100644 (file)
@@ -27,6 +27,7 @@
 #include <QJsonDocument>
 #include <QDateTime>
 #include <QJSValue>
+#include <QCoreApplication>
 
 #include "authenticate.h"
 
@@ -35,21 +36,27 @@ class QJSEngine;
 class Bluemonkey : public QObject
 {
        Q_OBJECT
+       Q_PROPERTY(QStringList arguments READ arguments)
+
 public:
-       Bluemonkey(std::map<std::string, std::string> config = std::map<std::string, std::string>(), QObject* parent = nullptr);
+       Bluemonkey(QObject * parent = nullptr);
+
        ~Bluemonkey();
 
        bool loadModule(const QString &name, QObject* module);
 
+       QStringList arguments() { return mArguments;}
+       void setArguments(const QStringList & args) { mArguments = args; }
+       void setArguments(int len, char **args);
+
 public Q_SLOTS:
+
        void assertIsTrue(bool isTrue, const QString &msg="");
 
-       void loadConfig(QString str);
+       void loadScript(QString str);
 
        bool loadModule(QString path);
 
-       void reloadEngine();
-
        void writeProgram(QString program);
 
        void log(QJSValue str);
@@ -57,6 +64,10 @@ public Q_SLOTS:
        QObject* createTimer();
        QObject* createQObject();
 
+       QObject* createCoreApplication();
+
+       int run(QCoreApplication *app);
+
 Q_SIGNALS:
 
        void ready();
@@ -65,6 +76,7 @@ private:
        QList<void*> modules;
        QJSEngine* engine;
        QStringList configsToLoad;
+       QStringList mArguments;
        std::map<std::string, std::string> configuration;
 };
 
index e4df302..06668b1 100644 (file)
@@ -6,21 +6,17 @@
 int main(int argc, char ** argv)
 {
        QCoreApplication app(argc, argv);
-
-       if(app.arguments().count() < 2)
+       if(argc < 2)
        {
-               qDebug() << "Error: must run with path to file.js";
-               qDebug() << "ie: " << app.applicationName() << " /path/to/file.js";
+               qCritical() << "usage: bluemonkey <path/to/script>";
                return -1;
        }
 
-       std::string path = app.arguments().at(1).toStdString();
-
-       std::map<std::string, std::string> config;
-
-       config["config"] = path;
+       Bluemonkey bluemonkey;
 
-       Bluemonkey bluemonkey(config);
+       bluemonkey.setArguments(argc, argv);
+       QString path = bluemonkey.arguments().at(1);
+       bluemonkey.loadScript(path);
 
-       app.exec();
+       return 0;
 }
old mode 100644 (file)
new mode 100755 (executable)
index 194d90a..32f52fd
@@ -1,3 +1,5 @@
+#!/usr/bin/env bluemonkey
+
 console.log("hello world!");
 
 bluemonkey.loadModule("@PLUGIN_INSTALL_PATH@/bluemonkeyDbModule.so");
@@ -9,88 +11,97 @@ exportObj = {};
 exportObj.foo = function() { return "bar"; }
 exportObj.bar = true;
 
-if(dbus !== undefined)
-{
-    try
-    {
-        var dbusIface = dbus.createInterface("org.freedesktop.DBus", "/", "org.freedesktop.DBus", dbus.Session);
-
-        var reply = dbusIface.GetId();
-
-        console.log("org.freedesktop.DBus.GetId() response: " + reply);
-
-        var registered = dbus.registerService("org.bluemonkey", 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);
-        console.log("exported: " + exported)
-
-        bluemonkey.assertIsTrue(exported, "Failed to export custom dbus object: " + dbus.errorMessage(dbus.Session));
-
-        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)
-    {
-        console.log("nasty dbus errors");
-    }
-}
+app = new Application();
 
-if(ble !== undefined)
+app.main = function()
 {
-    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))
-    });
+       console.log("running main()");
+
+       if(dbus !== undefined)
+       {
+               try
+               {
+                       var dbusIface = dbus.createInterface("org.freedesktop.DBus", "/", "org.freedesktop.DBus", dbus.Session);
+
+                       var reply = dbusIface.GetId();
+
+                       console.log("org.freedesktop.DBus.GetId() response: " + reply);
+
+                       var registered = dbus.registerService("org.bluemonkey", dbus.Session)
+
+                       bluemonkey.assertIsTrue(registered, "could not register service: " + dbus.errorMessage(dbus.Session));
+               }
+               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)
+                       {
+                               console.log("scan finished");
+                       }
+               });
+
+               ble.scan = true;
+               ble.devicesChanged.connect(function ()
+               {
+                       console.log("devices that match the service uuid: " + ble.devices(serviceUuid))
+               });
+       }
+
+       if(websockets !== undefined)
+       {
+               console.log("can has websockets!");
+
+               server = new WebSocketServer();
+               server.onconnection = function(s)
+               {
+                       console.log("server can has new connection!");
+                       s.onmessage = function(msg)
+                       {
+                               console.log("server received msg: " + msg);
+                               s.send("pong");
+                       };
+               };
+
+               server.listen(8070);
+
+               socket = new WebSocket("ws://localhost:8070");
+
+               socket.onmessage = function(msg)
+               {
+                       console.log("msg: "+ msg);
+               };
+
+               socket.onopen = function()
+               {
+                       console.log("client connection opened!");
+                       socket.send("ping");
+               };
+
+               socket.onclose = function()
+               {
+                       console.log("closed");
+               };
+
+               socket.onerror = function(err)
+               {
+                       console.log("error: " + err);
+               }
+
+               socket.open();
+       }
+       else
+       {
+               console.log("no websocket support :(");
+       }
 }
 
-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 :(");
-}
+app.run();
index 9fd93b2..1f05ca1 100644 (file)
@@ -25,8 +25,8 @@
 #include <QtDebug>
 extern "C" void create(std::map<std::string, std::string> config, std::map<std::string, QObject*> &exports, QString &js, QObject* parent)
 {
-       exports["dbus"] = new BMDBus(nullptr);
-       exports["testExport"] = new TestQObject(nullptr);
+       exports["dbus"] = new BMDBus(parent);
+       exports["testExport"] = new TestQObject(parent);
 
        js.append("dbus.defineMethodSignature = function(obj, methodName, retType, args)"
                  "{"
index eeec874..348b045 100644 (file)
@@ -9,86 +9,22 @@
 
 #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(); };"
-                         "");
+QString BinaryType::Blob = "blob";
+QString BinaryType::ArrayBuffer = "arraybuffer";
 
+bool BinaryType::validType(const QString &t)
+{
+       return t == Blob || t == ArrayBuffer;
 }
 
+extern const char bmws_api[];
 
+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(parent);
 
+       js.append(bmws_api);
+}
 
 Websockets::Websockets(QObject *parent)
        :QObject(parent)
@@ -101,56 +37,84 @@ QObject *Websockets::createClient(const QString &url, const QStringList &protoco
        return new WebsocketClient(url, nullptr);
 }
 
-QObject *Websockets::createServer()
+QObject *Websockets::createServer(bool useSsl)
 {
-
+       return new WebsocketServer(useSsl, this);
 }
 
 
-WebsocketClient::WebsocketClient(const QString &url, QObject *parent)
-       :QWebSocket(QString(), QWebSocketProtocol::VersionLatest, parent), mUrl(url)
+WebsocketClient::WebsocketClient(const QString &url, QObject *parent, QWebSocket * ws)
+       :QObject(parent), mUrl(url), mBinaryType("blob"), mSocket(ws)
 {
-       qDebug() << "Constructed websocket client";
-
-       connect(this, &WebsocketClient::connected, []()
+       if(!mSocket)
+               mSocket = new QWebSocket(QString(), QWebSocketProtocol::VersionLatest, this);
+       else //reparent to this
+               mSocket->setParent(this);
+
+       connect(mSocket, &QWebSocket::connected, this, &WebsocketClient::connected);
+       connect(mSocket, &QWebSocket::disconnected, this, &WebsocketClient::disconnected);
+       connect(mSocket, &QWebSocket::stateChanged, this, &WebsocketClient::stateChanged);
+       connect(mSocket, &QWebSocket::textMessageReceived, [this](const QString & msg)
        {
-               qDebug() << "connected";
+               mBinaryType = BinaryType::Blob;
+               textMessageReceived(msg);
        });
-
-       connect(this, &WebsocketClient::disconnected, []()
+       connect(mSocket, &QWebSocket::binaryMessageReceived, [this](const QByteArray & msg)
        {
-               qDebug() << "disconnected";
+               mBinaryType = BinaryType::ArrayBuffer;
+               binaryMessageReceived(msg);
        });
+}
 
-       connect(this, &WebsocketClient::stateChanged, [](QAbstractSocket::SocketState state)
-       {
-               qDebug() << "state changed: " << state;
-       });
+WebsocketClient::WebsocketClient(QWebSocket *other, QObject* parent)
+       :WebsocketClient("", parent, other)
+{
 
-       open(QUrl(url));
+}
+
+WebsocketClient::~WebsocketClient()
+{
+       mSocket->close();
 }
 
 int WebsocketClient::readyState()
 {
-       if(state() == QAbstractSocket::UnconnectedState)
+       if(mSocket->state() == QAbstractSocket::UnconnectedState)
        {
                return 3;
        }
-       else if(state() == QAbstractSocket::ConnectingState)
+       else if(mSocket->state() == QAbstractSocket::ConnectingState)
        {
                return 0;
        }
-       else if(state() == QAbstractSocket::ClosingState)
+       else if(mSocket->state() == QAbstractSocket::ClosingState)
        {
                return 2;
        }
-       else if(state() == QAbstractSocket::ConnectedState)
+       else if(mSocket->state() == QAbstractSocket::ConnectedState)
        {
                return 1;
        }
        return -1;
 }
 
+void WebsocketClient::open()
+{
+       mSocket->open(mUrl);
+}
+
+void WebsocketClient::send(const QByteArray &msg)
+{
+       if(mBinaryType == BinaryType::Blob)
+       {
+               mSocket->sendTextMessage(msg);
+       }
+       else
+       {
+               mSocket->sendBinaryMessage(msg);
+       }
+}
+
 int main(int argc, char** argv)
 {
        QCoreApplication app(argc, argv);
@@ -159,8 +123,7 @@ int main(int argc, char** argv)
        QObject::connect(&client, &WebsocketClient::connected, [&client]()
        {
                qDebug() << "Can has connection!";
-
-               client.sendTextMessage("Hello world!");
+               client.send("Hello world!");
        });
 
        QObject::connect(&client, &WebsocketClient::textMessageReceived, [](const QString & msg)
@@ -186,6 +149,20 @@ WebsocketServer::WebsocketServer(bool ssl, QObject *parent)
        :QObject(parent), mServer(nullptr)
 {
        mServer = new QWebSocketServer("", ssl ? QWebSocketServer::SecureMode : QWebSocketServer::NonSecureMode, this);
+
+       connect(mServer, &QWebSocketServer::newConnection, [this]()
+       {
+               QWebSocket * socket = mServer->nextPendingConnection();
+
+               auto client = new WebsocketClient(socket, this);
+
+               newConnection(client);
+       });
+}
+
+WebsocketServer::~WebsocketServer()
+{
+       close();
 }
 
 int WebsocketServer::secureMode()
@@ -195,5 +172,14 @@ int WebsocketServer::secureMode()
 
 void WebsocketServer::listen(quint16 port)
 {
+       mServer->listen(QHostAddress::Any, port);
+}
 
+void WebsocketServer::close()
+{
+       mServer->close();
 }
+
+
+
+
index 6384dfb..3d09548 100644 (file)
@@ -4,6 +4,9 @@
 #include <QObject>
 #include <QtWebSockets/QWebSocket>
 #include <QtWebSockets/QWebSocketServer>
+
+#include <memory>
+
 class Websockets : public QObject
 {
        Q_OBJECT
@@ -12,28 +15,62 @@ public:
 
 public Q_SLOTS:
        QObject * createClient(const QString & url, const QStringList  &protocols);
-       QObject * createServer();
+       QObject * createServer(bool useSsl = false);
 };
 
-class WebsocketClient : public QWebSocket
+namespace BinaryType
+{
+       extern QString Blob;
+       extern QString ArrayBuffer;
+
+       extern bool validType(const QString & t);
+}
+
+class WebsocketClient : public QObject
 {
        Q_OBJECT
        Q_PROPERTY(int readyState READ readyState)
        Q_PROPERTY(QString url READ getUrl)
+       Q_PROPERTY(QString binaryType READ binaryType WRITE setBinaryType)
+
 public:
-       WebsocketClient(const QString & url, QObject* parent = nullptr);
+       WebsocketClient(const QString & url, QObject* parent = nullptr, QWebSocket *ws = nullptr);
+       WebsocketClient(QWebSocket * other, QObject *parent = nullptr);
+
+       ~WebsocketClient();
 
        int readyState();
        QString getUrl() { return mUrl; }
 
+       QString binaryType() { return mBinaryType; }
+       void setBinaryType(const QString & bt)
+       {
+               if(!BinaryType::validType(bt))
+                       return;
+
+               mBinaryType = bt;
+       }
+
 public Q_SLOTS:
+       void open();
+       void send(const QByteArray &msg);
+       void close() { mSocket->close(); }
+
+       QString errorString() { return mSocket->errorString(); }
+
+Q_SIGNALS:
 
-       QString getErrorString() { return errorString(); }
-       void _sendTextMessage(const QString & msg) { sendTextMessage(msg); }
-       void _sendBinaryMessage(const QByteArray & msg) { sendBinaryMessage(msg); }
+       void connected();
+       void disconnected();
+       void stateChanged(QAbstractSocket::SocketState state);
+       void textMessageReceived(const QString &message);
+       void binaryMessageReceived(const QByteArray &message);
+       void error(QAbstractSocket::SocketError error);
 
 private:
        QString mUrl;
+       QString mBinaryType;
+       QWebSocket * mSocket;
 };
 
 class WebsocketServer : public QObject
@@ -44,16 +81,20 @@ class WebsocketServer : public QObject
 
 public:
        WebsocketServer(bool ssl = false, QObject * parent = nullptr);
+       ~WebsocketServer();
 
-       int secureMode();
+       QString serverName() { return mServer->serverName(); }
+       void setServerName(const QString & n) { mServer->setServerName(n); }
 
+       int secureMode();
        void setSecureMode(int mode);
 
 public Q_SLOTS:
+
        void listen(quint16 port);
+       void close();
 
 Q_SIGNALS:
-
        void newConnection(QObject * socket);
 
 private:
diff --git a/plugins/bluemonkey/bmws.js b/plugins/bluemonkey/bmws.js
new file mode 100644 (file)
index 0000000..ea45e37
--- /dev/null
@@ -0,0 +1,115 @@
+/// This is the js api for bluemonkey websockets
+
+function listProperties(obj) {
+   var propList = "";
+   for(var propName in obj) {
+         propList += (propName + ", ");
+   }
+   console.log(propList);
+}
+
+function _hookupWebSocket(socket)
+{
+       socket.client.connected.connect(function()
+       {
+               if(socket.onopen !== undefined)
+                       socket.onopen();
+               else
+                       console.log('onopen is like, totally undefined');
+       });
+
+       socket.client.disconnected.connect(function()
+       {
+               if(socket.onclose !== undefined)
+                       socket.onclose()
+       });
+
+       socket.client.error.connect(function(err)
+       {
+               if(socket.onerror !== undefined)
+                       socket.onerror(socket.client.errorString());
+       });
+
+       socket.client.textMessageReceived.connect(function(msg)
+       {
+               if(socket.onmessage !== undefined)
+               {
+                       socket.onmessage(msg);
+               }
+       });
+
+       socket.client.binaryMessageReceived.connect(function(msg)
+       {
+               if(socket.onmessage !== undefined)
+               {
+                       socket.onmessage(msg);
+               }
+       });
+}
+
+function WebSocket(url, protocols, client)
+{
+       if(client === undefined)
+       {
+               this.client = websockets.createClient(url, protocols);
+       }
+       else
+       {
+               this.client = client
+               _hookupWebSocket(this);
+       }
+       Object.defineProperty(this, 'binaryType', { enumerable : false, get : function() { return this.client.binaryType; }, set : function (val)
+       {
+               this.client.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; }});
+}
+
+WebSocket.prototype.open = function()
+{
+       _hookupWebSocket(this)
+       this.client.open();
+}
+
+WebSocket.prototype.send = function(msg)
+{
+       this.client.send(msg);
+};
+
+WebSocket.prototype.close = function() { this.client.close(); };
+
+function WebSocketServer(useSsl)
+{
+       if(useSsl === undefined)
+               useSsl = false;
+       this.server = websockets.createServer(useSsl);
+       this._connectAllTheThings(this);
+}
+
+WebSocketServer.prototype._connectAllTheThings = function(obj)
+{
+       obj.server.newConnection.connect(function(c)
+       {
+               if(obj.onconnection !== undefined)
+                       obj.onconnection(new WebSocket('', '', c));
+               else
+                       console.log("onconnection is not defined for WebSocketServer");
+       });
+};
+
+WebSocketServer.prototype.listen = function(port)
+{
+       this.server.listen(port);
+};
+
+WebSocketServer.prototype.close = function(){ this.server.close(); };
index 9ab1df8..5670bbb 100644 (file)
@@ -1,4 +1,5 @@
 configure_file (${CMAKE_CURRENT_SOURCE_DIR}/genmapping.py ${CMAKE_CURRENT_BINARY_DIR}/genmapping @ONLY)
 configure_file (${CMAKE_CURRENT_SOURCE_DIR}/ambctl.py ${CMAKE_CURRENT_BINARY_DIR}/ambctl @ONLY)
+configure_file (${CMAKE_CURRENT_SOURCE_DIR}/generate_api.py ${CMAKE_CURRENT_BINARY_DIR}/generate_api @ONLY)
 
 install (PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/ambctl DESTINATION bin)
similarity index 100%
rename from xwalk/generate_api.py
rename to tools/generate_api.py
index c2ae60f..8566b17 100644 (file)
@@ -9,10 +9,10 @@ set(vehicle_api_sources vehicle.cc vehicle_extension.cc vehicle_instance.cc comm
 include_directories(${include_dirs} ${CMAKE_CURRENT_SOURCE_DIR}/)
 
 add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/vehicle_api.cc
-                                  COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/generate_api.py ${CMAKE_CURRENT_SOURCE_DIR}/vehicle_api.js kSource_vehicle_api ${CMAKE_CURRENT_BINARY_DIR}/vehicle_api.cc )
+                                  COMMAND python ${CMAKE_SOURCE_DIR}/tools/generate_api.py ${CMAKE_CURRENT_SOURCE_DIR}/vehicle_api.js kSource_vehicle_api ${CMAKE_CURRENT_BINARY_DIR}/vehicle_api.cc )
 
 add_library(vehicle_extension MODULE ${vehicle_api_sources} ${CMAKE_CURRENT_BINARY_DIR}/vehicle_api.cc)
-target_link_libraries(vehicle_extension ${link_libraries} amb ${gio_LIBRARIES} -L${CMAKE_CURRENT_BINARY_DIR}/lib)
+target_link_libraries(vehicle_extension ${link_libraries} amb ${gio_LIBRARIES} -L${CMAKE_BINARY_DIR}/lib)
 
 add_custom_target(js3cc DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/vehicle_api.cc)
 add_dependencies(vehicle_extension js3cc)