Add support for storing application data on the core

This commit is contained in:
Michael Zanetti 2021-04-06 22:56:26 +02:00
parent 96ae3cd01a
commit 60de0a3eed
6 changed files with 111 additions and 1 deletions

View File

@ -0,0 +1,82 @@
#include "appdatahandler.h"
#include "jsonrpc/jsonrpcserver.h"
#include "nymeasettings.h"
#include <QSettings>
#include <QDir>
AppDataHandler::AppDataHandler(QObject *parent) : JsonHandler(parent)
{
// Methods
QString description; QVariantMap params; QVariantMap returns;
description = "Store an app data entry to the server. App data can be used by the client application "
"to store configuration values. The app data storage is a key-value pair storage. Each "
"entry value is identified by an appId, a key and optionally a group. The value data is "
"a bytearray and can contain arbitrary data, such as a JSON map or image data, however, "
"be aware of the maximum packet size for the used transport.\n"
"This might be useful to a client application to sync settings across multiple instances of "
"the same application.\n"
"The group parameter might be used to create groups for this application.\n"
"IMPORTANT: Currently no verification of the appId is done. The appid is merely a mechanism "
"to prevent different different client apps from colliding by using the same key for data "
"entries. This implies that the app data storage may not be suited for sensitive data given "
"that anyone with a valid server token can read it.\n ";
params.insert("appId", enumValueName(String));
params.insert("o:group", enumValueName(String));
params.insert("key", enumValueName(String));
params.insert("value", enumValueName(String));
registerMethod("Store", description, params, returns);
description.clear(); params.clear(); returns.clear();
description = "Retrieve an app data storage value that has previously been set with Store(). If no value "
"had been set for this appId/key combination before, an empty value will be returned.";
params.insert("appId", enumValueName(String));
params.insert("o:group", enumValueName(String));
params.insert("key", enumValueName(String));
returns.insert("value", enumValueName(String));
registerMethod("Load", description, params, returns);
// Notifications
description.clear(); params.clear();
description = "Emitted whenever the app data is changed on the server.";
params.insert("appId", enumValueName(String));
params.insert("o:group", enumValueName(String));
params.insert("key", enumValueName(String));
params.insert("value", enumValueName(String));
registerNotification("Changed", description, params);
}
QString AppDataHandler::name() const
{
return "AppData";
}
JsonReply* AppDataHandler::Store(const QVariantMap &params)
{
QString appId = params.value("appId").toString();
QString group = params.value("group").toString();
QString key = params.value("key").toString();
QVariant value = params.value("value");
// Note: we're using a different file for each group as QSettings tends to get slow with loads of keys.
// Might be replaced with a DB at some point if needed. However, current estimate is this won't be
// used for excessive amounts of data as it is mostly meant as a config file syncing mechanism.
QSettings settings(NymeaSettings::storagePath() + "/appdata/" + appId + '/' + group + ".conf", QSettings::IniFormat);
settings.setValue(key, value);
return createReply(QVariantMap());
}
JsonReply* AppDataHandler::Load(const QVariantMap &params)
{
QString appId = params.value("appId").toString();
QString group = params.value("group").toString();
QString key = params.value("key").toString();
QSettings settings(NymeaSettings::storagePath() + "/appdata/" + appId + '/' + group + ".conf", QSettings::IniFormat);
QVariantMap returns;
returns.insert("value", settings.value(key).toString());
return createReply(returns);
}

View File

@ -0,0 +1,22 @@
#ifndef APPDATAHANDLER_H
#define APPDATAHANDLER_H
#include <QObject>
#include "jsonrpc/jsonhandler.h"
class AppDataHandler : public JsonHandler
{
Q_OBJECT
public:
explicit AppDataHandler(QObject *parent = nullptr);
QString name() const override;
Q_INVOKABLE JsonReply *Store(const QVariantMap &params);
Q_INVOKABLE JsonReply *Load(const QVariantMap &params);
signals:
};
#endif // APPDATAHANDLER_H

View File

@ -71,6 +71,7 @@
#include "configurationhandler.h"
#include "networkmanagerhandler.h"
#include "tagshandler.h"
#include "appdatahandler.h"
#include "systemhandler.h"
#include "usershandler.h"
#include "zigbeehandler.h"
@ -594,6 +595,7 @@ void JsonRPCServerImplementation::setup()
registerHandler(new ConfigurationHandler(this));
registerHandler(new NetworkManagerHandler(NymeaCore::instance()->networkManager(), this));
registerHandler(new TagsHandler(this));
registerHandler(new AppDataHandler(this));
registerHandler(new SystemHandler(NymeaCore::instance()->platform(), this));
registerHandler(new UsersHandler(NymeaCore::instance()->userManager(), this));
registerHandler(new ZigbeeHandler(NymeaCore::instance()->zigbeeManager(), this));

View File

@ -86,6 +86,7 @@ HEADERS += nymeacore.h \
jsonrpc/configurationhandler.h \
jsonrpc/networkmanagerhandler.h \
jsonrpc/tagshandler.h \
jsonrpc/appdatahandler.h \
jsonrpc/systemhandler.h \
jsonrpc/scriptshandler.h \
jsonrpc/usershandler.h \
@ -173,6 +174,7 @@ SOURCES += nymeacore.cpp \
jsonrpc/configurationhandler.cpp \
jsonrpc/networkmanagerhandler.cpp \
jsonrpc/tagshandler.cpp \
jsonrpc/appdatahandler.cpp \
jsonrpc/systemhandler.cpp \
jsonrpc/scriptshandler.cpp \
jsonrpc/usershandler.cpp \

View File

@ -83,6 +83,8 @@ translations.files = $$[QT_SOURCE_TREE]/translations/*.qm
# Redefine target to make output file suite the plugin filename schema
TARGET = $$qtLibraryTarget(nymea_integrationplugin"$$TARGET")
target.depends += $${JSONFILE}
# Install plugin
target.path = $$[QT_INSTALL_LIBS]/nymea/plugins/
INSTALLS += target translations

View File

@ -674,7 +674,7 @@ void TestJSONRPC::enableDisableNotifications_legacy()
QStringList expectedNamespaces;
if (enabled == "true") {
expectedNamespaces << "Actions" << "NetworkManager" << "Devices" << "Integrations" << "System" << "Rules" << "States" << "Logging" << "Tags" << "JSONRPC" << "Configuration" << "Events" << "Scripts" << "Users" << "Zigbee";
expectedNamespaces << "Actions" << "NetworkManager" << "Devices" << "Integrations" << "System" << "Rules" << "States" << "Logging" << "Tags" << "AppData" << "JSONRPC" << "Configuration" << "Events" << "Scripts" << "Users" << "Zigbee";
}
std::sort(expectedNamespaces.begin(), expectedNamespaces.end());