Split thing state cache into individual files

pull/494/head
Michael Zanetti 2022-02-05 22:53:08 +01:00
parent 28d2f53261
commit 7bfb48feac
7 changed files with 55 additions and 107 deletions

View File

@ -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");

View File

@ -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");

View File

@ -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();
}

View File

@ -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);

View File

@ -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
{

View File

@ -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;

View File

@ -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);