diff options
| author | Andrew Branson <andrew.branson@cern.ch> | 2016-02-18 09:13:32 +0100 |
|---|---|---|
| committer | Andrew Branson <andrew.branson@cern.ch> | 2016-02-18 09:13:32 +0100 |
| commit | f4910b3ac84c72a7e17c99895a3b9abb0e9534fe (patch) | |
| tree | 91ae8cfd80dc3d7a2adedee9cab0d407c5c23c84 /rockworkd/libpebble/jskit | |
| parent | 7305ce8e080d0a6ee7505fe978a2e601b56a5ce8 (diff) | |
| parent | 8f014f0915c7bdc97573f953aa9a3ae25a5f953a (diff) | |
Merge branch 'rockwork'
Conflicts:
po/de.po
po/en_GB.po
po/eu.po
po/fr.po
po/hu.po
po/it.po
po/pt.po
po/rockwork.mzanetti.pot
po/ru.po
po/template.pot
rockwork/InfoPage.qml
rockwork/Main.qml
rockwork/NotificationsPage.qml
rockworkd/rockworkd.pro
version.pri
Diffstat (limited to 'rockworkd/libpebble/jskit')
| -rw-r--r-- | rockworkd/libpebble/jskit/jskitconsole.cpp | 201 | ||||
| -rw-r--r-- | rockworkd/libpebble/jskit/jskitconsole.h | 56 | ||||
| -rw-r--r-- | rockworkd/libpebble/jskit/jskitmanager.cpp | 2 | ||||
| -rw-r--r-- | rockworkd/libpebble/jskit/jskitpebble.cpp | 9 | ||||
| -rw-r--r-- | rockworkd/libpebble/jskit/jskitpebble.h | 1 | ||||
| -rw-r--r-- | rockworkd/libpebble/jskit/jskitsetup.js | 104 | ||||
| -rw-r--r-- | rockworkd/libpebble/jskit/jskitwebsocket.cpp | 311 | ||||
| -rw-r--r-- | rockworkd/libpebble/jskit/jskitwebsocket.h | 79 |
8 files changed, 738 insertions, 25 deletions
diff --git a/rockworkd/libpebble/jskit/jskitconsole.cpp b/rockworkd/libpebble/jskit/jskitconsole.cpp index 3d6c85c..384965b 100644 --- a/rockworkd/libpebble/jskit/jskitconsole.cpp +++ b/rockworkd/libpebble/jskit/jskitconsole.cpp @@ -4,26 +4,209 @@ JSKitConsole::JSKitConsole(QObject *parent) : QObject(parent), - l(metaObject()->className()) + l("JSKit Log"), + w("JSKit Warning"), + e("JSKit Error"), + i("JSKit Info") { } -void JSKitConsole::log(const QString &msg) +void JSKitConsole::log(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6, const QString &msg7, const QString &msg8, const QString &msg9) { - qCDebug(l) << msg; + qCDebug(l) << msg0 << msg1 << msg2 << msg3 << msg4 << msg5 << msg6 << msg7 << msg8 << msg9; } -void JSKitConsole::warn(const QString &msg) +void JSKitConsole::log(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6, const QString &msg7, const QString &msg8) { - qCWarning(l) << msg; + qCDebug(l) << msg0 << msg1 << msg2 << msg3 << msg4 << msg5 << msg6 << msg7 << msg8; } -void JSKitConsole::error(const QString &msg) +void JSKitConsole::log(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6, const QString &msg7) { - qCCritical(l) << msg; + qCDebug(l) << msg0 << msg1 << msg2 << msg3 << msg4 << msg5 << msg6 << msg7; } -void JSKitConsole::info(const QString &msg) +void JSKitConsole::log(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6) { - qCDebug(l) << msg; + qCDebug(l) << msg0 << msg1 << msg2 << msg3 << msg4 << msg5 << msg6; +} + +void JSKitConsole::log(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5) +{ + qCDebug(l) << msg0 << msg1 << msg2 << msg3 << msg4 << msg5; +} + +void JSKitConsole::log(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4) +{ + qCDebug(l) << msg0 << msg1 << msg2 << msg3 << msg4; +} + +void JSKitConsole::log(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3) +{ + qCDebug(l) << msg0 << msg1 << msg2 << msg3; +} + +void JSKitConsole::log(const QString &msg0, const QString &msg1, const QString &msg2) +{ + qCDebug(l) << msg0 << msg1 << msg2; +} + +void JSKitConsole::log(const QString &msg0, const QString &msg1) +{ + qCDebug(l) << msg0 << msg1; +} + +void JSKitConsole::log(const QString &msg0) +{ + qCDebug(l) << msg0; +} + +void JSKitConsole::warn(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6, const QString &msg7, const QString &msg8, const QString &msg9) +{ + qCWarning(w) << msg0 << msg1 << msg2 << msg3 << msg4 << msg5 << msg6 << msg7 << msg8 << msg9; +} + +void JSKitConsole::warn(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6, const QString &msg7, const QString &msg8) +{ + qCWarning(w) << msg0 << msg1 << msg2 << msg3 << msg4 << msg5 << msg6 << msg7 << msg8; +} + +void JSKitConsole::warn(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6, const QString &msg7) +{ + qCWarning(w) << msg0 << msg1 << msg2 << msg3 << msg4 << msg5 << msg6 << msg7; +} + +void JSKitConsole::warn(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6) +{ + qCWarning(w) << msg0 << msg1 << msg2 << msg3 << msg4 << msg5 << msg6; +} + +void JSKitConsole::warn(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5) +{ + qCWarning(w) << msg0 << msg1 << msg2 << msg3 << msg4 << msg5; +} + +void JSKitConsole::warn(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4) +{ + qCWarning(w) << msg0 << msg1 << msg2 << msg3 << msg4; +} + +void JSKitConsole::warn(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3) +{ + qCWarning(w) << msg0 << msg1 << msg2 << msg3; +} + +void JSKitConsole::warn(const QString &msg0, const QString &msg1, const QString &msg2) +{ + qCWarning(w) << msg0 << msg1 << msg2; +} + +void JSKitConsole::warn(const QString &msg0, const QString &msg1) +{ + qCWarning(w) << msg0 << msg1; +} + +void JSKitConsole::warn(const QString &msg0) +{ + qCWarning(w) << msg0; +} + +void JSKitConsole::error(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6, const QString &msg7, const QString &msg8, const QString &msg9) +{ + qCCritical(e) << msg0 << msg1 << msg2 << msg3 << msg4 << msg5 << msg6 << msg7 << msg8 << msg9; +} + +void JSKitConsole::error(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6, const QString &msg7, const QString &msg8) +{ + qCCritical(e) << msg0 << msg1 << msg2 << msg3 << msg4 << msg5 << msg6 << msg7 << msg8; +} + +void JSKitConsole::error(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6, const QString &msg7) +{ + qCCritical(e) << msg0 << msg1 << msg2 << msg3 << msg4 << msg5 << msg6 << msg7; +} + +void JSKitConsole::error(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6) +{ + qCCritical(e) << msg0 << msg1 << msg2 << msg3 << msg4 << msg5 << msg6; +} + +void JSKitConsole::error(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5) +{ + qCCritical(e) << msg0 << msg1 << msg2 << msg3 << msg4 << msg5; +} + +void JSKitConsole::error(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4) +{ + qCCritical(e) << msg0 << msg1 << msg2 << msg3 << msg4; +} + +void JSKitConsole::error(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3) +{ + qCCritical(e) << msg0 << msg1 << msg2 << msg3; +} + +void JSKitConsole::error(const QString &msg0, const QString &msg1, const QString &msg2) +{ + qCCritical(e) << msg0 << msg1 << msg2; +} + +void JSKitConsole::error(const QString &msg0, const QString &msg1) +{ + qCCritical(e) << msg0 << msg1; +} + +void JSKitConsole::error(const QString &msg0) +{ + qCCritical(e) << msg0; +} + +void JSKitConsole::info(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6, const QString &msg7, const QString &msg8, const QString &msg9) +{ + qCDebug(i) << msg0 << msg1 << msg2 << msg3 << msg4 << msg5 << msg6 << msg7 << msg8 << msg9; +} + +void JSKitConsole::info(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6, const QString &msg7, const QString &msg8) +{ + qCDebug(i) << msg0 << msg1 << msg2 << msg3 << msg4 << msg5 << msg6 << msg7 << msg8; +} + +void JSKitConsole::info(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6, const QString &msg7) +{ + qCDebug(i) << msg0 << msg1 << msg2 << msg3 << msg4 << msg5 << msg6 << msg7; +} + +void JSKitConsole::info(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6) +{ + qCDebug(i) << msg0 << msg1 << msg2 << msg3 << msg4 << msg5 << msg6; +} + +void JSKitConsole::info(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5) +{ + qCDebug(i) << msg0 << msg1 << msg2 << msg3 << msg4 << msg5; +} + +void JSKitConsole::info(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4) +{ + qCDebug(i) << msg0 << msg1 << msg2 << msg3 << msg4; +} + +void JSKitConsole::info(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3) +{ + qCDebug(i) << msg0 << msg1 << msg2 << msg3; +} + +void JSKitConsole::info(const QString &msg0, const QString &msg1, const QString &msg2) +{ + qCDebug(i) << msg0 << msg1 << msg2; +} + +void JSKitConsole::info(const QString &msg0, const QString &msg1) +{ + qCDebug(i) << msg0 << msg1; +} + +void JSKitConsole::info(const QString &msg0) +{ + qCDebug(i) << msg0; } diff --git a/rockworkd/libpebble/jskit/jskitconsole.h b/rockworkd/libpebble/jskit/jskitconsole.h index 3896ae3..6f8970d 100644 --- a/rockworkd/libpebble/jskit/jskitconsole.h +++ b/rockworkd/libpebble/jskit/jskitconsole.h @@ -3,18 +3,66 @@ #include <QLoggingCategory> +/* + We opted to do multiple overloaded functions rather than one with default + arguments as this method produces nicer log messages and wont omit (possibly) + important messages like empty string, undefined, or null. +*/ + class JSKitConsole : public QObject { Q_OBJECT QLoggingCategory l; + QLoggingCategory w; + QLoggingCategory e; + QLoggingCategory i; public: explicit JSKitConsole(QObject *parent=0); - Q_INVOKABLE void log(const QString &msg); - Q_INVOKABLE void warn(const QString &msg); - Q_INVOKABLE void error(const QString &msg); - Q_INVOKABLE void info(const QString &msg); + Q_INVOKABLE void log(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6, const QString &msg7, const QString &msg8, const QString &msg9); + Q_INVOKABLE void log(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6, const QString &msg7, const QString &msg8); + Q_INVOKABLE void log(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6, const QString &msg7); + Q_INVOKABLE void log(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6); + Q_INVOKABLE void log(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5); + Q_INVOKABLE void log(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4); + Q_INVOKABLE void log(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3); + Q_INVOKABLE void log(const QString &msg0, const QString &msg1, const QString &msg2); + Q_INVOKABLE void log(const QString &msg0, const QString &msg1); + Q_INVOKABLE void log(const QString &msg0); + + Q_INVOKABLE void warn(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6, const QString &msg7, const QString &msg8, const QString &msg9); + Q_INVOKABLE void warn(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6, const QString &msg7, const QString &msg8); + Q_INVOKABLE void warn(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6, const QString &msg7); + Q_INVOKABLE void warn(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6); + Q_INVOKABLE void warn(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5); + Q_INVOKABLE void warn(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4); + Q_INVOKABLE void warn(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3); + Q_INVOKABLE void warn(const QString &msg0, const QString &msg1, const QString &msg2); + Q_INVOKABLE void warn(const QString &msg0, const QString &msg1); + Q_INVOKABLE void warn(const QString &msg0); + + Q_INVOKABLE void error(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6, const QString &msg7, const QString &msg8, const QString &msg9); + Q_INVOKABLE void error(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6, const QString &msg7, const QString &msg8); + Q_INVOKABLE void error(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6, const QString &msg7); + Q_INVOKABLE void error(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6); + Q_INVOKABLE void error(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5); + Q_INVOKABLE void error(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4); + Q_INVOKABLE void error(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3); + Q_INVOKABLE void error(const QString &msg0, const QString &msg1, const QString &msg2); + Q_INVOKABLE void error(const QString &msg0, const QString &msg1); + Q_INVOKABLE void error(const QString &msg0); + + Q_INVOKABLE void info(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6, const QString &msg7, const QString &msg8, const QString &msg9); + Q_INVOKABLE void info(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6, const QString &msg7, const QString &msg8); + Q_INVOKABLE void info(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6, const QString &msg7); + Q_INVOKABLE void info(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5, const QString &msg6); + Q_INVOKABLE void info(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4, const QString &msg5); + Q_INVOKABLE void info(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3, const QString &msg4); + Q_INVOKABLE void info(const QString &msg0, const QString &msg1, const QString &msg2, const QString &msg3); + Q_INVOKABLE void info(const QString &msg0, const QString &msg1, const QString &msg2); + Q_INVOKABLE void info(const QString &msg0, const QString &msg1); + Q_INVOKABLE void info(const QString &msg0); }; #endif // JSKITCONSOLE_H diff --git a/rockworkd/libpebble/jskit/jskitmanager.cpp b/rockworkd/libpebble/jskit/jskitmanager.cpp index 04bf674..8a03afd 100644 --- a/rockworkd/libpebble/jskit/jskitmanager.cpp +++ b/rockworkd/libpebble/jskit/jskitmanager.cpp @@ -82,7 +82,7 @@ AppInfo JSKitManager::currentApp() void JSKitManager::handleAppStarted(const QUuid &uuid) { AppInfo info = m_apps->info(uuid); - if (!info.uuid().isNull() && info.isJSKit()) { + if (!info.uuid().isNull() && info.isJSKit() && info.uuid() != m_curApp.uuid()) { qCDebug(l) << "Preparing to start JSKit app" << info.uuid() << info.shortName(); m_curApp = info; diff --git a/rockworkd/libpebble/jskit/jskitpebble.cpp b/rockworkd/libpebble/jskit/jskitpebble.cpp index a300aef..e755d60 100644 --- a/rockworkd/libpebble/jskit/jskitpebble.cpp +++ b/rockworkd/libpebble/jskit/jskitpebble.cpp @@ -4,6 +4,7 @@ #include "jskitpebble.h" #include "jskitxmlhttprequest.h" +#include "jskitwebsocket.h" static const char *token_salt = "0feeb7416d3c4546a19b04bccd8419b1"; @@ -315,10 +316,16 @@ void JSKitPebble::openURL(const QUrl &url) QJSValue JSKitPebble::createXMLHttpRequest() { JSKitXMLHttpRequest *xhr = new JSKitXMLHttpRequest(m_mgr->engine()); - // Should be deleted by JS engine. return m_mgr->engine()->newQObject(xhr); } +QJSValue JSKitPebble::createWebSocket(const QString &url, const QJSValue &protocols) +{ + JSKitWebSocket *ws = new JSKitWebSocket(m_mgr->engine(), url, protocols); + return m_mgr->engine()->newQObject(ws); +} + + QJSValue JSKitPebble::buildAckEventObject(uint transaction, const QString &message) const { QJSEngine *engine = m_mgr->engine(); diff --git a/rockworkd/libpebble/jskit/jskitpebble.h b/rockworkd/libpebble/jskit/jskitpebble.h index d9cd670..c461adb 100644 --- a/rockworkd/libpebble/jskit/jskitpebble.h +++ b/rockworkd/libpebble/jskit/jskitpebble.h @@ -32,6 +32,7 @@ public: Q_INVOKABLE void openURL(const QUrl &url); Q_INVOKABLE QJSValue createXMLHttpRequest(); + Q_INVOKABLE QJSValue createWebSocket(const QString &url, const QJSValue &protocols=QJSValue{}); void invokeCallbacks(const QString &type, const QJSValueList &args = QJSValueList()); diff --git a/rockworkd/libpebble/jskit/jskitsetup.js b/rockworkd/libpebble/jskit/jskitsetup.js index 340c4f1..2f85c7d 100644 --- a/rockworkd/libpebble/jskit/jskitsetup.js +++ b/rockworkd/libpebble/jskit/jskitsetup.js @@ -81,16 +81,6 @@ console = new (function() { ); })(); -/*localStorage = new (function() { - _jskit.make_proxies(this, _jskit.localstorage, - ['clear', 'getItem', 'setItem', 'removeItem', 'key'] - ); - - _jskit.make_properties(this, _jskit.localstorage, - ['length'] - ); -})();*/ - //It appears that Proxy is not available since Qt is using Javascript v5 /*(function() { var proxy = _jskit.make_proxies({}, _jskit.localstorage, ['set', 'has', 'deleteProperty', 'keys', 'enumerate']); @@ -194,3 +184,97 @@ Object.defineProperty(window, "localStorage", new (function () { localStorage.setItem(keys[index], value); } })(); + +function WebSocket(url, protocols) { + var ws = _jskit.pebble.createWebSocket(url, protocols); + _jskit.make_proxies(this, ws, ['close', 'send']); + _jskit.make_properties(this, ws, + ['readyState', 'bufferedAmount', 'onopen', 'onerror', 'onclose', 'onmessage', + 'extensions', 'protocol', 'binaryType']); + + this.CONNECTING = 0; + this.OPEN = 1; + this.CLOSING = 2; + this.CLOSED = 3; +} + +//Borrowed from https://github.com/pebble/pypkjs/blob/master/pypkjs/javascript/events.py#L9 +Event = function(event_type, event_init_dict) { + var self = this; + this.stopPropagation = function() {}; + this.stopImmediatePropagation = function() { self._aborted = true; } + this.preventDefault = function() { self.defaultPrevented = true; } + this.initEvent = function(event_type, bubbles, cancelable) { + self.type = event_type; + self.bubbles = bubbles; + self.cancelable = cancelable + }; + + if(!event_init_dict) event_init_dict = {}; + this.type = event_type; + this.bubbles = event_init_dict.bubbles || false; + this.cancelable = event_init_dict.cancelable || false; + this.defaultPrevented = false; + this.target = null; + this.currentTarget = null; + this.eventPhase = 2; + this._aborted = false; +}; +Event._init = function(event_type, event_init_dict) { + //Convenience function to call from the engine + return new Event(event_type, event_init_dict) +}; + +Event.NONE = 0; +Event.CAPTURING_PHASE = 1; +Event.AT_TARGET = 2; +Event.BUBBLING_PHASE = 3; + +//Borrowed from https://github.com/pebble/pypkjs/blob/master/pypkjs/javascript/ws.py#L14 +CloseEvent = function(wasClean, code, reason, eventInitDict) { + Event.call(this, "close", eventInitDict); + + Object.defineProperties(this, { + wasClean: { + get: function() { return wasClean; }, + enumerable: true, + }, + code: { + get: function() { return code; }, + enumerable: true, + }, + reason: { + get: function() { return reason; }, + enumerable: true, + }, + }); +}; + +CloseEvent.prototype = Object.create(Event.prototype); +CloseEvent.prototype.constructor = CloseEvent; +CloseEvent._init = function(wasClean, code, reason) { + //Convenience function to call from the engine + return new CloseEvent(wasClean, code, reason) +}; + +MessageEvent = function(origin, data, eventInitDict) { + Event.call(this, "message", eventInitDict); + + Object.defineProperties(this, { + origin: { + get: function() { return origin; }, + enumerable: true, + }, + data: { + get: function() { return data; }, + enumerable: true, + } + }); +}; + +MessageEvent.prototype = Object.create(Event.prototype); +MessageEvent.prototype.constructor = MessageEvent; +MessageEvent._init = function(origin, data) { + //Convenience function to call from the engine + return new MessageEvent(origin, data) +};
\ No newline at end of file diff --git a/rockworkd/libpebble/jskit/jskitwebsocket.cpp b/rockworkd/libpebble/jskit/jskitwebsocket.cpp new file mode 100644 index 0000000..e66cdfb --- /dev/null +++ b/rockworkd/libpebble/jskit/jskitwebsocket.cpp @@ -0,0 +1,311 @@ +#include "jskitwebsocket.h" +#include "jskitmanager.h" + +JSKitWebSocket::JSKitWebSocket(QJSEngine *engine, const QString &url, const QJSValue &protocols) : + QObject(engine), + l(metaObject()->className()), + m_engine(engine), + m_webSocket(new QWebSocket("", QWebSocketProtocol::VersionLatest, this)), + m_url(url) +{ + //As of QT 5.5: "QWebSocket currently does not support extensions and subprotocols" + Q_UNUSED(protocols) + + connect(m_webSocket, &QWebSocket::connected, + this, &JSKitWebSocket::handleConnected); + connect(m_webSocket, &QWebSocket::disconnected, + this, &JSKitWebSocket::handleDisconnected); + connect(m_webSocket, static_cast<void(QWebSocket::*)(QAbstractSocket::SocketError)>(&QWebSocket::error), + this, &JSKitWebSocket::handleError); + connect(m_webSocket, &QWebSocket::sslErrors, + this, &JSKitWebSocket::handleSslErrors); + connect(m_webSocket, &QWebSocket::textMessageReceived, + this, &JSKitWebSocket::handleTextMessageReceived); + connect(m_webSocket, &QWebSocket::binaryMessageReceived, + this, &JSKitWebSocket::handleBinaryMessageReceived); + + qCDebug(l) << "WebSocket opened for" << url; + //m_webSocket->ignoreSslErrors(); + m_webSocket->open(QUrl(url)); +} + +void JSKitWebSocket::send(const QJSValue &data) +{ + //TODO throw SYNTAX_ERR if "The data is a string that has unpaired surrogates" - https://developer.mozilla.org/en-US/docs/Web/API/WebSocket#Exceptions_thrown_2 + + if (m_readyState != OPEN) { + //TODO throw INVALID_STATE_ERR if not opened - https://developer.mozilla.org/en-US/docs/Web/API/WebSocket#Exceptions_thrown_2 + qCDebug(l) << "trying to send when connection is not yet open"; + + return; + } + + if (data.isUndefined() || data.isNull()) { + qCDebug(l) << "Refusing to send a null or undefined message"; + } else if (data.isString()) { + qCDebug(l) << "Sending text message:" << data.toString(); + + QByteArray byteData = data.toString().toUtf8(); + m_bufferedAmount += byteData.size(); + + m_webSocket->sendTextMessage(data.toString()); + } else if (data.isObject()) { + if (data.hasProperty("byteLength")) { + // Looks like an ArrayView or an ArrayBufferView! + QJSValue buffer = data.property("buffer"); + if (buffer.isUndefined()) { + // We must assume we've been passed an ArrayBuffer directly + buffer = data; + } + + QJSValue array = buffer.property("_bytes"); + int byteLength = buffer.property("byteLength").toInt(); + + if (array.isArray()) { + QByteArray byteData; + byteData.reserve(byteLength); + + for (int i = 0; i < byteLength; i++) { + byteData.append(array.property(i).toInt()); + } + + qCDebug(l) << "sending binary message with" << byteData.length() << "bytes"; + + m_bufferedAmount += byteData.size(); + m_webSocket->sendBinaryMessage(byteData); + } else { + qCWarning(l) << "Refusing to send an unknown/invalid ArrayBuffer" << data.toString(); + } + } else { + qCWarning(l) << "Refusing to send an unknown object:" << data.toString(); + } + } +} + +void JSKitWebSocket::close(quint32 code, const QString &reason) +{ + //TODO throw SYNTAX_ERR if "The reason string contains unpaired surrogates" - https://developer.mozilla.org/en-US/docs/Web/API/WebSocket#Exceptions_thrown_2 + + + QByteArray byteData = reason.toUtf8(); + if (byteData.size() >= 123) { + //TODO throw SYNTAX_ERR for invalid reason - https://developer.mozilla.org/en-US/docs/Web/API/WebSocket#Exceptions_thrown + qCDebug(l) << "Invalid reason"; + + return; + } + + QWebSocketProtocol::CloseCode closeCode = QWebSocketProtocol::CloseCodeNormal; + if ((code >= 1000 && code <= 1011) || code == 1015) { + closeCode = static_cast<QWebSocketProtocol::CloseCode>(code);; + } + else { + //TODO throw INVALID_ACCESS_ERR for invalide code - https://developer.mozilla.org/en-US/docs/Web/API/WebSocket#Exceptions_thrown + qCDebug(l) << "Invalid close code"; + + return; + } + + m_webSocket->close(closeCode, reason); + m_readyState = CLOSING; +} + +void JSKitWebSocket::setOnclose(const QJSValue &onclose) +{ + m_onclose = onclose; +} + +void JSKitWebSocket::setOnerror(const QJSValue &onerror) +{ + m_onerror = onerror; +} + +void JSKitWebSocket::setOnmessage(const QJSValue &onmessage) +{ + m_onmessage = onmessage; +} + +void JSKitWebSocket::setOnopen(const QJSValue &onopen) +{ + m_onopen = onopen; +} + +QJSValue JSKitWebSocket::onclose() const +{ + return m_onclose; +} + +QJSValue JSKitWebSocket::onerror() const +{ + return m_onerror; +} + +QJSValue JSKitWebSocket::onmessage() const +{ + return m_onmessage; +} + +QJSValue JSKitWebSocket::onopen() const +{ + return m_onopen; +} + +quint32 JSKitWebSocket::bufferedAmount() +{ + return m_bufferedAmount; +} + +quint8 JSKitWebSocket::readyState() +{ + return m_readyState; +} + +QString JSKitWebSocket::url() +{ + return m_url; +} + +void JSKitWebSocket::handleConnected() +{ + m_readyState = OPEN; + qCDebug(l) << "Connection opened"; + + if (m_onopen.isCallable()) { + qCDebug(l) << "Going to call onopen"; + + QJSValueList eventArgs; + eventArgs.append("open"); + QJSValue event = m_engine->globalObject().property("Event").property("_init").call(eventArgs); + + QJSValueList args; + args.append(event); + QJSValue result = m_onopen.callWithInstance(m_engine->newQObject(this), args); + if (result.isError()) { + qCWarning(l) << "JS error in onopen handler:" << JSKitManager::describeError(result); + } + } +} + +void JSKitWebSocket::handleDisconnected() +{ + m_readyState = CLOSED; + qCDebug(l) << "Connection closed"; + + if (m_onclose.isCallable()) { + qCDebug(l) << "Going to call onclose"; + + QJSValueList eventArgs; + eventArgs.append(QJSValue(true)); //wasClean + eventArgs.append(QJSValue(m_webSocket->closeCode())); + eventArgs.append(QJSValue(m_webSocket->closeReason())); + + QJSValue event = m_engine->globalObject().property("CloseEvent").property("_init").call(eventArgs); + + QJSValueList args; + args.append(event); + + QJSValue result = m_onclose.callWithInstance(m_engine->newQObject(this)); + if (result.isError()) { + qCWarning(l) << "JS error in onclose handler:" << JSKitManager::describeError(result); + } + } +} + +void JSKitWebSocket::handleError(QAbstractSocket::SocketError error) +{ + qCDebug(l) << "Error:" << error; + + if (m_onerror.isCallable()) { + qCDebug(l) << "Going to call onerror"; + + QJSValueList eventArgs; + eventArgs.append(QJSValue("error")); + QJSValue event = m_engine->globalObject().property("Event").property("_init").call(eventArgs); + + QJSValueList args; + args.append(event); + QJSValue result = m_onerror.callWithInstance(m_engine->newQObject(this), args); + if (result.isError()) { + qCWarning(l) << "JS error in onclose handler:" << JSKitManager::describeError(result); + } + } +} + +void JSKitWebSocket::handleSslErrors(const QList<QSslError> &errors) +{ + qCDebug(l) << "Ssl Errors:" << errors; + + if (m_onerror.isCallable()) { + qCDebug(l) << "Going to call onerror"; + + QJSValueList eventArgs; + eventArgs.append(QJSValue("error")); + QJSValue event = m_engine->globalObject().property("Event").property("_init").call(eventArgs); + + QJSValueList args; + args.append(event); + QJSValue result = m_onerror.callWithInstance(m_engine->newQObject(this), args); + if (result.isError()) { + qCWarning(l) << "JS error in onclose handler:" << JSKitManager::describeError(result); + } + } +} + +void JSKitWebSocket::handleTextMessageReceived(const QString &message) +{ + qCDebug(l) << "Text message recieved: " << message; + + callOnmessage(QJSValue(message)); +} + +void JSKitWebSocket::handleBinaryMessageReceived(const QByteArray &message) +{ + qCDebug(l) << "Binary message recieved"; + + if (m_onmessage.isCallable()) { + if (m_binaryType == "arraybuffer") { + QJSValue arrayBufferProto = m_engine->globalObject().property("ArrayBuffer").property("prototype"); + QJSValue arrayBuf = m_engine->newObject(); + + if (arrayBufferProto.isUndefined()) { + qCWarning(l) << "Cannot find proto of ArrayBuffer"; + } else { + arrayBuf.setPrototype(arrayBufferProto); + arrayBuf.setProperty("byteLength", m_engine->toScriptValue<uint>(message.size())); + + QJSValue array = m_engine->newArray(message.size()); + for (int i = 0; i < message.size(); i++) { + array.setProperty(i, m_engine->toScriptValue<int>(message[i])); + } + + arrayBuf.setProperty("_bytes", array); + qCDebug(l) << "calling onmessage with ArrayBuffer of" << message.size() << "bytes"; + + callOnmessage(arrayBuf); + } + } else { + qCWarning(l) << "unsupported binaryType:" << m_binaryType; + } + } +} + +void JSKitWebSocket::callOnmessage(QJSValue data) +{ + if (m_onmessage.isCallable()) { + qCDebug(l) << "Going to call onmessage"; + + QJSValueList eventArgs; + eventArgs.append(QJSValue(m_webSocket->origin())); + eventArgs.append(data); + + QJSValue messageEvent = m_engine->globalObject().property("MessageEvent").property("_init").call(eventArgs); + + QJSValueList args; + args.append(messageEvent); + + QJSValue result = m_onmessage.callWithInstance(m_engine->newQObject(this), args); + if (result.isError()) { + qCWarning(l) << "JS error in onmessage handler:" << JSKitManager::describeError(result); + } + } +} diff --git a/rockworkd/libpebble/jskit/jskitwebsocket.h b/rockworkd/libpebble/jskit/jskitwebsocket.h new file mode 100644 index 0000000..192e9a4 --- /dev/null +++ b/rockworkd/libpebble/jskit/jskitwebsocket.h @@ -0,0 +1,79 @@ +#ifndef JSKITWEBSOCKET_P_H +#define JSKITWEBSOCKET_P_H + +#include <QLoggingCategory> +#include <QWebSocket> +#include <QJSEngine> + +class JSKitWebSocket : public QObject +{ + Q_OBJECT + QLoggingCategory l; + + Q_PROPERTY(QString binaryType MEMBER m_binaryType) + Q_PROPERTY(quint32 bufferedAmount READ bufferedAmount) + Q_PROPERTY(QString extensions MEMBER m_extensions) + Q_PROPERTY(QJSValue onclose READ onclose WRITE setOnclose) + Q_PROPERTY(QJSValue onerror READ onerror WRITE setOnerror) + Q_PROPERTY(QJSValue onmessage READ onmessage WRITE setOnmessage) + Q_PROPERTY(QJSValue onopen READ onopen WRITE setOnopen) + Q_PROPERTY(QString protocol MEMBER m_protocol) + Q_PROPERTY(quint8 readyState READ readyState) + Q_PROPERTY(QString url READ url) + +public: + explicit JSKitWebSocket(QJSEngine *engine, const QString &url, const QJSValue &protocols=QJSValue()); + + enum ReadyStates { + CONNECTING = 0, + OPEN = 1, + CLOSING = 2, + CLOSED = 3 + }; + Q_ENUMS(ReadyStates) + + Q_INVOKABLE void send(const QJSValue &data); + Q_INVOKABLE void close(quint32 code=1000, const QString &reason=QString()); + + void setOnclose(const QJSValue &onclose); + void setOnerror(const QJSValue &onerror); + void setOnmessage(const QJSValue &onmessage); + void setOnopen(const QJSValue &onopen); + + QJSValue onclose() const; + QJSValue onerror() const; + QJSValue onmessage() const; + QJSValue onopen() const; + + quint32 bufferedAmount(); + quint8 readyState(); + QString url(); + +private slots: + void handleConnected(); + void handleDisconnected(); + void handleError(QAbstractSocket::SocketError error); + void handleSslErrors(const QList<QSslError> &errors); + void handleTextMessageReceived(const QString &message); + void handleBinaryMessageReceived(const QByteArray &message); + +private: + void callOnmessage(QJSValue data); + +private: + QJSEngine *m_engine; + QWebSocket *m_webSocket; + + QString m_binaryType = "arraybuffer"; + quint32 m_bufferedAmount = 0; + QString m_extensions; + QJSValue m_onclose; + QJSValue m_onerror; + QJSValue m_onmessage; + QJSValue m_onopen; + QString m_protocol; + quint8 m_readyState = CONNECTING; + QString m_url; +}; + +#endif // JSKITWEBSOCKET_P_H |
