~~~~~~~~~~~~~{.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"
}
~~~~~~~~~~~~~
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)
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);
}
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());
+ });
}
void Ble::startScan(bool scan)
{
- qDebug() << "Scanning: " << (scan ? "true":"false");
scan ? mDeviceDiscoveryAgent->start() : mDeviceDiscoveryAgent->stop();
}
{
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();
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);
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;
}
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;
}
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;
}
}
}
});
- qDebug() << "attempting to connect to device: " << device.address().toString();
control->connectToDevice();
}
}
"{"
" 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()
engine->deleteLater();
}
-void Bluemonkey::loadConfig(QString str)
+void Bluemonkey::loadScript(QString str)
{
QFile file(str);
if(!file.open(QIODevice::ReadOnly))
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");
}
}
std::map<std::string, QObject*> exports;
QString js;
- create(configuration, exports, js, nullptr);
+ create(configuration, exports, js, this);
for(auto i : exports)
{
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)
return new QObject(this);
}
+QObject *Bluemonkey::createCoreApplication()
+{
+ return QCoreApplication::instance();
+}
+
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)
{
Q_ASSERT(isTrue);
}
+
+
+int Bluemonkey::run(QCoreApplication *app)
+{
+ return app->exec();
+}
#include <QJsonDocument>
#include <QDateTime>
#include <QJSValue>
+#include <QCoreApplication>
#include "authenticate.h"
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);
QObject* createTimer();
QObject* createQObject();
+ QObject* createCoreApplication();
+
+ int run(QCoreApplication *app);
+
Q_SIGNALS:
void ready();
QList<void*> modules;
QJSEngine* engine;
QStringList configsToLoad;
+ QStringList mArguments;
std::map<std::string, std::string> configuration;
};
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;
}
+#!/usr/bin/env bluemonkey
+
console.log("hello world!");
bluemonkey.loadModule("@PLUGIN_INSTALL_PATH@/bluemonkeyDbModule.so");
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();
#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)"
"{"
#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)
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);
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)
: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()
void WebsocketServer::listen(quint16 port)
{
+ mServer->listen(QHostAddress::Any, port);
+}
+void WebsocketServer::close()
+{
+ mServer->close();
}
+
+
+
+
#include <QObject>
#include <QtWebSockets/QWebSocket>
#include <QtWebSockets/QWebSocketServer>
+
+#include <memory>
+
class Websockets : public QObject
{
Q_OBJECT
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
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:
--- /dev/null
+/// 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(); };
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)
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)