#include "LocalStateHelper.h" #include #include #include #include LocalStateHelper::LocalStateHelper(const QString& baseDir) : m_baseDir(baseDir) , m_filePath(baseDir + "/config/local_state.json") { } bool LocalStateHelper::loadState(const QString& relativePath) { m_filePath = m_baseDir + "/" + relativePath; QFile file(m_filePath); if (!file.exists()) { QDir dir(QFileInfo(m_filePath).path()); if (!dir.exists() && !dir.mkpath(".")) { m_error = QString("Cannot create state directory: %1").arg(dir.path()); return false; } m_state = QJsonObject{ {"max_policy_seq", 0}, {"last_success_run_at", QString()}, {"last_online_verified_at", QString()}, {"last_success_version", QString()} }; m_loaded = true; if (!saveState()) { m_error = QString("Cannot write new state file: %1").arg(m_filePath); return false; } return true; } if (!file.open(QIODevice::ReadOnly)) { m_error = QString("Cannot open state file: %1").arg(m_filePath); return false; } QByteArray raw = file.readAll(); file.close(); QJsonParseError parseError; QJsonDocument doc = QJsonDocument::fromJson(raw, &parseError); if (parseError.error != QJsonParseError::NoError || !doc.isObject()) { m_error = QString("Invalid state JSON: %1").arg(parseError.errorString()); return false; } m_state = doc.object(); m_loaded = true; return true; } bool LocalStateHelper::saveState() const { if (!m_loaded) return false; QFile file(m_filePath); if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { return false; } QJsonDocument doc(m_state); file.write(doc.toJson(QJsonDocument::Indented)); file.close(); return true; } bool LocalStateHelper::isLoaded() const { return m_loaded; } QString LocalStateHelper::errorString() const { return m_error; } qint64 LocalStateHelper::maxPolicySeq() const { return m_state.value("max_policy_seq").toVariant().toLongLong(); } QDateTime LocalStateHelper::lastSuccessRunAt() const { return QDateTime::fromString(m_state.value("last_success_run_at").toString(), Qt::ISODate); } QDateTime LocalStateHelper::lastOnlineVerifiedAt() const { return QDateTime::fromString(m_state.value("last_online_verified_at").toString(), Qt::ISODate); } QString LocalStateHelper::lastSuccessVersion() const { return m_state.value("last_success_version").toString(); } bool LocalStateHelper::isPolicySeqRolledBack(qint64 policySeq) const { if (!m_loaded) return false; return policySeq < maxPolicySeq(); } bool LocalStateHelper::isSystemTimeRewound() const { if (!m_loaded) return false; const QDateTime now = QDateTime::currentDateTimeUtc(); const QDateTime lastRun = lastSuccessRunAt(); const QDateTime lastOnline = lastOnlineVerifiedAt(); return (lastRun.isValid() && now < lastRun) || (lastOnline.isValid() && now < lastOnline); } void LocalStateHelper::updateAfterSuccessfulRun(const QString& currentVersion, qint64 policySeq) { if (!m_loaded) m_loaded = true; m_state["last_success_run_at"] = QDateTime::currentDateTimeUtc().toString(Qt::ISODate); m_state["last_success_version"] = currentVersion; if (policySeq > maxPolicySeq()) m_state["max_policy_seq"] = policySeq; } void LocalStateHelper::updateOnlineVerified(qint64 policySeq) { if (!m_loaded) m_loaded = true; m_state["last_online_verified_at"] = QDateTime::currentDateTimeUtc().toString(Qt::ISODate); if (policySeq > maxPolicySeq()) m_state["max_policy_seq"] = policySeq; }