diff --git a/libnymea-core/debugreportgenerator.cpp b/libnymea-core/debugreportgenerator.cpp index 11dd54b1..e07ef9c4 100644 --- a/libnymea-core/debugreportgenerator.cpp +++ b/libnymea-core/debugreportgenerator.cpp @@ -207,7 +207,6 @@ void DebugReportGenerator::saveConfigs() // Start copy files setting files copyFileToReportDirectory(NymeaSettings(NymeaSettings::SettingsRoleGlobal).fileName(), "config"); copyFileToReportDirectory(NymeaSettings(NymeaSettings::SettingsRoleThings).fileName(), "config"); - copyFileToReportDirectory(NymeaSettings(NymeaSettings::SettingsRoleThingStates).fileName(), "config"); copyFileToReportDirectory(NymeaSettings(NymeaSettings::SettingsRoleRules).fileName(), "config"); copyFileToReportDirectory(NymeaSettings(NymeaSettings::SettingsRolePlugins).fileName(), "config"); copyFileToReportDirectory(NymeaSettings(NymeaSettings::SettingsRoleTags).fileName(), "config"); diff --git a/libnymea-core/debugserverhandler.cpp b/libnymea-core/debugserverhandler.cpp index b9e485cd..1da268d4 100644 --- a/libnymea-core/debugserverhandler.cpp +++ b/libnymea-core/debugserverhandler.cpp @@ -227,34 +227,6 @@ HttpReply *DebugServerHandler::processDebugRequest(const QString &requestPath, c return reply; } - if (requestPath.startsWith("/debug/settings/thingstates")) { - QString settingsFileName = NymeaSettings(NymeaSettings::SettingsRoleThingStates).fileName(); - qCDebug(dcDebugServer()) << "Loading" << settingsFileName; - QFile settingsFile(settingsFileName); - if (!settingsFile.exists()) { - qCWarning(dcDebugServer()) << "Could not read file for debug download" << settingsFileName << "file does not exist."; - HttpReply *reply = HttpReply::createErrorReply(HttpReply::NotFound); - reply->setHeader(HttpReply::ContentTypeHeader, "text/html"); - reply->setPayload(createErrorXmlDocument(HttpReply::NotFound, tr("Could not find file \"%1\".").arg(settingsFileName))); - return reply; - } - - if (!settingsFile.open(QFile::ReadOnly)) { - qCWarning(dcDebugServer()) << "Could not read file for debug download" << settingsFileName; - HttpReply *reply = HttpReply::createErrorReply(HttpReply::Forbidden); - reply->setHeader(HttpReply::ContentTypeHeader, "text/html"); - reply->setPayload(createErrorXmlDocument(HttpReply::NotFound, tr("Could not open file \"%1\".").arg(settingsFileName))); - return reply; - } - - QByteArray settingsFileData = settingsFile.readAll(); - settingsFile.close(); - - HttpReply *reply = HttpReply::createSuccessReply(); - reply->setHeader(HttpReply::ContentTypeHeader, "text/plain"); - reply->setPayload(settingsFileData); - return reply; - } if (requestPath.startsWith("/debug/settings/plugins")) { QString settingsFileName = NymeaSettings(NymeaSettings::SettingsRolePlugins).fileName(); @@ -1391,56 +1363,6 @@ QByteArray DebugServerHandler::createDebugXmlDocument() writer.writeEndElement(); // div download-row - // Download row thing states - writer.writeStartElement("div"); - writer.writeAttribute("class", "download-row"); - - writer.writeStartElement("div"); - writer.writeAttribute("class", "download-name-column"); - //: The thing states settings download description of the debug interface - writer.writeTextElement("p", tr("Thing states settings")); - writer.writeEndElement(); // div download-name-column - - writer.writeStartElement("div"); - writer.writeAttribute("class", "download-path-column"); - writer.writeTextElement("p", NymeaSettings(NymeaSettings::SettingsRoleThingStates).fileName()); - writer.writeEndElement(); // div download-path-column - - writer.writeStartElement("div"); - writer.writeAttribute("class", "download-button-column"); - writer.writeStartElement("form"); - writer.writeAttribute("class", "download-button"); - writer.writeStartElement("button"); - writer.writeAttribute("class", "button"); - writer.writeAttribute("type", "button"); - if (!QFile::exists(NymeaSettings(NymeaSettings::SettingsRoleThingStates).fileName())) { - writer.writeAttribute("disabled", "true"); - } - writer.writeAttribute("onClick", "downloadFile('/debug/settings/thingstates', 'thingstates.conf')"); - writer.writeCharacters(tr("Download")); - writer.writeEndElement(); // button - writer.writeEndElement(); // form - writer.writeEndElement(); // div download-button-column - - writer.writeStartElement("div"); - writer.writeAttribute("class", "show-button-column"); - writer.writeStartElement("form"); - writer.writeAttribute("class", "show-button"); - writer.writeStartElement("button"); - writer.writeAttribute("class", "button"); - writer.writeAttribute("type", "button"); - if (!QFile::exists(NymeaSettings(NymeaSettings::SettingsRoleThingStates).fileName())) { - writer.writeAttribute("disabled", "true"); - } - writer.writeAttribute("onClick", "showFile('/debug/settings/thingstates')"); - writer.writeCharacters(tr("Show")); - writer.writeEndElement(); // button - writer.writeEndElement(); // form - writer.writeEndElement(); // div show-button-column - - writer.writeEndElement(); // div download-row - - // Download row rules writer.writeStartElement("div"); writer.writeAttribute("class", "download-row"); diff --git a/libnymea-core/integrations/thingmanagerimplementation.cpp b/libnymea-core/integrations/thingmanagerimplementation.cpp index 94a9c7fe..f642014e 100644 --- a/libnymea-core/integrations/thingmanagerimplementation.cpp +++ b/libnymea-core/integrations/thingmanagerimplementation.cpp @@ -845,8 +845,7 @@ Thing::ThingError ThingManagerImplementation::removeConfiguredThing(const ThingI settings.remove(""); settings.endGroup(); - NymeaSettings stateCache(NymeaSettings::SettingsRoleThingStates); - stateCache.remove(thingId.toString()); + QFile::remove(statesCacheFile(thingId)); foreach (const IOConnectionId &ioConnectionId, m_ioConnections.keys()) { IOConnection ioConnection = m_ioConnections.value(ioConnectionId); @@ -1792,12 +1791,12 @@ void ThingManagerImplementation::onLoaded() void ThingManagerImplementation::cleanupThingStateCache() { - NymeaSettings settings(NymeaSettings::SettingsRoleThingStates); - foreach (const QString &entry, settings.childGroups()) { - ThingId thingId(entry); + QDir dir(NymeaSettings::cachePath() + "/thingstates/"); + foreach (const QFileInfo &entry, dir.entryList()) { + ThingId thingId(entry.baseName()); if (!m_configuredThings.contains(thingId)) { qCDebug(dcThingManager()) << "Thing ID" << thingId << "not found in configured things. Cleaning up stale thing state cache."; - settings.remove(entry); + QFile::remove(entry.absoluteFilePath()); } } } @@ -1831,7 +1830,9 @@ void ThingManagerImplementation::slotThingStateValueChanged(const StateTypeId &s qCWarning(dcThingManager()) << "Invalid thing id in state change. Not forwarding event. Thing setup not complete yet?"; return; } - storeThingState(thing, stateTypeId); + if (thing->thingClass().getStateType(stateTypeId).cached()) { + storeThingState(thing, stateTypeId); + } emit thingStateChanged(thing, stateTypeId, value, minValue, maxValue); @@ -2100,10 +2101,21 @@ void ThingManagerImplementation::postSetupThing(Thing *thing) plugin->postSetupThing(thing); } +QString ThingManagerImplementation::statesCacheFile(const ThingId &thingId) +{ + return NymeaSettings::cachePath() + "/thingstates/" + thingId.toString().remove(QRegExp("[{}]")) + ".cache"; +} + void ThingManagerImplementation::loadThingStates(Thing *thing) { - NymeaSettings settings(NymeaSettings::SettingsRoleThingStates); - settings.beginGroup(thing->id().toString()); + QSettings *settings = nullptr; + if (QFile::exists(statesCacheFile(thing->id()))) { + settings = new QSettings(statesCacheFile(thing->id()), QSettings::IniFormat); + } else { + // try legacy (<= 0.30 cache) + settings = new QSettings(NymeaSettings::settingsPath() + "/thingstates.conf", QSettings::IniFormat); + settings->beginGroup(thing->id().toString()); + } ThingClass thingClass = m_supportedThings.value(thing->thingClassId()); foreach (const StateType &stateType, thingClass.stateTypes()) { QVariant value = stateType.defaultValue(); @@ -2111,15 +2123,15 @@ void ThingManagerImplementation::loadThingStates(Thing *thing) QVariant maxValue = stateType.maxValue(); if (stateType.cached()) { - if (settings.childGroups().contains(stateType.id().toString())) { - settings.beginGroup(stateType.id().toString()); - value = settings.value("value"); - minValue = settings.value("minValue"); - maxValue = settings.value("maxValue"); - settings.endGroup(); - } else if (settings.contains(stateType.id().toString())) { + if (settings->childGroups().contains(stateType.id().toString())) { + settings->beginGroup(stateType.id().toString()); + value = settings->value("value"); + minValue = settings->value("minValue"); + maxValue = settings->value("maxValue"); + settings->endGroup(); + } else if (settings->contains(stateType.id().toString())) { // Migration from < 0.30 - value = settings.value(stateType.id().toString()); + value = settings->value(stateType.id().toString()); } value.convert(stateType.type()); minValue.convert(stateType.type()); @@ -2130,7 +2142,7 @@ void ThingManagerImplementation::loadThingStates(Thing *thing) thing->setStateMinMaxValues(stateType.id(), minValue, maxValue); thing->setStateValueFilter(stateType.id(), stateType.filter()); } - settings.endGroup(); + delete settings; } void ThingManagerImplementation::storeIOConnections() @@ -2295,19 +2307,20 @@ void ThingManagerImplementation::storeThingStates(Thing *thing) { ThingClass thingClass = m_supportedThings.value(thing->thingClassId()); foreach (const StateType &stateType, thingClass.stateTypes()) { - storeThingState(thing, stateType.id()); + if (stateType.cached()) { + storeThingState(thing, stateType.id()); + } } } void ThingManagerImplementation::storeThingState(Thing *thing, const StateTypeId &stateTypeId) { - NymeaSettings settings(NymeaSettings::SettingsRoleThingStates); - settings.beginGroup(thing->id().toString()); + QSettings settings(statesCacheFile(thing->id()), QSettings::IniFormat); + qCDebug(dcThingManager()) << "Caching state:" << thing->name() << thing->thingClass().stateTypes().findById(stateTypeId).name(); settings.beginGroup(stateTypeId.toString()); settings.setValue("value", thing->stateValue(stateTypeId)); settings.setValue("minValue", thing->state(stateTypeId).minValue()); settings.setValue("maxValue", thing->state(stateTypeId).maxValue()); settings.endGroup(); - settings.endGroup(); } diff --git a/libnymea-core/integrations/thingmanagerimplementation.h b/libnymea-core/integrations/thingmanagerimplementation.h index 6f6fbbb6..41aba703 100644 --- a/libnymea-core/integrations/thingmanagerimplementation.h +++ b/libnymea-core/integrations/thingmanagerimplementation.h @@ -162,6 +162,7 @@ private: void trySetupThing(Thing *thing); void registerThing(Thing *thing); void postSetupThing(Thing *thing); + QString statesCacheFile(const ThingId &thingId); void storeThingStates(Thing *thing); void storeThingState(Thing *thing, const StateTypeId &stateTypeId); void loadThingStates(Thing *thing); diff --git a/libnymea/nymeasettings.cpp b/libnymea/nymeasettings.cpp index e57c3a25..c2c7ad40 100644 --- a/libnymea/nymeasettings.cpp +++ b/libnymea/nymeasettings.cpp @@ -114,9 +114,6 @@ NymeaSettings::NymeaSettings(const SettingsRole &role, QObject *parent): case SettingsRoleGlobal: fileName = "nymead.conf"; break; - case SettingsRoleThingStates: - fileName = "thingstates.conf"; - break; case SettingsRoleTags: fileName = "tags.conf"; break; @@ -207,6 +204,22 @@ QString NymeaSettings::storagePath() return path; } +QString NymeaSettings::cachePath() +{ + QString path; + QString organisationName = QCoreApplication::instance()->organizationName(); + if (!qEnvironmentVariableIsEmpty("SNAP")) { + path = QString(qgetenv("SNAP_DATA")); + } else if (organisationName == "nymea-test") { + path = "/tmp/" + organisationName; + } else if (NymeaSettings::isRoot()) { + path = "/var/cache/" + organisationName; + } else { + path = QDir::homePath() + "/.cache/" + organisationName; + } + return path; +} + /*! Return a list of all settings keys.*/ QStringList NymeaSettings::allKeys() const { diff --git a/libnymea/nymeasettings.h b/libnymea/nymeasettings.h index 8c514b68..0977f8e4 100644 --- a/libnymea/nymeasettings.h +++ b/libnymea/nymeasettings.h @@ -48,7 +48,6 @@ public: SettingsRoleRules, SettingsRolePlugins, SettingsRoleGlobal, - SettingsRoleThingStates, SettingsRoleTags, SettingsRoleMqttPolicies, SettingsRoleIOConnections, @@ -66,6 +65,7 @@ public: static QString settingsPath(); static QString translationsPath(); static QString storagePath(); + static QString cachePath(); // forwarded QSettings methods QStringList allKeys() const; diff --git a/tests/testlib/nymeatestbase.cpp b/tests/testlib/nymeatestbase.cpp index 32ea0847..083b1604 100644 --- a/tests/testlib/nymeatestbase.cpp +++ b/tests/testlib/nymeatestbase.cpp @@ -64,8 +64,8 @@ void NymeaTestBase::initTestCase(const QString &loggingRules) thingSettings.clear(); NymeaSettings pluginSettings(NymeaSettings::SettingsRolePlugins); pluginSettings.clear(); - NymeaSettings statesSettings(NymeaSettings::SettingsRoleThingStates); - statesSettings.clear(); + QDir dir(NymeaSettings::cachePath() + "/thingstates/"); + dir.removeRecursively(); // Reset to default settings NymeaSettings nymeadSettings(NymeaSettings::SettingsRoleGlobal);