summaryrefslogtreecommitdiff
path: root/daemon
diff options
context:
space:
mode:
authorJavier <dev.git@javispedro.com>2014-11-30 20:58:57 +0100
committerJavier <dev.git@javispedro.com>2014-11-30 20:58:57 +0100
commitf7c8244641a4242f6a8c706bd918494b23e48075 (patch)
treef84b5ead8f4d621cf47e10489889fb9fef8b1f61 /daemon
parent4527ab9a4147a8f15bf8ca5613341df9d0029d0c (diff)
introduce the AppMsgManager and the JsKitManager
will be used to handle application messages (push, etc) while the JSKitManager will run PebbleKit JS scripts. also add the ability to unpack PebbleDicts
Diffstat (limited to 'daemon')
-rw-r--r--daemon/appmanager.cpp15
-rw-r--r--daemon/appmanager.h3
-rw-r--r--daemon/appmsgmanager.cpp77
-rw-r--r--daemon/appmsgmanager.h30
-rw-r--r--daemon/daemon.pro12
-rw-r--r--daemon/jskitmanager.cpp77
-rw-r--r--daemon/jskitmanager.h41
-rw-r--r--daemon/jskitmanager_p.h15
-rw-r--r--daemon/manager.cpp15
-rw-r--r--daemon/manager.h8
-rw-r--r--daemon/unpacker.cpp88
-rw-r--r--daemon/unpacker.h29
-rw-r--r--daemon/watchconnector.h12
13 files changed, 395 insertions, 27 deletions
diff --git a/daemon/appmanager.cpp b/daemon/appmanager.cpp
index 34af3af..d06681e 100644
--- a/daemon/appmanager.cpp
+++ b/daemon/appmanager.cpp
@@ -29,6 +29,21 @@ QStringList AppManager::appPaths() const
QStandardPaths::LocateDirectory);
}
+const AppManager::AppInfo & AppManager::info(const QUuid &uuid) const
+{
+ return _apps.value(uuid);
+}
+
+const AppManager::AppInfo & AppManager::info(const QString &name) const
+{
+ QUuid uuid = _names.value(name);
+ if (!uuid.isNull()) {
+ return info(uuid);
+ } else {
+ return AppInfo();
+ }
+}
+
void AppManager::rescan()
{
QStringList watchedDirs = _watcher->directories();
diff --git a/daemon/appmanager.h b/daemon/appmanager.h
index 5e150ab..dc2a979 100644
--- a/daemon/appmanager.h
+++ b/daemon/appmanager.h
@@ -30,7 +30,8 @@ public:
QStringList appPaths() const;
- bool installPebbleApp(const QString &pbwFile);
+ const AppInfo & info(const QUuid &uuid) const;
+ const AppInfo & info(const QString &shortName) const;
public slots:
void rescan();
diff --git a/daemon/appmsgmanager.cpp b/daemon/appmsgmanager.cpp
new file mode 100644
index 0000000..9eb948e
--- /dev/null
+++ b/daemon/appmsgmanager.cpp
@@ -0,0 +1,77 @@
+#include "appmsgmanager.h"
+#include "unpacker.h"
+
+// TODO D-Bus server for non JS kit apps!!!!
+
+AppMsgManager::AppMsgManager(WatchConnector *watch, QObject *parent)
+ : QObject(parent), watch(watch)
+{
+ watch->setEndpointHandler(WatchConnector::watchLAUNCHER,
+ [this](const QByteArray &data) {
+ if (data.at(0) == WatchConnector::appmsgPUSH) {
+ logger()->debug() << "LAUNCHER is PUSHing" << data.toHex();
+ 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";
+ return true;
+ }
+
+ switch (dict.value(1).toInt()) {
+ case WatchConnector::launcherSTARTED:
+ logger()->debug() << "App starting in watch:" << uuid;
+ this->watch->sendMessage(WatchConnector::watchLAUNCHER,
+ buildAckMessage(transaction));
+ emit appStarted(uuid);
+ break;
+ case WatchConnector::launcherSTOPPED:
+ logger()->debug() << "App stopping in watch:" << uuid;
+ this->watch->sendMessage(WatchConnector::watchLAUNCHER,
+ buildAckMessage(transaction));
+ emit appStopped(uuid);
+ break;
+ default:
+ logger()->warn() << "LAUNCHER pushed unknown message:" << uuid << dict;
+ this->watch->sendMessage(WatchConnector::watchLAUNCHER,
+ buildNackMessage(transaction));
+ break;
+ }
+ }
+
+ return true;
+ });
+
+ watch->setEndpointHandler(WatchConnector::watchAPPLICATION_MESSAGE,
+ [this](const QByteArray &data) {
+ switch (data.at(0)) {
+ case WatchConnector::appmsgPUSH:
+ break;
+ }
+
+ return true;
+ });
+}
+
+void AppMsgManager::send(const QUuid &uuid, const QVariantMap &data)
+{
+ // TODO
+}
+
+QByteArray AppMsgManager::buildAckMessage(uint transaction)
+{
+ QByteArray ba(2, Qt::Uninitialized);
+ ba[0] = WatchConnector::appmsgACK;
+ ba[1] = transaction;
+ return ba;
+}
+
+QByteArray AppMsgManager::buildNackMessage(uint transaction)
+{
+ QByteArray ba(2, Qt::Uninitialized);
+ ba[0] = WatchConnector::appmsgNACK;
+ ba[1] = transaction;
+ return ba;
+}
diff --git a/daemon/appmsgmanager.h b/daemon/appmsgmanager.h
new file mode 100644
index 0000000..651d84e
--- /dev/null
+++ b/daemon/appmsgmanager.h
@@ -0,0 +1,30 @@
+#ifndef APPMSGMANAGER_H
+#define APPMSGMANAGER_H
+
+#include "watchconnector.h"
+
+class AppMsgManager : public QObject
+{
+ Q_OBJECT
+ LOG4QT_DECLARE_QCLASS_LOGGER
+
+public:
+ explicit AppMsgManager(WatchConnector *watch, QObject *parent);
+
+public slots:
+ void send(const QUuid &uuid, const QVariantMap &data);
+
+signals:
+ void appStarted(const QUuid &uuid);
+ void appStopped(const QUuid &uuid);
+ void dataReceived(const QUuid &uuid, const QVariantMap &data);
+
+private:
+ static QByteArray buildAckMessage(uint transaction);
+ static QByteArray buildNackMessage(uint transaction);
+
+private:
+ WatchConnector *watch;
+};
+
+#endif // APPMSGMANAGER_H
diff --git a/daemon/daemon.pro b/daemon/daemon.pro
index d4d7dbf..21c15c8 100644
--- a/daemon/daemon.pro
+++ b/daemon/daemon.pro
@@ -4,7 +4,7 @@ CONFIG += console
CONFIG += link_pkgconfig
QT -= gui
-QT += bluetooth dbus contacts
+QT += bluetooth dbus contacts qml
PKGCONFIG += mlite5 icu-i18n
CONFIG += c++11
@@ -23,7 +23,10 @@ SOURCES += \
dbusadaptor.cpp \
appmanager.cpp \
musicmanager.cpp \
- datalogmanager.cpp
+ datalogmanager.cpp \
+ unpacker.cpp \
+ appmsgmanager.cpp \
+ jskitmanager.cpp
HEADERS += \
manager.h \
@@ -37,7 +40,10 @@ HEADERS += \
appmanager.h \
musicmanager.h \
unpacker.h \
- datalogmanager.h
+ datalogmanager.h \
+ appmsgmanager.h \
+ jskitmanager.h \
+ jskitmanager_p.h
OTHER_FILES += \
org.pebbled.xml \
diff --git a/daemon/jskitmanager.cpp b/daemon/jskitmanager.cpp
new file mode 100644
index 0000000..698b22b
--- /dev/null
+++ b/daemon/jskitmanager.cpp
@@ -0,0 +1,77 @@
+#include <QQmlEngine>
+#include <QJSValueIterator>
+#include "jskitmanager.h"
+#include "jskitmanager_p.h"
+
+JSKitPebble::JSKitPebble(JSKitManager *mgr)
+ : QObject(mgr)
+{
+}
+
+JSKitPebble::~JSKitPebble()
+{
+}
+
+JSKitManager::JSKitManager(AppManager *apps, AppMsgManager *appmsg, QObject *parent) :
+ QObject(parent), _apps(apps), _appmsg(appmsg), _engine(0)
+{
+ connect(_appmsg, &AppMsgManager::appStarted, this, &JSKitManager::handleAppStarted);
+ connect(_appmsg, &AppMsgManager::appStopped, this, &JSKitManager::handleAppStopped);
+}
+
+JSKitManager::~JSKitManager()
+{
+ if (_engine) {
+ stopJsApp();
+ }
+}
+
+void JSKitManager::handleAppStarted(const QUuid &uuid)
+{
+ const auto &info = _apps->info(uuid);
+ if (!info.uuid.isNull() && info.isJSKit) {
+ logger()->debug() << "Preparing to start JSKit app" << info.uuid << info.shortName;
+ _curApp = info;
+ startJsApp();
+ }
+}
+
+void JSKitManager::handleAppStopped(const QUuid &uuid)
+{
+ if (!_curApp.uuid.isNull()) {
+ if (_curApp.uuid != uuid) {
+ logger()->warn() << "Closed app with invalid UUID";
+ }
+
+ _curApp = AppManager::AppInfo();
+ }
+}
+
+void JSKitManager::startJsApp()
+{
+ if (_engine) stopJsApp();
+ _engine = new QJSEngine(this);
+ _jspebble = new JSKitPebble(this);
+
+ QJSValue globalObj = _engine->globalObject();
+
+ globalObj.setProperty("Pebble", _engine->newQObject(_jspebble));
+
+ QJSValueIterator it(globalObj);
+ while (it.hasNext()) {
+ it.next();
+ logger()->debug() << "JS property:" << it.name();
+ }
+}
+
+void JSKitManager::stopJsApp()
+{
+ if (!_engine) return; // Nothing to do!
+
+ _engine->collectGarbage();
+
+ delete _engine;
+ _engine = 0;
+ delete _jspebble;
+ _jspebble = 0;
+}
diff --git a/daemon/jskitmanager.h b/daemon/jskitmanager.h
new file mode 100644
index 0000000..5e2880f
--- /dev/null
+++ b/daemon/jskitmanager.h
@@ -0,0 +1,41 @@
+#ifndef JSKITMANAGER_H
+#define JSKITMANAGER_H
+
+#include <QJSEngine>
+#include "appmanager.h"
+#include "appmsgmanager.h"
+
+class JSKitPebble;
+
+class JSKitManager : public QObject
+{
+ Q_OBJECT
+ LOG4QT_DECLARE_QCLASS_LOGGER
+
+public:
+ explicit JSKitManager(AppManager *apps, AppMsgManager *appmsg, QObject *parent = 0);
+ ~JSKitManager();
+
+signals:
+
+public slots:
+
+private slots:
+ void handleAppStarted(const QUuid &uuid);
+ void handleAppStopped(const QUuid &uuid);
+
+private:
+ void startJsApp();
+ void stopJsApp();
+
+private:
+ friend class JSKitPebble;
+
+ AppManager *_apps;
+ AppMsgManager *_appmsg;
+ AppManager::AppInfo _curApp;
+ QJSEngine *_engine;
+ QPointer<JSKitPebble> _jspebble;
+};
+
+#endif // JSKITMANAGER_H
diff --git a/daemon/jskitmanager_p.h b/daemon/jskitmanager_p.h
new file mode 100644
index 0000000..690a0ec
--- /dev/null
+++ b/daemon/jskitmanager_p.h
@@ -0,0 +1,15 @@
+#ifndef JSKITMANAGER_P_H
+#define JSKITMANAGER_P_H
+
+#include "jskitmanager.h"
+
+class JSKitPebble : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit JSKitPebble(JSKitManager *mgr);
+ ~JSKitPebble();
+};
+
+#endif // JSKITMANAGER_P_H
diff --git a/daemon/manager.cpp b/daemon/manager.cpp
index 7a02c86..778fdc6 100644
--- a/daemon/manager.cpp
+++ b/daemon/manager.cpp
@@ -1,19 +1,21 @@
-#include "manager.h"
-#include "dbusadaptor.h"
-
#include <QDebug>
#include <QtContacts/QContact>
#include <QtContacts/QContactPhoneNumber>
+#include "manager.h"
+#include "dbusadaptor.h"
+
Manager::Manager(Settings *settings, QObject *parent) :
QObject(parent), settings(settings),
watch(new WatchConnector(this)),
dbus(new DBusConnector(this)),
+ apps(new AppManager(this)),
voice(new VoiceCallManager(settings, this)),
notifications(new NotificationManager(settings, this)),
music(new MusicManager(watch, this)),
datalog(new DataLogManager(watch, this)),
- apps(new AppManager(this)),
+ appmsg(new AppMsgManager(watch, this)),
+ js(new JSKitManager(apps, appmsg, this)),
notification(MNotification::DeviceEvent)
{
connect(settings, SIGNAL(valueChanged(QString)), SLOT(onSettingChanged(const QString&)));
@@ -42,11 +44,6 @@ Manager::Manager(Settings *settings, QObject *parent) :
}
return true;
});
- watch->setEndpointHandler(WatchConnector::watchLAUNCHER,
- [this](const QByteArray &data) {
- logger()->debug() << "LAUNCHER msg:" << data.toHex();
- return true;
- });
connect(voice, SIGNAL(activeVoiceCallChanged()), SLOT(onActiveVoiceCallChanged()));
connect(voice, SIGNAL(error(const QString &)), SLOT(onVoiceError(const QString &)));
diff --git a/daemon/manager.h b/daemon/manager.h
index 8b2fd96..f1dd53e 100644
--- a/daemon/manager.h
+++ b/daemon/manager.h
@@ -7,6 +7,8 @@
#include "notificationmanager.h"
#include "musicmanager.h"
#include "datalogmanager.h"
+#include "appmsgmanager.h"
+#include "jskitmanager.h"
#include "appmanager.h"
#include "settings.h"
@@ -40,11 +42,13 @@ class Manager :
WatchConnector *watch;
DBusConnector *dbus;
+ AppManager *apps;
VoiceCallManager *voice;
NotificationManager *notifications;
MusicManager *music;
DataLogManager *datalog;
- AppManager *apps;
+ AppMsgManager *appmsg;
+ JSKitManager *js;
MNotification notification;
@@ -73,7 +77,7 @@ protected:
void transliterateMessage(const QString &text);
signals:
- void mprisMetadataChanged(QVariantMap);
+ void mprisMetadataChanged(const QVariantMap &metadata);
public slots:
void applyProfile();
diff --git a/daemon/unpacker.cpp b/daemon/unpacker.cpp
new file mode 100644
index 0000000..fc38020
--- /dev/null
+++ b/daemon/unpacker.cpp
@@ -0,0 +1,88 @@
+#include "unpacker.h"
+#include "watchconnector.h"
+
+QByteArray Unpacker::readBytes(int n)
+{
+ if (checkBad(n)) return QByteArray();
+ const char *u = &_buf.constData()[_offset];
+ _offset += n;
+ return QByteArray(u, n);
+}
+
+QString Unpacker::readFixedString(int n)
+{
+ if (checkBad(n)) return QString();
+ const char *u = &_buf.constData()[_offset];
+ _offset += n;
+ return QString::fromUtf8(u, strnlen(u, n));
+}
+
+QUuid Unpacker::readUuid()
+{
+ if (checkBad(16)) return QString();
+ _offset += 16;
+ return QUuid::fromRfc4122(_buf.mid(_offset - 16, 16));
+}
+
+QMap<int, QVariant> Unpacker::readDict()
+{
+ QMap<int, QVariant> d;
+ if (checkBad(1)) return d;
+
+ const int n = read<quint8>();
+
+ for (int i = 0; i < n; i++) {
+ if (checkBad(4 + 1 + 2)) return d;
+ const int key = readLE<qint32>(); // For some reason, this is little endian.
+ const int type = readLE<quint8>();
+ const int width = readLE<quint16>();
+
+ switch (type) {
+ case WatchConnector::typeBYTES:
+ d.insert(key, QVariant::fromValue(readBytes(width)));
+ break;
+ case WatchConnector::typeSTRING:
+ d.insert(key, QVariant::fromValue(readFixedString(width)));
+ break;
+ case WatchConnector::typeUINT:
+ switch (width) {
+ case sizeof(quint8):
+ d.insert(key, QVariant::fromValue(readLE<quint8>()));
+ break;
+ case sizeof(quint16):
+ d.insert(key, QVariant::fromValue(readLE<quint16>()));
+ break;
+ case sizeof(quint32):
+ d.insert(key, QVariant::fromValue(readLE<quint32>()));
+ break;
+ default:
+ _bad = true;
+ return d;
+ }
+
+ break;
+ case WatchConnector::typeINT:
+ switch (width) {
+ case sizeof(qint8):
+ d.insert(key, QVariant::fromValue(readLE<qint8>()));
+ break;
+ case sizeof(qint16):
+ d.insert(key, QVariant::fromValue(readLE<qint16>()));
+ break;
+ case sizeof(qint32):
+ d.insert(key, QVariant::fromValue(readLE<qint32>()));
+ break;
+ default:
+ _bad = true;
+ return d;
+ }
+
+ break;
+ default:
+ _bad = true;
+ return d;
+ }
+ }
+
+ return d;
+}
diff --git a/daemon/unpacker.h b/daemon/unpacker.h
index 94908cb..000c3e8 100644
--- a/daemon/unpacker.h
+++ b/daemon/unpacker.h
@@ -5,19 +5,30 @@
#include <QByteArray>
#include <QString>
#include <QUuid>
+#include <QVariantMap>
+#include <Log4Qt/Logger>
class Unpacker
{
+ LOG4QT_DECLARE_STATIC_LOGGER(logger, Unpacker)
+
public:
Unpacker(const QByteArray &data);
template <typename T>
T read();
+ template <typename T>
+ T readLE();
+
+ QByteArray readBytes(int n);
+
QString readFixedString(int n);
QUuid readUuid();
+ QMap<int, QVariant> readDict();
+
void skip(int n);
bool bad() const;
@@ -45,19 +56,13 @@ inline T Unpacker::read()
return qFromBigEndian<T>(u);
}
-inline QString Unpacker::readFixedString(int n)
-{
- if (checkBad(n)) return QString();
- const char *u = &_buf.constData()[_offset];
- _offset += n;
- return QString::fromUtf8(u, strnlen(u, n));
-}
-
-inline QUuid Unpacker::readUuid()
+template <typename T>
+inline T Unpacker::readLE()
{
- if (checkBad(16)) return QString();
- _offset += 16;
- return QUuid::fromRfc4122(_buf.mid(_offset - 16, 16));
+ if (checkBad(sizeof(T))) return 0;
+ const uchar *u = p();
+ _offset += sizeof(T);
+ return qFromLittleEndian<T>(u);
}
inline void Unpacker::skip(int n)
diff --git a/daemon/watchconnector.h b/daemon/watchconnector.h
index c5ec332..8a7d574 100644
--- a/daemon/watchconnector.h
+++ b/daemon/watchconnector.h
@@ -122,6 +122,10 @@ public:
datalogTIMEOUT = 7
};
enum {
+ launcherSTARTED = 1,
+ launcherSTOPPED = 0
+ };
+ enum {
leadEMAIL = 0,
leadSMS = 1,
leadFACEBOOK = 2,
@@ -153,6 +157,14 @@ public:
DEFAULT_TIMEOUT_MSECS = 100
};
+ typedef QMap<int, QVariant> Dict;
+ enum DictItemType {
+ typeBYTES,
+ typeSTRING,
+ typeUINT,
+ typeINT
+ };
+
typedef std::function<bool(const QByteArray &)> EndpointHandlerFunc;
explicit WatchConnector(QObject *parent = 0);