summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJavier <dev.git@javispedro.com>2014-12-01 02:21:30 +0100
committerJavier <dev.git@javispedro.com>2014-12-01 02:21:30 +0100
commit1e3794c476caf5c41360c36cc13c8425ec0dd26c (patch)
treef86693c5e17671f821871f95e462f299170277e0
parentcf405034b49e5e8ba7a8d22522878c8834b8d4ae (diff)
implement message passing around jskit apps and watch
-rw-r--r--daemon/appinfo.cpp26
-rw-r--r--daemon/appinfo.h8
-rw-r--r--daemon/appmsgmanager.cpp171
-rw-r--r--daemon/appmsgmanager.h17
-rw-r--r--daemon/daemon.pro6
-rw-r--r--daemon/jskitmanager.cpp25
-rw-r--r--daemon/jskitmanager.h5
-rw-r--r--daemon/jskitobjects.cpp35
-rw-r--r--daemon/jskitobjects.h14
-rw-r--r--daemon/manager.cpp2
-rw-r--r--daemon/packer.cpp91
-rw-r--r--daemon/packer.h67
-rw-r--r--daemon/unpacker.cpp2
-rw-r--r--daemon/watchconnector.cpp19
-rw-r--r--daemon/watchconnector.h4
15 files changed, 448 insertions, 44 deletions
diff --git a/daemon/appinfo.cpp b/daemon/appinfo.cpp
index a4442a3..e2406b8 100644
--- a/daemon/appinfo.cpp
+++ b/daemon/appinfo.cpp
@@ -10,7 +10,8 @@ struct AppInfoData : public QSharedData {
QString versionLabel;
bool watchface;
bool jskit;
- QHash<QString, int> appKeys;
+ QHash<QString, int> keyInts;
+ QHash<int, QString> keyNames;
QString path;
};
@@ -116,19 +117,30 @@ void AppInfo::setJSKit(bool b)
d->jskit = b;
}
-QHash<QString, int> AppInfo::appKeys() const
+void AppInfo::addAppKey(const QString &key, int value)
{
- return d->appKeys;
+ d->keyInts.insert(key, value);
+ d->keyNames.insert(value, key);
}
-void AppInfo::setAppKeys(const QHash<QString, int> &appKeys)
+bool AppInfo::hasAppKeyValue(int value) const
{
- d->appKeys = appKeys;
+ return d->keyNames.contains(value);
}
-void AppInfo::addAppKey(const QString &key, int value)
+QString AppInfo::appKeyForValue(int value) const
+{
+ return d->keyNames.value(value);
+}
+
+bool AppInfo::hasAppKey(const QString &key) const
+{
+ return d->keyInts.contains(key);
+}
+
+int AppInfo::valueForAppKey(const QString &key) const
{
- d->appKeys.insert(key, value);
+ return d->keyInts.value(key, -1);
}
QString AppInfo::path() const
diff --git a/daemon/appinfo.h b/daemon/appinfo.h
index da71dfc..038a708 100644
--- a/daemon/appinfo.h
+++ b/daemon/appinfo.h
@@ -52,10 +52,14 @@ public:
bool isJSKit() const;
void setJSKit(bool b);
- QHash<QString, int> appKeys() const;
- void setAppKeys(const QHash<QString, int> &string);
void addAppKey(const QString &key, int value);
+ bool hasAppKeyValue(int value) const;
+ QString appKeyForValue(int value) const;
+
+ bool hasAppKey(const QString &key) const;
+ int valueForAppKey(const QString &key) const;
+
QString path() const;
void setPath(const QString &string);
diff --git a/daemon/appmsgmanager.cpp b/daemon/appmsgmanager.cpp
index 23bf802..b620078 100644
--- a/daemon/appmsgmanager.cpp
+++ b/daemon/appmsgmanager.cpp
@@ -1,21 +1,28 @@
#include "appmsgmanager.h"
#include "unpacker.h"
+#include "packer.h"
// TODO D-Bus server for non JS kit apps!!!!
-AppMsgManager::AppMsgManager(WatchConnector *watch, QObject *parent)
- : QObject(parent), watch(watch)
+AppMsgManager::AppMsgManager(AppManager *apps, WatchConnector *watch, QObject *parent)
+ : QObject(parent), apps(apps), watch(watch), lastTransactionId(0)
{
watch->setEndpointHandler(WatchConnector::watchLAUNCHER,
[this](const QByteArray &data) {
if (data.at(0) == WatchConnector::appmsgPUSH) {
- Unpacker u(data);
- u.skip(1); // skip data.at(0) which we just already checked above.
- uint transaction = u.read<quint8>();
- QUuid uuid = u.readUuid();
- WatchConnector::Dict dict = u.readDict();
- if (u.bad() || !dict.contains(1)) {
- logger()->warn() << "Failed to parse LAUNCHER message";
+ uint transaction;
+ QUuid uuid;
+ WatchConnector::Dict dict;
+
+ if (!unpackPushMessage(data, &transaction, &uuid, &dict)) {
+ // Failed to parse!
+ // Since we're the only one handling this endpoint,
+ // all messages must be accepted
+ logger()->warn() << "Failed to parser LAUNCHER PUSH message";
+ return true;
+ }
+ if (!dict.contains(1)) {
+ logger()->warn() << "LAUNCHER message has no item in dict";
return true;
}
@@ -46,7 +53,26 @@ AppMsgManager::AppMsgManager(WatchConnector *watch, QObject *parent)
watch->setEndpointHandler(WatchConnector::watchAPPLICATION_MESSAGE,
[this](const QByteArray &data) {
switch (data.at(0)) {
- case WatchConnector::appmsgPUSH:
+ case WatchConnector::appmsgPUSH: {
+ uint transaction;
+ QUuid uuid;
+ WatchConnector::Dict dict;
+
+ if (!unpackPushMessage(data, &transaction, &uuid, &dict)) {
+ logger()->warn() << "Failed to parse APP_MSG PUSH";
+ return true;
+ }
+
+ logger()->debug() << "Received appmsg PUSH from" << uuid << "with" << dict;
+
+ QVariantMap data = mapAppKeys(uuid, dict);
+ logger()->debug() << "Mapped dict" << data;
+
+ emit messageReceived(uuid, data);
+ break;
+ }
+ default:
+ logger()->warn() << "Unknown application message type:" << data.at(0);
break;
}
@@ -54,9 +80,132 @@ AppMsgManager::AppMsgManager(WatchConnector *watch, QObject *parent)
});
}
+void AppMsgManager::send(const QUuid &uuid, const QVariantMap &data, const std::function<void ()> &ackCallback, const std::function<void ()> &nackCallback)
+{
+ WatchConnector::Dict dict = mapAppKeys(uuid, data);
+ quint8 transaction = ++lastTransactionId;
+ QByteArray msg = buildPushMessage(transaction, uuid, dict);
+
+ logger()->debug() << "Sending appmsg" << transaction << "to" << uuid << "with" << dict;
+
+ WatchConnector::Dict t_dict;
+ QUuid t_uuid;
+ uint t_trans;
+ if (unpackPushMessage(msg, &t_trans, &t_uuid, &t_dict)) {
+ logger()->debug() << t_trans << t_uuid << t_dict;
+ } else {
+ logger()->warn() << "not unpack my own";
+ }
+
+
+ watch->sendMessage(WatchConnector::watchAPPLICATION_MESSAGE, msg,
+ [this, ackCallback, nackCallback, transaction](const QByteArray &reply) {
+ if (reply.size() < 2) return false;
+
+ quint8 type = reply[0];
+ quint8 recv_transaction = reply[1];
+
+ logger()->debug() << "Got response to transaction" << transaction;
+
+ if (recv_transaction != transaction) return false;
+
+ switch (type) {
+ case WatchConnector::appmsgACK:
+ logger()->debug() << "Got ACK to transaction" << transaction;
+ if (ackCallback) ackCallback();
+ return true;
+ case WatchConnector::appmsgNACK:
+ logger()->info() << "Got NACK to transaction" << transaction;
+ if (nackCallback) nackCallback();
+ return true;
+ default:
+ return false;
+ }
+ });
+}
+
void AppMsgManager::send(const QUuid &uuid, const QVariantMap &data)
{
- // TODO
+ std::function<void()> nullCallback;
+ send(uuid, data, nullCallback, nullCallback);
+}
+
+WatchConnector::Dict AppMsgManager::mapAppKeys(const QUuid &uuid, const QVariantMap &data)
+{
+ AppInfo info = apps->info(uuid);
+ if (info.uuid() != uuid) {
+ logger()->warn() << "Unknown app GUID while sending message:" << uuid;
+ }
+
+ WatchConnector::Dict d;
+
+ for (QVariantMap::const_iterator it = data.constBegin(); it != data.constEnd(); ++it) {
+ if (info.hasAppKey(it.key())) {
+ d.insert(info.valueForAppKey(it.key()), it.value());
+ } else {
+ // Even if we do not know about this appkey, try to see if it's already a numeric key we
+ // can send to the watch.
+ bool ok = false;
+ int num = it.key().toInt(&ok);
+ if (ok) {
+ d.insert(num, it.value());
+ } else {
+ logger()->warn() << "Unknown appKey" << it.key() << "for app with GUID" << uuid;
+ }
+ }
+ }
+
+ return d;
+}
+
+QVariantMap AppMsgManager::mapAppKeys(const QUuid &uuid, const WatchConnector::Dict &dict)
+{
+ AppInfo info = apps->info(uuid);
+ if (info.uuid() != uuid) {
+ logger()->warn() << "Unknown app GUID while sending message:" << uuid;
+ }
+
+ QVariantMap data;
+
+ for (WatchConnector::Dict::const_iterator it = dict.constBegin(); it != dict.constEnd(); ++it) {
+ if (info.hasAppKeyValue(it.key())) {
+ data.insert(info.appKeyForValue(it.key()), it.value());
+ } else {
+ logger()->warn() << "Unknown appKey value" << it.key() << "for app with GUID" << uuid;
+ data.insert(QString::number(it.key()), it.value());
+ }
+ }
+
+ return data;
+}
+
+bool AppMsgManager::unpackPushMessage(const QByteArray &msg, uint *transaction, QUuid *uuid, WatchConnector::Dict *dict)
+{
+ Unpacker u(msg);
+ quint8 code = u.read<quint8>();
+ Q_ASSERT(code == WatchConnector::appmsgPUSH);
+
+ *transaction = u.read<quint8>();
+ *uuid = u.readUuid();
+ *dict = u.readDict();
+
+ if (u.bad()) {
+ return false;
+ }
+
+ return true;
+}
+
+QByteArray AppMsgManager::buildPushMessage(uint transaction, const QUuid &uuid, const WatchConnector::Dict &dict)
+{
+ QByteArray ba;
+ Packer p(&ba);
+ p.write<quint8>(WatchConnector::appmsgPUSH);
+ p.write<quint8>(transaction);
+ p.writeUuid(uuid);
+ p.writeDict(dict);
+
+ return ba;
}
QByteArray AppMsgManager::buildAckMessage(uint transaction)
diff --git a/daemon/appmsgmanager.h b/daemon/appmsgmanager.h
index 651d84e..ca1d484 100644
--- a/daemon/appmsgmanager.h
+++ b/daemon/appmsgmanager.h
@@ -2,6 +2,7 @@
#define APPMSGMANAGER_H
#include "watchconnector.h"
+#include "appmanager.h"
class AppMsgManager : public QObject
{
@@ -9,7 +10,11 @@ class AppMsgManager : public QObject
LOG4QT_DECLARE_QCLASS_LOGGER
public:
- explicit AppMsgManager(WatchConnector *watch, QObject *parent);
+ explicit AppMsgManager(AppManager *apps, WatchConnector *watch, QObject *parent);
+
+ void send(const QUuid &uuid, const QVariantMap &data,
+ const std::function<void()> &ackCallback,
+ const std::function<void()> &nackCallback);
public slots:
void send(const QUuid &uuid, const QVariantMap &data);
@@ -17,14 +22,22 @@ public slots:
signals:
void appStarted(const QUuid &uuid);
void appStopped(const QUuid &uuid);
- void dataReceived(const QUuid &uuid, const QVariantMap &data);
+ void messageReceived(const QUuid &uuid, const QVariantMap &data);
private:
+ WatchConnector::Dict mapAppKeys(const QUuid &uuid, const QVariantMap &data);
+ QVariantMap mapAppKeys(const QUuid &uuid, const WatchConnector::Dict &dict);
+
+ static bool unpackPushMessage(const QByteArray &msg, uint *transaction, QUuid *uuid, WatchConnector::Dict *dict);
+
+ static QByteArray buildPushMessage(uint transaction, const QUuid &uuid, const WatchConnector::Dict &dict);
static QByteArray buildAckMessage(uint transaction);
static QByteArray buildNackMessage(uint transaction);
private:
+ AppManager *apps;
WatchConnector *watch;
+ quint8 lastTransactionId;
};
#endif // APPMSGMANAGER_H
diff --git a/daemon/daemon.pro b/daemon/daemon.pro
index a6631df..c59d408 100644
--- a/daemon/daemon.pro
+++ b/daemon/daemon.pro
@@ -28,7 +28,8 @@ SOURCES += \
appmsgmanager.cpp \
jskitmanager.cpp \
appinfo.cpp \
- jskitobjects.cpp
+ jskitobjects.cpp \
+ packer.cpp
HEADERS += \
manager.h \
@@ -46,7 +47,8 @@ HEADERS += \
appmsgmanager.h \
jskitmanager.h \
appinfo.h \
- jskitobjects.h
+ jskitobjects.h \
+ packer.h
OTHER_FILES += \
org.pebbled.xml \
diff --git a/daemon/jskitmanager.cpp b/daemon/jskitmanager.cpp
index 2da6c09..f8ec34a 100644
--- a/daemon/jskitmanager.cpp
+++ b/daemon/jskitmanager.cpp
@@ -9,6 +9,7 @@ JSKitManager::JSKitManager(AppManager *apps, AppMsgManager *appmsg, QObject *par
{
connect(_appmsg, &AppMsgManager::appStarted, this, &JSKitManager::handleAppStarted);
connect(_appmsg, &AppMsgManager::appStopped, this, &JSKitManager::handleAppStopped);
+ connect(_appmsg, &AppMsgManager::messageReceived, this, &JSKitManager::handleAppMessage);
}
JSKitManager::~JSKitManager()
@@ -40,6 +41,23 @@ void JSKitManager::handleAppStopped(const QUuid &uuid)
}
}
+void JSKitManager::handleAppMessage(const QUuid &uuid, const QVariantMap &data)
+{
+ if (_curApp.uuid() == uuid) {
+ logger()->debug() << "received a message for the current JSKit app";
+
+ if (!_engine) {
+ logger()->debug() << "but engine is stopped";
+ return;
+ }
+
+ QJSValue eventObj = _engine->newObject();
+ eventObj.setProperty("payload", _engine->toScriptValue(data));
+
+ _jspebble->invokeCallbacks("appmessage", QJSValueList({eventObj}));
+ }
+}
+
void JSKitManager::startJsApp()
{
if (_engine) stopJsApp();
@@ -49,7 +67,8 @@ void JSKitManager::startJsApp()
}
_engine = new QJSEngine(this);
- _jspebble = new JSKitPebble(this);
+ _jspebble = new JSKitPebble(_curApp, this);
+ _jsconsole = new JSKitConsole(this);
_jsstorage = new JSKitLocalStorage(_curApp.uuid(), this);
logger()->debug() << "starting JS app";
@@ -57,8 +76,12 @@ void JSKitManager::startJsApp()
QJSValue globalObj = _engine->globalObject();
globalObj.setProperty("Pebble", _engine->newQObject(_jspebble));
+ globalObj.setProperty("console", _engine->newQObject(_jsconsole));
globalObj.setProperty("localStorage", _engine->newQObject(_jsstorage));
+ QJSValue windowObj = _engine->newObject();
+ windowObj.setProperty("localStorage", globalObj.property("localStorage"));
+ globalObj.setProperty("window", windowObj);
QFile scriptFile(_curApp.path() + "/pebble-js-app.js");
if (!scriptFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
diff --git a/daemon/jskitmanager.h b/daemon/jskitmanager.h
index f25a96f..d09bf54 100644
--- a/daemon/jskitmanager.h
+++ b/daemon/jskitmanager.h
@@ -6,6 +6,7 @@
#include "appmsgmanager.h"
class JSKitPebble;
+class JSKitConsole;
class JSKitLocalStorage;
class JSKitManager : public QObject
@@ -18,12 +19,14 @@ public:
~JSKitManager();
signals:
+ void appNotification(const QUuid &uuid, const QString &title, const QString &body);
public slots:
private slots:
void handleAppStarted(const QUuid &uuid);
void handleAppStopped(const QUuid &uuid);
+ void handleAppMessage(const QUuid &uuid, const QVariantMap &data);
private:
void startJsApp();
@@ -37,8 +40,8 @@ private:
AppInfo _curApp;
QJSEngine *_engine;
QPointer<JSKitPebble> _jspebble;
+ QPointer<JSKitConsole> _jsconsole;
QPointer<JSKitLocalStorage> _jsstorage;
-
};
#endif // JSKITMANAGER_H
diff --git a/daemon/jskitobjects.cpp b/daemon/jskitobjects.cpp
index f40138a..aecc55d 100644
--- a/daemon/jskitobjects.cpp
+++ b/daemon/jskitobjects.cpp
@@ -4,8 +4,8 @@
#include <QDir>
#include "jskitobjects.h"
-JSKitPebble::JSKitPebble(JSKitManager *mgr)
- : QObject(mgr), _mgr(mgr)
+JSKitPebble::JSKitPebble(const AppInfo &info, JSKitManager *mgr)
+ : QObject(mgr), _appInfo(info), _mgr(mgr)
{
}
@@ -34,17 +34,28 @@ void JSKitPebble::removeEventListener(const QString &type, QJSValue function)
void JSKitPebble::sendAppMessage(QJSValue message, QJSValue callbackForAck, QJSValue callbackForNack)
{
- // TODO contact _mgr->appmsg->...
- logger()->debug() << "sendAppMessage" << message.toString();
+ QVariantMap data = message.toVariant().toMap();
+
+ logger()->debug() << "sendAppMessage" << data;
+
+ _mgr->_appmsg->send(_appInfo.uuid(), data, [this, callbackForAck]() mutable {
+ logger()->debug() << "Invoking ack callback";
+ callbackForAck.call();
+ }, [this, callbackForNack]() mutable {
+ logger()->debug() << "Invoking nack callback";
+ callbackForNack.call();
+ });
}
void JSKitPebble::showSimpleNotificationOnPebble(const QString &title, const QString &body)
{
logger()->debug() << "showSimpleNotificationOnPebble" << title << body;
+ emit _mgr->appNotification(_appInfo.uuid(), title, body);
}
void JSKitPebble::openUrl(const QUrl &url)
{
+ logger()->debug() << "opening url" << url.toString();
if (!QDesktopServices::openUrl(url)) {
logger()->warn() << "Failed to open URL:" << url;
}
@@ -56,6 +67,7 @@ void JSKitPebble::invokeCallbacks(const QString &type, const QJSValueList &args)
QList<QJSValue> &callbacks = _callbacks[type];
for (QList<QJSValue>::iterator it = callbacks.begin(); it != callbacks.end(); ++it) {
+ logger()->debug() << "invoking callback" << type << it->toString();
QJSValue result = it->call(args);
if (result.isError()) {
logger()->warn() << "error while invoking callback" << type << it->toString() << ":"
@@ -64,6 +76,16 @@ void JSKitPebble::invokeCallbacks(const QString &type, const QJSValueList &args)
}
}
+JSKitConsole::JSKitConsole(JSKitManager *mgr)
+ : QObject(mgr)
+{
+}
+
+void JSKitConsole::log(const QString &msg)
+{
+ logger()->info() << msg;
+}
+
JSKitLocalStorage::JSKitLocalStorage(const QUuid &uuid, JSKitManager *mgr)
: QObject(mgr), _storage(new QSettings(getStorageFileFor(uuid), QSettings::IniFormat, this))
{
@@ -117,5 +139,8 @@ QString JSKitLocalStorage::getStorageFileFor(const QUuid &uuid)
{
QDir dataDir(QStandardPaths::writableLocation(QStandardPaths::DataLocation));
dataDir.mkdir("js-storage");
- return dataDir.absoluteFilePath("js-storage/" + uuid.toString() + ".ini");
+ QString fileName = uuid.toString();
+ fileName.remove('{');
+ fileName.remove('}');
+ return dataDir.absoluteFilePath("js-storage/" + fileName + ".ini");
}
diff --git a/daemon/jskitobjects.h b/daemon/jskitobjects.h
index 2375084..c59bfac 100644
--- a/daemon/jskitobjects.h
+++ b/daemon/jskitobjects.h
@@ -10,7 +10,7 @@ class JSKitPebble : public QObject
LOG4QT_DECLARE_QCLASS_LOGGER
public:
- explicit JSKitPebble(JSKitManager *mgr);
+ explicit JSKitPebble(const AppInfo &appInfo, JSKitManager *mgr);
Q_INVOKABLE void addEventListener(const QString &type, QJSValue function);
Q_INVOKABLE void removeEventListener(const QString &type, QJSValue function);
@@ -24,10 +24,22 @@ public:
void invokeCallbacks(const QString &type, const QJSValueList &args = QJSValueList());
private:
+ AppInfo _appInfo;
JSKitManager *_mgr;
QHash<QString, QList<QJSValue>> _callbacks;
};
+class JSKitConsole : public QObject
+{
+ Q_OBJECT
+ LOG4QT_DECLARE_QCLASS_LOGGER
+
+public:
+ explicit JSKitConsole(JSKitManager *mgr);
+
+ Q_INVOKABLE void log(const QString &msg);
+};
+
class JSKitLocalStorage : public QObject
{
Q_OBJECT
diff --git a/daemon/manager.cpp b/daemon/manager.cpp
index 778fdc6..8d41c89 100644
--- a/daemon/manager.cpp
+++ b/daemon/manager.cpp
@@ -14,7 +14,7 @@ Manager::Manager(Settings *settings, QObject *parent) :
notifications(new NotificationManager(settings, this)),
music(new MusicManager(watch, this)),
datalog(new DataLogManager(watch, this)),
- appmsg(new AppMsgManager(watch, this)),
+ appmsg(new AppMsgManager(apps, watch, this)),
js(new JSKitManager(apps, appmsg, this)),
notification(MNotification::DeviceEvent)
{
diff --git a/daemon/packer.cpp b/daemon/packer.cpp
new file mode 100644
index 0000000..569f7a8
--- /dev/null
+++ b/daemon/packer.cpp
@@ -0,0 +1,91 @@
+#include "packer.h"
+#include "watchconnector.h"
+
+void Packer::writeBytes(int n, const QByteArray &b)
+{
+ if (b.size() > n) {
+ _buf->append(b.constData(), n);
+ } else {
+ int diff = n - b.size();
+ _buf->append(b);
+ if (diff > 0) {
+ _buf->append(QByteArray(diff, '\0'));
+ }
+ }
+}
+
+void Packer::writeUuid(const QUuid &uuid)
+{
+ writeBytes(16, uuid.toRfc4122());
+}
+
+void Packer::writeDict(const QMap<int, QVariant> &d)
+{
+ int size = d.size();
+ if (size > 0xFF) {
+ logger()->warn() << "Dictionary is too large to encode";
+ writeLE<quint8>(0);
+ return;
+ }
+
+ writeLE<quint8>(size);
+
+ for (QMap<int, QVariant>::const_iterator it = d.constBegin(); it != d.constEnd(); ++it) {
+ writeLE<quint32>(it.key());
+
+ switch (int(it.value().type())) {
+ case QMetaType::Char:
+ writeLE<quint8>(WatchConnector::typeINT);
+ writeLE<quint16>(sizeof(char));
+ writeLE<char>(it.value().value<char>());
+ break;
+ case QMetaType::Short:
+ writeLE<quint8>(WatchConnector::typeINT);
+ writeLE<quint16>(sizeof(short));
+ writeLE<short>(it.value().value<short>());
+ break;
+ case QMetaType::Int:
+ writeLE<quint8>(WatchConnector::typeINT);
+ writeLE<quint16>(sizeof(int));
+ writeLE<int>(it.value().value<int>());
+ break;
+
+ case QMetaType::UChar:
+ writeLE<quint8>(WatchConnector::typeINT);
+ writeLE<quint16>(sizeof(char));
+ writeLE<char>(it.value().value<char>());
+ break;
+ case QMetaType::UShort:
+ writeLE<quint8>(WatchConnector::typeINT);
+ writeLE<quint16>(sizeof(short));
+ writeLE<short>(it.value().value<short>());
+ break;
+ case QMetaType::UInt:
+ writeLE<quint8>(WatchConnector::typeINT);
+ writeLE<quint16>(sizeof(int));
+ writeLE<int>(it.value().value<int>());
+ break;
+
+ case QMetaType::QByteArray: {
+ QByteArray ba = it.value().toByteArray();
+ writeLE<quint8>(WatchConnector::typeBYTES);
+ writeLE<quint16>(ba.size());
+ _buf->append(ba);
+ break;
+ }
+
+ default:
+ logger()->warn() << "Unknown dict item type:" << it.value().typeName();
+ /* Fallthrough */
+ case QMetaType::QString:
+ case QMetaType::QUrl:
+ {
+ QByteArray s = it.value().toString().toUtf8();
+ writeLE<quint8>(WatchConnector::typeSTRING);
+ writeLE<quint16>(s.size());
+ _buf->append(s);
+ break;
+ }
+ }
+ }
+}
diff --git a/daemon/packer.h b/daemon/packer.h
new file mode 100644
index 0000000..d22072c
--- /dev/null
+++ b/daemon/packer.h
@@ -0,0 +1,67 @@
+#ifndef PACKER_H
+#define PACKER_H
+
+#include <QtEndian>
+#include <QByteArray>
+#include <QString>
+#include <QUuid>
+#include <QVariantMap>
+#include <Log4Qt/Logger>
+
+class Packer
+{
+ LOG4QT_DECLARE_STATIC_LOGGER(logger, Packer)
+
+public:
+ Packer(QByteArray *buf);
+
+ template <typename T>
+ void write(T v);
+
+ template <typename T>
+ void writeLE(T v);
+
+ void writeBytes(int n, const QByteArray &b);
+
+ void writeFixedString(int n, const QString &s);
+
+ void writeUuid(const QUuid &uuid);
+
+ void writeDict(const QMap<int, QVariant> &d);
+
+private:
+ char *p(int n);
+ uchar *up(int n);
+ QByteArray *_buf;
+};
+
+inline Packer::Packer(QByteArray *buf)
+ : _buf(buf)
+{
+}
+
+template <typename T>
+void Packer::write(T v)
+{
+ qToBigEndian(v, up(sizeof(T)));
+}
+
+template <typename T>
+void Packer::writeLE(T v)
+{
+ qToLittleEndian(v, up(sizeof(T)));
+}
+
+inline char * Packer::p(int n)
+{
+ int size = _buf->size();
+ _buf->resize(size + n);
+ return &_buf->data()[size];
+}
+
+inline uchar * Packer::up(int n)
+{
+ return reinterpret_cast<uchar *>(p(n));
+}
+
+#endif // PACKER_H
diff --git a/daemon/unpacker.cpp b/daemon/unpacker.cpp
index fc38020..e904db8 100644
--- a/daemon/unpacker.cpp
+++ b/daemon/unpacker.cpp
@@ -29,7 +29,7 @@ QMap<int, QVariant> Unpacker::readDict()
QMap<int, QVariant> d;
if (checkBad(1)) return d;
- const int n = read<quint8>();
+ const int n = readLE<quint8>();
for (int i = 0; i < n; i++) {
if (checkBad(4 + 1 + 2)) return d;
diff --git a/daemon/watchconnector.cpp b/daemon/watchconnector.cpp
index a3ea181..dd95821 100644
--- a/daemon/watchconnector.cpp
+++ b/daemon/watchconnector.cpp
@@ -89,7 +89,7 @@ QString WatchConnector::decodeEndpoint(uint val)
return endpoint ? QString(endpoint) : QString("watchUNKNOWN_%1").arg(val);
}
-void WatchConnector::setEndpointHandler(uint endpoint, EndpointHandlerFunc func)
+void WatchConnector::setEndpointHandler(uint endpoint, const EndpointHandlerFunc &func)
{
if (func) {
handlers.insert(endpoint, func);
@@ -241,6 +241,7 @@ void WatchConnector::sendData(const QByteArray &data)
reconnect();
} else if (is_connected) {
logger()->debug() << "Writing" << data.length() << "bytes to socket";
+ logger()->debug() << data.toHex();
socket->write(data);
}
}
@@ -251,7 +252,7 @@ void WatchConnector::onBytesWritten(qint64 bytes)
logger()->debug() << "Socket written" << bytes << "bytes," << writeData.length() << "left";
}
-void WatchConnector::sendMessage(uint endpoint, const QByteArray &data)
+void WatchConnector::sendMessage(uint endpoint, const QByteArray &data, const EndpointHandlerFunc &callback)
{
logger()->debug() << "sending message to endpoint" << decodeEndpoint(endpoint);
QByteArray msg;
@@ -268,6 +269,10 @@ void WatchConnector::sendMessage(uint endpoint, const QByteArray &data)
msg.append(data);
sendData(msg);
+
+ if (callback) {
+ tmpHandlers[endpoint].append(callback);
+ }
}
void WatchConnector::buildData(QByteArray &res, QStringList data)
@@ -445,9 +450,8 @@ void WatchConnector::endPhoneCall(uint cookie)
void WatchConnector::getAppbankStatus(const std::function<void(const QString &s)>& callback)
{
- sendMessage(watchAPP_MANAGER, QByteArray(1, appmgrGET_APPBANK_STATUS));
-
- tmpHandlers[watchAPP_MANAGER].append([this, callback](const QByteArray &data) {
+ sendMessage(watchAPP_MANAGER, QByteArray(1, appmgrGET_APPBANK_STATUS),
+ [this, callback](const QByteArray &data) {
if (data.at(0) != appmgrGET_APPBANK_STATUS) {
return false;
}
@@ -491,9 +495,8 @@ void WatchConnector::getAppbankStatus(const std::function<void(const QString &s)
void WatchConnector::getAppbankUuids(const function<void(const QList<QUuid> &)>& callback)
{
- sendMessage(watchAPP_MANAGER, QByteArray(1, appmgrGET_APPBANK_UUIDS));
-
- tmpHandlers[watchAPP_MANAGER].append([this, callback](const QByteArray &data) {
+ sendMessage(watchAPP_MANAGER, QByteArray(1, appmgrGET_APPBANK_UUIDS),
+ [this, callback](const QByteArray &data) {
if (data.at(0) != appmgrGET_APPBANK_UUIDS) {
return false;
}
diff --git a/daemon/watchconnector.h b/daemon/watchconnector.h
index 8a7d574..6c7fdd4 100644
--- a/daemon/watchconnector.h
+++ b/daemon/watchconnector.h
@@ -173,7 +173,7 @@ public:
inline bool isConnected() const { return is_connected; }
inline QString name() const { return socket != nullptr ? socket->peerName() : ""; }
- void setEndpointHandler(uint endpoint, EndpointHandlerFunc func);
+ void setEndpointHandler(uint endpoint, const EndpointHandlerFunc &func);
void clearEndpointHandler(uint endpoint);
static QString timeStamp();
@@ -192,7 +192,7 @@ public slots:
void disconnect();
void reconnect();
- void sendMessage(uint endpoint, const QByteArray &data);
+ void sendMessage(uint endpoint, const QByteArray &data, const EndpointHandlerFunc &callback = EndpointHandlerFunc());
void ping(uint val);
void time();