diff options
Diffstat (limited to 'launcher/net')
-rw-r--r-- | launcher/net/Download.cpp | 2 | ||||
-rw-r--r-- | launcher/net/Download.h | 2 | ||||
-rw-r--r-- | launcher/net/HttpMetaCache.cpp | 23 | ||||
-rw-r--r-- | launcher/net/HttpMetaCache.h | 17 | ||||
-rw-r--r-- | launcher/net/MetaCacheSink.cpp | 45 | ||||
-rw-r--r-- | launcher/net/MetaCacheSink.h | 3 |
6 files changed, 86 insertions, 6 deletions
diff --git a/launcher/net/Download.cpp b/launcher/net/Download.cpp index 8db11eaa..fd3dbedc 100644 --- a/launcher/net/Download.cpp +++ b/launcher/net/Download.cpp @@ -60,7 +60,7 @@ auto Download::makeCached(QUrl url, MetaEntryPtr entry, Options options) -> Down dl->m_url = url; dl->m_options = options; auto md5Node = new ChecksumValidator(QCryptographicHash::Md5); - auto cachedNode = new MetaCacheSink(entry, md5Node); + auto cachedNode = new MetaCacheSink(entry, md5Node, options.testFlag(Option::MakeEternal)); dl->m_sink.reset(cachedNode); return dl; } diff --git a/launcher/net/Download.h b/launcher/net/Download.h index 1d264381..3faa5db5 100644 --- a/launcher/net/Download.h +++ b/launcher/net/Download.h @@ -49,7 +49,7 @@ class Download : public NetAction { public: using Ptr = shared_qobject_ptr<class Download>; - enum class Option { NoOptions = 0, AcceptLocalFiles = 1 }; + enum class Option { NoOptions = 0, AcceptLocalFiles = 1, MakeEternal = 2 }; Q_DECLARE_FLAGS(Options, Option) protected: diff --git a/launcher/net/HttpMetaCache.cpp b/launcher/net/HttpMetaCache.cpp index 4d86c0b8..9606ddb6 100644 --- a/launcher/net/HttpMetaCache.cpp +++ b/launcher/net/HttpMetaCache.cpp @@ -121,6 +121,14 @@ auto HttpMetaCache::resolveEntry(QString base, QString resource_path, QString ex SaveEventually(); } + // Get rid of old entries, to prevent cache problems + auto current_time = QDateTime::currentSecsSinceEpoch(); + if (entry->isExpired(current_time - ( file_last_changed / 1000 ))) { + qWarning() << "Removing cache entry because of old age!"; + selected_base.entry_list.remove(resource_path); + return staleEntry(base, resource_path); + } + // entry passed all the checks we cared about. entry->basePath = getBasePath(base); return entry; @@ -221,6 +229,13 @@ void HttpMetaCache::Load() foo->etag = Json::ensureString(element_obj, "etag"); foo->local_changed_timestamp = Json::ensureDouble(element_obj, "last_changed_timestamp"); foo->remote_changed_timestamp = Json::ensureString(element_obj, "remote_changed_timestamp"); + + foo->makeEternal(Json::ensureBoolean(element_obj, "eternal", false)); + if (!foo->isEternal()) { + foo->current_age = Json::ensureDouble(element_obj, "current_age"); + foo->max_age = Json::ensureDouble(element_obj, "max_age"); + } + // presumed innocent until closer examination foo->stale = false; @@ -240,6 +255,8 @@ void HttpMetaCache::SaveNow() if (m_index_file.isNull()) return; + qDebug() << "[HttpMetaCache]" << "Saving metacache with" << m_entries.size() << "entries"; + QJsonObject toplevel; Json::writeString(toplevel, "version", "1"); @@ -259,6 +276,12 @@ void HttpMetaCache::SaveNow() entryObj.insert("last_changed_timestamp", QJsonValue(double(entry->local_changed_timestamp))); if (!entry->remote_changed_timestamp.isEmpty()) entryObj.insert("remote_changed_timestamp", QJsonValue(entry->remote_changed_timestamp)); + if (entry->isEternal()) { + entryObj.insert("eternal", true); + } else { + entryObj.insert("current_age", QJsonValue(double(entry->current_age))); + entryObj.insert("max_age", QJsonValue(double(entry->max_age))); + } entriesArr.append(entryObj); } } diff --git a/launcher/net/HttpMetaCache.h b/launcher/net/HttpMetaCache.h index e944b3d5..c0b12318 100644 --- a/launcher/net/HttpMetaCache.h +++ b/launcher/net/HttpMetaCache.h @@ -64,14 +64,31 @@ class MetaEntry { auto getMD5Sum() -> QString { return md5sum; } void setMD5Sum(QString md5sum) { this->md5sum = md5sum; } + /* Whether the entry expires after some time (false) or not (true). */ + void makeEternal(bool eternal) { is_eternal = eternal; } + [[nodiscard]] bool isEternal() const { return is_eternal; } + + auto getCurrentAge() -> qint64 { return current_age; } + void setCurrentAge(qint64 age) { current_age = age; } + + auto getMaximumAge() -> qint64 { return max_age; } + void setMaximumAge(qint64 age) { max_age = age; } + + bool isExpired(qint64 offset) { return !is_eternal && (current_age >= max_age - offset); }; + protected: QString baseId; QString basePath; QString relativePath; QString md5sum; QString etag; + qint64 local_changed_timestamp = 0; QString remote_changed_timestamp; // QString for now, RFC 2822 encoded time + qint64 current_age = 0; + qint64 max_age = 0; + bool is_eternal = false; + bool stale = true; }; diff --git a/launcher/net/MetaCacheSink.cpp b/launcher/net/MetaCacheSink.cpp index f86dd870..5ae53c1c 100644 --- a/launcher/net/MetaCacheSink.cpp +++ b/launcher/net/MetaCacheSink.cpp @@ -36,13 +36,18 @@ #include "MetaCacheSink.h" #include <QFile> #include <QFileInfo> -#include "FileSystem.h" #include "Application.h" namespace Net { -MetaCacheSink::MetaCacheSink(MetaEntryPtr entry, ChecksumValidator * md5sum) - :Net::FileSink(entry->getFullPath()), m_entry(entry), m_md5Node(md5sum) +/** Maximum time to hold a cache entry + * = 1 week in seconds + */ +#define MAX_TIME_TO_EXPIRE 1*7*24*60*60 + + +MetaCacheSink::MetaCacheSink(MetaEntryPtr entry, ChecksumValidator * md5sum, bool is_eternal) + :Net::FileSink(entry->getFullPath()), m_entry(entry), m_md5Node(md5sum), m_is_eternal(is_eternal) { addValidator(md5sum); } @@ -88,6 +93,40 @@ Task::State MetaCacheSink::finalizeCache(QNetworkReply & reply) } m_entry->setLocalChangedTimestamp(output_file_info.lastModified().toUTC().toMSecsSinceEpoch()); + + { // Cache lifetime + if (m_is_eternal) { + qDebug() << "[MetaCache] Adding eternal cache entry:" << m_entry->getFullPath(); + m_entry->makeEternal(true); + } else if (reply.hasRawHeader("Cache-Control")) { + auto cache_control_header = reply.rawHeader("Cache-Control"); + // qDebug() << "[MetaCache] Parsing 'Cache-Control' header with" << cache_control_header; + + QRegularExpression max_age_expr("max-age=([0-9]+)"); + qint64 max_age = max_age_expr.match(cache_control_header).captured(1).toLongLong(); + m_entry->setMaximumAge(max_age); + + } else if (reply.hasRawHeader("Expires")) { + auto expires_header = reply.rawHeader("Expires"); + // qDebug() << "[MetaCache] Parsing 'Expires' header with" << expires_header; + + qint64 max_age = QDateTime::fromString(expires_header).toSecsSinceEpoch() - QDateTime::currentSecsSinceEpoch(); + m_entry->setMaximumAge(max_age); + } else { + m_entry->setMaximumAge(MAX_TIME_TO_EXPIRE); + } + + if (reply.hasRawHeader("Age")) { + auto age_header = reply.rawHeader("Age"); + // qDebug() << "[MetaCache] Parsing 'Age' header with" << age_header; + + qint64 current_age = age_header.toLongLong(); + m_entry->setCurrentAge(current_age); + } else { + m_entry->setCurrentAge(0); + } + } + m_entry->setStale(false); APPLICATION->metacache()->updateEntry(m_entry); diff --git a/launcher/net/MetaCacheSink.h b/launcher/net/MetaCacheSink.h index c9f7edfe..f5948085 100644 --- a/launcher/net/MetaCacheSink.h +++ b/launcher/net/MetaCacheSink.h @@ -42,7 +42,7 @@ namespace Net { class MetaCacheSink : public FileSink { public: - MetaCacheSink(MetaEntryPtr entry, ChecksumValidator* md5sum); + MetaCacheSink(MetaEntryPtr entry, ChecksumValidator* md5sum, bool is_eternal = false); virtual ~MetaCacheSink() = default; auto hasLocalData() -> bool override; @@ -54,5 +54,6 @@ class MetaCacheSink : public FileSink { private: MetaEntryPtr m_entry; ChecksumValidator* m_md5Node; + bool m_is_eternal; }; } // namespace Net |