diff options
| author | Javier <dev.git@javispedro.com> | 2014-11-30 17:27:08 +0100 |
|---|---|---|
| committer | Javier <dev.git@javispedro.com> | 2014-11-30 17:37:19 +0100 |
| commit | 49f1261bf9d635d5e3d881e87a93ed4e76abfe90 (patch) | |
| tree | 4432ecd771a3aca533914d02f9947cb497493395 /daemon/appmanager.cpp | |
| parent | d55d1d472d5876f90dd95301d9f3b6bef6f4c494 (diff) | |
allow receiving responses to commands in watchconnector
* the skeleton is in place for watchconnector to allow query->response
messages. I've used call/cc style because it is impossible to make
QBluetoothSocket synchronous (waitForReadyRead() is a no-op)
* remove watchcommands, instead create musicmanager to listen for the
music endpoint. The other (simpler) endpoints are now listened in
watchconnector itself. hangupAll() slot is moved to voicecallmanager.
* instead of emitting signals for each received message, listeners
can now register for receiving messages targeted towards a given
endpoint
* when reading from bluetoothsocket, properly handle short reads
* remove useless 'watch' namespace
* create appmanager, which mantains a database of installed apps
(installed on the phone, that is; watch installed apps will come
later)
* all the *Managers are now instantiated by the main Manager itself
* introduce Unpacker helper class for decoding watch messages
* implement getAppbankStatus and getAppbankUuids messages and response
parsers
* remove file logging for now (20MB is bad for eMMC!)
* use dbus object path /org/pebbled instead of /
Diffstat (limited to 'daemon/appmanager.cpp')
| -rw-r--r-- | daemon/appmanager.cpp | 109 |
1 files changed, 103 insertions, 6 deletions
diff --git a/daemon/appmanager.cpp b/daemon/appmanager.cpp index b4a3d68..34af3af 100644 --- a/daemon/appmanager.cpp +++ b/daemon/appmanager.cpp @@ -1,15 +1,112 @@ #include <QStandardPaths> -#include <QUuid> +#include <QJsonDocument> +#include <QJsonObject> +#include <QDir> #include "appmanager.h" AppManager::AppManager(QObject *parent) - : QObject(parent) + : QObject(parent), + _watcher(new QFileSystemWatcher(this)) { + connect(_watcher, &QFileSystemWatcher::directoryChanged, + this, &AppManager::rescan); + + QDir dataDir(QStandardPaths::writableLocation(QStandardPaths::DataLocation)); + if (!dataDir.exists("apps")) { + if (!dataDir.mkdir("apps")) { + logger()->warn() << "could not create dir" << dataDir.absoluteFilePath("apps"); + } + } + logger()->debug() << "install apps in" << dataDir.absoluteFilePath("apps"); + + rescan(); +} + +QStringList AppManager::appPaths() const +{ + return QStandardPaths::locateAll(QStandardPaths::DataLocation, + QLatin1String("apps"), + QStandardPaths::LocateDirectory); +} + +void AppManager::rescan() +{ + QStringList watchedDirs = _watcher->directories(); + if (!watchedDirs.isEmpty()) _watcher->removePaths(watchedDirs); + QStringList watchedFiles = _watcher->files(); + if (!watchedFiles.isEmpty()) _watcher->removePaths(watchedFiles); + _apps.clear(); + _names.clear(); + + Q_FOREACH(const QString &path, appPaths()) { + QDir dir(path); + _watcher->addPath(dir.absolutePath()); + logger()->debug() << "scanning dir" << dir.absolutePath(); + QStringList entries = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Readable | QDir::Executable); + logger()->debug() << "scanning dir results" << entries; + Q_FOREACH(const QString &path, entries) { + QString appPath = dir.absoluteFilePath(path); + _watcher->addPath(appPath); + if (dir.exists(path + "/appinfo.json")) { + _watcher->addPath(appPath + "/appinfo.json"); + scanApp(appPath); + } + } + } + + logger()->debug() << "now watching" << _watcher->directories() << _watcher->files(); } -QString AppManager::getAppDir(const QUuid& uuid) const +void AppManager::scanApp(const QString &path) { - return QStandardPaths::locate(QStandardPaths::DataLocation, - QString("apps/%1").arg(uuid.toString()), - QStandardPaths::LocateDirectory); + logger()->debug() << "scanning app" << path; + QDir appDir(path); + if (!appDir.isReadable()) { + logger()->warn() << "app" << appDir.absolutePath() << "is not readable"; + return; + } + + QFile appInfoFile(path + "/appinfo.json"); + if (!appInfoFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + logger()->warn() << "cannot open app info file" << appInfoFile.fileName() << ":" + << appInfoFile.errorString(); + return; + } + + QJsonParseError parseError; + QJsonDocument doc = QJsonDocument::fromJson(appInfoFile.readAll(), &parseError); + if (parseError.error != QJsonParseError::NoError) { + logger()->warn() << "cannot parse app info file" << appInfoFile.fileName() << ":" + << parseError.errorString(); + return; + } + + const QJsonObject root = doc.object(); + AppInfo info; + info.uuid = QUuid(root["uuid"].toString()); + info.shortName = root["shortName"].toString(); + info.longName = root["longName"].toString(); + info.company = root["companyName"].toString(); + info.versionCode = root["versionCode"].toInt(); + info.versionLabel = root["versionLabel"].toString(); + + const QJsonObject watchapp = root["watchapp"].toObject(); + info.isWatchface = watchapp["watchface"].toBool(); + info.isJSKit = appDir.exists("pebble-js-app.js"); + + const QJsonObject appkeys = root["appKeys"].toObject(); + for (QJsonObject::const_iterator it = appkeys.constBegin(); it != appkeys.constEnd(); ++it) { + info.appKeys.insert(it.key(), it.value().toInt()); + } + + if (info.uuid.isNull() || info.shortName.isEmpty()) { + logger()->warn() << "invalid or empty uuid/name in" << appInfoFile.fileName(); + return; + } + + _apps.insert(info.uuid, info); + _names.insert(info.shortName, info.uuid); + + const char *type = info.isWatchface ? "watchface" : "app"; + logger()->debug() << "found installed" << type << info.shortName << info.versionLabel << "with uuid" << info.uuid.toString(); } |
