diff --git a/libnymea-core/jsonrpc/appdatahandler.cpp b/libnymea-core/jsonrpc/appdatahandler.cpp new file mode 100644 index 00000000..bd274a82 --- /dev/null +++ b/libnymea-core/jsonrpc/appdatahandler.cpp @@ -0,0 +1,82 @@ +#include "appdatahandler.h" +#include "jsonrpc/jsonrpcserver.h" + +#include "nymeasettings.h" + +#include +#include + +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 ¶ms) +{ + 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 ¶ms) +{ + 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); +} diff --git a/libnymea-core/jsonrpc/appdatahandler.h b/libnymea-core/jsonrpc/appdatahandler.h new file mode 100644 index 00000000..5635f953 --- /dev/null +++ b/libnymea-core/jsonrpc/appdatahandler.h @@ -0,0 +1,22 @@ +#ifndef APPDATAHANDLER_H +#define APPDATAHANDLER_H + +#include +#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 ¶ms); + Q_INVOKABLE JsonReply *Load(const QVariantMap ¶ms); + +signals: + +}; + +#endif // APPDATAHANDLER_H diff --git a/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp b/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp index 25213cdc..36a75646 100644 --- a/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp +++ b/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp @@ -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)); diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index ece76d66..845e81f3 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -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 \ diff --git a/libnymea/integrations/plugin.pri b/libnymea/integrations/plugin.pri index dd6a90f5..03c0294d 100644 --- a/libnymea/integrations/plugin.pri +++ b/libnymea/integrations/plugin.pri @@ -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 diff --git a/tests/auto/jsonrpc/testjsonrpc.cpp b/tests/auto/jsonrpc/testjsonrpc.cpp index ab46d928..813b7215 100644 --- a/tests/auto/jsonrpc/testjsonrpc.cpp +++ b/tests/auto/jsonrpc/testjsonrpc.cpp @@ -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());