diff --git a/app/path.cpp b/app/path.cpp index 30de556e..ea48ea16 100644 --- a/app/path.cpp +++ b/app/path.cpp @@ -29,13 +29,31 @@ QByteArray Path::readDataFile(QString fileName) return dataFile.readAll(); } -void Path::writeDataFile(QString fileName, QByteArray data) +void Path::writeCacheFile(QString fileName, QByteArray data) { - QFile dataFile(QDir(s_CacheDir).absoluteFilePath(fileName)); + QDir cacheDir(s_CacheDir); + + // Create the cache path if it does not exist + if (!cacheDir.exists()) { + cacheDir.mkpath("."); + } + + QFile dataFile(cacheDir.absoluteFilePath(fileName)); dataFile.open(QIODevice::WriteOnly); dataFile.write(data); } +void Path::deleteCacheFile(QString fileName) +{ + QFile dataFile(QDir(s_CacheDir).absoluteFilePath(fileName)); + dataFile.remove(); +} + +QFileInfo Path::getCacheFileInfo(QString fileName) +{ + return QFileInfo(QDir(s_CacheDir), fileName); +} + QString Path::getDataFilePath(QString fileName) { QString candidatePath; @@ -79,7 +97,10 @@ void Path::initialize(bool portable) if (portable) { s_LogDir = QDir::currentPath(); s_BoxArtCacheDir = QDir::currentPath() + "/boxart"; - s_CacheDir = QDir::currentPath(); + + // In order for the If-Modified-Since logic to work in MappingFetcher, + // the cache directory must be different than the current directory. + s_CacheDir = QDir::currentPath() + "/cache"; } else { #ifdef Q_OS_DARWIN diff --git a/app/path.h b/app/path.h index b5ae73f2..430c40a9 100644 --- a/app/path.h +++ b/app/path.h @@ -1,6 +1,7 @@ #pragma once #include +#include class Path { @@ -10,7 +11,9 @@ public: static QString getBoxArtCacheDir(); static QByteArray readDataFile(QString fileName); - static void writeDataFile(QString fileName, QByteArray data); + static void writeCacheFile(QString fileName, QByteArray data); + static void deleteCacheFile(QString fileName); + static QFileInfo getCacheFileInfo(QString fileName); // Only safe to use directly for Qt classes static QString getDataFilePath(QString fileName); diff --git a/app/settings/mappingfetcher.cpp b/app/settings/mappingfetcher.cpp index 00cdb4a8..ded9c9eb 100644 --- a/app/settings/mappingfetcher.cpp +++ b/app/settings/mappingfetcher.cpp @@ -27,9 +27,17 @@ void MappingFetcher::start() QT_WARNING_POP #endif - // We'll get a callback when this is finished QUrl url("https://moonlight-stream.org/SDL_GameControllerDB/gamecontrollerdb.txt"); - m_Nam.get(QNetworkRequest(url)); + QNetworkRequest request(url); + + // Only download the file if it's newer than what we have + QFileInfo existingFileInfo = Path::getCacheFileInfo("gamecontrollerdb.txt"); + if (existingFileInfo.exists() && existingFileInfo.size() > 0) { + request.setHeader(QNetworkRequest::IfModifiedSinceHeader, existingFileInfo.lastModified().toUTC()); + } + + // We'll get a callback when this is finished + m_Nam.get(request); } void MappingFetcher::handleMappingListFetched(QNetworkReply* reply) @@ -40,10 +48,21 @@ void MappingFetcher::handleMappingListFetched(QNetworkReply* reply) // Queue the reply for deletion reply->deleteLater(); - // Update the cached data on disk for next call to applyMappings() - Path::writeDataFile("gamecontrollerdb.txt", reply->readAll()); + // If we get a 304 back, Qt will happily just tell us our request was + // successful and let us try to write our empty response to disk. Check + // the status code directly to prevent this. + if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 304) { + qInfo() << "Gamepad mappings are up to date"; + } + else { + // Update the cached data on disk for next call to applyMappings() + QByteArray data = reply->readAll(); + if (!data.isEmpty()) { + Path::writeCacheFile("gamecontrollerdb.txt", data); + } - qInfo() << "Downloaded updated gamepad mappings"; + qInfo() << "Downloaded updated gamepad mappings"; + } } else { qWarning() << "Failed to download updated gamepad mappings:" << reply->error();