Merge PR #494: Split thing cache into individual files

This commit is contained in:
Jenkins nymea 2022-03-27 19:49:30 +02:00
commit 443dbfb42b
7 changed files with 55 additions and 107 deletions

View File

@ -207,7 +207,6 @@ void DebugReportGenerator::saveConfigs()
// Start copy files setting files // Start copy files setting files
copyFileToReportDirectory(NymeaSettings(NymeaSettings::SettingsRoleGlobal).fileName(), "config"); copyFileToReportDirectory(NymeaSettings(NymeaSettings::SettingsRoleGlobal).fileName(), "config");
copyFileToReportDirectory(NymeaSettings(NymeaSettings::SettingsRoleThings).fileName(), "config"); copyFileToReportDirectory(NymeaSettings(NymeaSettings::SettingsRoleThings).fileName(), "config");
copyFileToReportDirectory(NymeaSettings(NymeaSettings::SettingsRoleThingStates).fileName(), "config");
copyFileToReportDirectory(NymeaSettings(NymeaSettings::SettingsRoleRules).fileName(), "config"); copyFileToReportDirectory(NymeaSettings(NymeaSettings::SettingsRoleRules).fileName(), "config");
copyFileToReportDirectory(NymeaSettings(NymeaSettings::SettingsRolePlugins).fileName(), "config"); copyFileToReportDirectory(NymeaSettings(NymeaSettings::SettingsRolePlugins).fileName(), "config");
copyFileToReportDirectory(NymeaSettings(NymeaSettings::SettingsRoleTags).fileName(), "config"); copyFileToReportDirectory(NymeaSettings(NymeaSettings::SettingsRoleTags).fileName(), "config");

View File

@ -227,34 +227,6 @@ HttpReply *DebugServerHandler::processDebugRequest(const QString &requestPath, c
return reply; 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")) { if (requestPath.startsWith("/debug/settings/plugins")) {
QString settingsFileName = NymeaSettings(NymeaSettings::SettingsRolePlugins).fileName(); QString settingsFileName = NymeaSettings(NymeaSettings::SettingsRolePlugins).fileName();
@ -1391,56 +1363,6 @@ QByteArray DebugServerHandler::createDebugXmlDocument()
writer.writeEndElement(); // div download-row 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 // Download row rules
writer.writeStartElement("div"); writer.writeStartElement("div");
writer.writeAttribute("class", "download-row"); writer.writeAttribute("class", "download-row");

View File

@ -845,8 +845,7 @@ Thing::ThingError ThingManagerImplementation::removeConfiguredThing(const ThingI
settings.remove(""); settings.remove("");
settings.endGroup(); settings.endGroup();
NymeaSettings stateCache(NymeaSettings::SettingsRoleThingStates); QFile::remove(statesCacheFile(thingId));
stateCache.remove(thingId.toString());
foreach (const IOConnectionId &ioConnectionId, m_ioConnections.keys()) { foreach (const IOConnectionId &ioConnectionId, m_ioConnections.keys()) {
IOConnection ioConnection = m_ioConnections.value(ioConnectionId); IOConnection ioConnection = m_ioConnections.value(ioConnectionId);
@ -1792,12 +1791,12 @@ void ThingManagerImplementation::onLoaded()
void ThingManagerImplementation::cleanupThingStateCache() void ThingManagerImplementation::cleanupThingStateCache()
{ {
NymeaSettings settings(NymeaSettings::SettingsRoleThingStates); QDir dir(NymeaSettings::cachePath() + "/thingstates/");
foreach (const QString &entry, settings.childGroups()) { foreach (const QFileInfo &entry, dir.entryList()) {
ThingId thingId(entry); ThingId thingId(entry.baseName());
if (!m_configuredThings.contains(thingId)) { if (!m_configuredThings.contains(thingId)) {
qCDebug(dcThingManager()) << "Thing ID" << thingId << "not found in configured things. Cleaning up stale thing state cache."; 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?"; qCWarning(dcThingManager()) << "Invalid thing id in state change. Not forwarding event. Thing setup not complete yet?";
return; return;
} }
storeThingState(thing, stateTypeId); if (thing->thingClass().getStateType(stateTypeId).cached()) {
storeThingState(thing, stateTypeId);
}
emit thingStateChanged(thing, stateTypeId, value, minValue, maxValue); emit thingStateChanged(thing, stateTypeId, value, minValue, maxValue);
@ -2100,10 +2101,21 @@ void ThingManagerImplementation::postSetupThing(Thing *thing)
plugin->postSetupThing(thing); plugin->postSetupThing(thing);
} }
QString ThingManagerImplementation::statesCacheFile(const ThingId &thingId)
{
return NymeaSettings::cachePath() + "/thingstates/" + thingId.toString().remove(QRegExp("[{}]")) + ".cache";
}
void ThingManagerImplementation::loadThingStates(Thing *thing) void ThingManagerImplementation::loadThingStates(Thing *thing)
{ {
NymeaSettings settings(NymeaSettings::SettingsRoleThingStates); QSettings *settings = nullptr;
settings.beginGroup(thing->id().toString()); 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()); ThingClass thingClass = m_supportedThings.value(thing->thingClassId());
foreach (const StateType &stateType, thingClass.stateTypes()) { foreach (const StateType &stateType, thingClass.stateTypes()) {
QVariant value = stateType.defaultValue(); QVariant value = stateType.defaultValue();
@ -2111,15 +2123,15 @@ void ThingManagerImplementation::loadThingStates(Thing *thing)
QVariant maxValue = stateType.maxValue(); QVariant maxValue = stateType.maxValue();
if (stateType.cached()) { if (stateType.cached()) {
if (settings.childGroups().contains(stateType.id().toString())) { if (settings->childGroups().contains(stateType.id().toString())) {
settings.beginGroup(stateType.id().toString()); settings->beginGroup(stateType.id().toString());
value = settings.value("value"); value = settings->value("value");
minValue = settings.value("minValue"); minValue = settings->value("minValue");
maxValue = settings.value("maxValue"); maxValue = settings->value("maxValue");
settings.endGroup(); settings->endGroup();
} else if (settings.contains(stateType.id().toString())) { } else if (settings->contains(stateType.id().toString())) {
// Migration from < 0.30 // Migration from < 0.30
value = settings.value(stateType.id().toString()); value = settings->value(stateType.id().toString());
} }
value.convert(stateType.type()); value.convert(stateType.type());
minValue.convert(stateType.type()); minValue.convert(stateType.type());
@ -2130,7 +2142,7 @@ void ThingManagerImplementation::loadThingStates(Thing *thing)
thing->setStateMinMaxValues(stateType.id(), minValue, maxValue); thing->setStateMinMaxValues(stateType.id(), minValue, maxValue);
thing->setStateValueFilter(stateType.id(), stateType.filter()); thing->setStateValueFilter(stateType.id(), stateType.filter());
} }
settings.endGroup(); delete settings;
} }
void ThingManagerImplementation::storeIOConnections() void ThingManagerImplementation::storeIOConnections()
@ -2295,19 +2307,20 @@ void ThingManagerImplementation::storeThingStates(Thing *thing)
{ {
ThingClass thingClass = m_supportedThings.value(thing->thingClassId()); ThingClass thingClass = m_supportedThings.value(thing->thingClassId());
foreach (const StateType &stateType, thingClass.stateTypes()) { 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) void ThingManagerImplementation::storeThingState(Thing *thing, const StateTypeId &stateTypeId)
{ {
NymeaSettings settings(NymeaSettings::SettingsRoleThingStates); QSettings settings(statesCacheFile(thing->id()), QSettings::IniFormat);
settings.beginGroup(thing->id().toString()); qCDebug(dcThingManager()) << "Caching state:" << thing->name() << thing->thingClass().stateTypes().findById(stateTypeId).name();
settings.beginGroup(stateTypeId.toString()); settings.beginGroup(stateTypeId.toString());
settings.setValue("value", thing->stateValue(stateTypeId)); settings.setValue("value", thing->stateValue(stateTypeId));
settings.setValue("minValue", thing->state(stateTypeId).minValue()); settings.setValue("minValue", thing->state(stateTypeId).minValue());
settings.setValue("maxValue", thing->state(stateTypeId).maxValue()); settings.setValue("maxValue", thing->state(stateTypeId).maxValue());
settings.endGroup(); settings.endGroup();
settings.endGroup();
} }

View File

@ -162,6 +162,7 @@ private:
void trySetupThing(Thing *thing); void trySetupThing(Thing *thing);
void registerThing(Thing *thing); void registerThing(Thing *thing);
void postSetupThing(Thing *thing); void postSetupThing(Thing *thing);
QString statesCacheFile(const ThingId &thingId);
void storeThingStates(Thing *thing); void storeThingStates(Thing *thing);
void storeThingState(Thing *thing, const StateTypeId &stateTypeId); void storeThingState(Thing *thing, const StateTypeId &stateTypeId);
void loadThingStates(Thing *thing); void loadThingStates(Thing *thing);

View File

@ -114,9 +114,6 @@ NymeaSettings::NymeaSettings(const SettingsRole &role, QObject *parent):
case SettingsRoleGlobal: case SettingsRoleGlobal:
fileName = "nymead.conf"; fileName = "nymead.conf";
break; break;
case SettingsRoleThingStates:
fileName = "thingstates.conf";
break;
case SettingsRoleTags: case SettingsRoleTags:
fileName = "tags.conf"; fileName = "tags.conf";
break; break;
@ -207,6 +204,22 @@ QString NymeaSettings::storagePath()
return path; 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.*/ /*! Return a list of all settings keys.*/
QStringList NymeaSettings::allKeys() const QStringList NymeaSettings::allKeys() const
{ {

View File

@ -48,7 +48,6 @@ public:
SettingsRoleRules, SettingsRoleRules,
SettingsRolePlugins, SettingsRolePlugins,
SettingsRoleGlobal, SettingsRoleGlobal,
SettingsRoleThingStates,
SettingsRoleTags, SettingsRoleTags,
SettingsRoleMqttPolicies, SettingsRoleMqttPolicies,
SettingsRoleIOConnections, SettingsRoleIOConnections,
@ -66,6 +65,7 @@ public:
static QString settingsPath(); static QString settingsPath();
static QString translationsPath(); static QString translationsPath();
static QString storagePath(); static QString storagePath();
static QString cachePath();
// forwarded QSettings methods // forwarded QSettings methods
QStringList allKeys() const; QStringList allKeys() const;

View File

@ -64,8 +64,8 @@ void NymeaTestBase::initTestCase(const QString &loggingRules)
thingSettings.clear(); thingSettings.clear();
NymeaSettings pluginSettings(NymeaSettings::SettingsRolePlugins); NymeaSettings pluginSettings(NymeaSettings::SettingsRolePlugins);
pluginSettings.clear(); pluginSettings.clear();
NymeaSettings statesSettings(NymeaSettings::SettingsRoleThingStates); QDir dir(NymeaSettings::cachePath() + "/thingstates/");
statesSettings.clear(); dir.removeRecursively();
// Reset to default settings // Reset to default settings
NymeaSettings nymeadSettings(NymeaSettings::SettingsRoleGlobal); NymeaSettings nymeadSettings(NymeaSettings::SettingsRoleGlobal);