mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-07-14 22:42:14 -07:00
Queue requests instead.
This commit is contained in:
parent
ad4be745c3
commit
a9716d6948
3 changed files with 32 additions and 77 deletions
|
|
@ -33,13 +33,13 @@ PictureLoaderWorker::PictureLoaderWorker()
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||||
networkManager->setTransferTimeout();
|
networkManager->setTransferTimeout();
|
||||||
#endif
|
#endif
|
||||||
auto cache = new QNetworkDiskCache(this);
|
cache = new QNetworkDiskCache(this);
|
||||||
cache->setCacheDirectory(SettingsCache::instance().getNetworkCachePath());
|
cache->setCacheDirectory(SettingsCache::instance().getNetworkCachePath());
|
||||||
cache->setMaximumCacheSize(1024L * 1024L *
|
cache->setMaximumCacheSize(1024L * 1024L *
|
||||||
static_cast<qint64>(SettingsCache::instance().getNetworkCacheSizeInMB()));
|
static_cast<qint64>(SettingsCache::instance().getNetworkCacheSizeInMB()));
|
||||||
// Note: the settings is in MB, but QNetworkDiskCache uses bytes
|
// Note: the settings is in MB, but QNetworkDiskCache uses bytes
|
||||||
connect(&SettingsCache::instance(), &SettingsCache::networkCacheSizeChanged, cache,
|
connect(&SettingsCache::instance(), &SettingsCache::networkCacheSizeChanged, this,
|
||||||
[cache](int newSizeInMB) { cache->setMaximumCacheSize(1024L * 1024L * static_cast<qint64>(newSizeInMB)); });
|
[this](int newSizeInMB) { cache->setMaximumCacheSize(1024L * 1024L * static_cast<qint64>(newSizeInMB)); });
|
||||||
networkManager->setCache(cache);
|
networkManager->setCache(cache);
|
||||||
// Use a ManualRedirectPolicy since we keep track of redirects in picDownloadFinished
|
// Use a ManualRedirectPolicy since we keep track of redirects in picDownloadFinished
|
||||||
// We can't use NoLessSafeRedirectPolicy because it is not applied with AlwaysCache
|
// We can't use NoLessSafeRedirectPolicy because it is not applied with AlwaysCache
|
||||||
|
|
@ -57,7 +57,8 @@ PictureLoaderWorker::PictureLoaderWorker()
|
||||||
moveToThread(pictureLoaderThread);
|
moveToThread(pictureLoaderThread);
|
||||||
|
|
||||||
connect(&requestTimer, &QTimer::timeout, this, &PictureLoaderWorker::processQueuedRequests);
|
connect(&requestTimer, &QTimer::timeout, this, &PictureLoaderWorker::processQueuedRequests);
|
||||||
requestTimer.setSingleShot(true);
|
requestTimer.setInterval(1000);
|
||||||
|
requestTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
PictureLoaderWorker::~PictureLoaderWorker()
|
PictureLoaderWorker::~PictureLoaderWorker()
|
||||||
|
|
@ -65,33 +66,23 @@ PictureLoaderWorker::~PictureLoaderWorker()
|
||||||
pictureLoaderThread->deleteLater();
|
pictureLoaderThread->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PictureLoaderWorker::queueRequest(const QUrl &url, PictureLoaderWorkerWork *worker)
|
||||||
|
{
|
||||||
|
QUrl cachedRedirect = getCachedRedirect(url);
|
||||||
|
if (!cachedRedirect.isEmpty()) {
|
||||||
|
queueRequest(cachedRedirect, worker);
|
||||||
|
}
|
||||||
|
if (cache->metaData(url).isValid()) {
|
||||||
|
makeRequest(url, worker);
|
||||||
|
} else {
|
||||||
|
requestLoadQueue.append(qMakePair(url, worker));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
QNetworkReply *PictureLoaderWorker::makeRequest(const QUrl &url, PictureLoaderWorkerWork *worker)
|
QNetworkReply *PictureLoaderWorker::makeRequest(const QUrl &url, PictureLoaderWorkerWork *worker)
|
||||||
{
|
{
|
||||||
constexpr int urlRequestDelayMs = 100; // Minimum delay between requests to the same URL (in milliseconds)
|
|
||||||
|
|
||||||
// Check if we're rate-limited globally
|
|
||||||
if (rateLimited) {
|
|
||||||
requestQueue.append(qMakePair(url, worker));
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if a request was recently made to this URL
|
|
||||||
QDateTime now = QDateTime::currentDateTimeUtc();
|
|
||||||
if (lastRequestTime.contains(url)) {
|
|
||||||
int elapsedMs = lastRequestTime[url].msecsTo(now);
|
|
||||||
if (elapsedMs < urlRequestDelayMs) {
|
|
||||||
// Queue the request if too soon to reissue
|
|
||||||
requestQueue.append(qMakePair(url, worker));
|
|
||||||
if (!requestTimer.isActive()) {
|
|
||||||
requestTimer.start(urlRequestDelayMs);
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the last request time for this URL
|
|
||||||
lastRequestTime[url] = now;
|
|
||||||
|
|
||||||
// Check for cached redirects
|
// Check for cached redirects
|
||||||
QUrl cachedRedirect = getCachedRedirect(url);
|
QUrl cachedRedirect = getCachedRedirect(url);
|
||||||
if (!cachedRedirect.isEmpty()) {
|
if (!cachedRedirect.isEmpty()) {
|
||||||
|
|
@ -118,10 +109,6 @@ QNetworkReply *PictureLoaderWorker::makeRequest(const QUrl &url, PictureLoaderWo
|
||||||
|
|
||||||
if (reply->error() == QNetworkReply::NoError) {
|
if (reply->error() == QNetworkReply::NoError) {
|
||||||
worker->picDownloadFinished(reply);
|
worker->picDownloadFinished(reply);
|
||||||
} else if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 429) {
|
|
||||||
handleRateLimit(url, worker);
|
|
||||||
} else {
|
|
||||||
worker->picDownloadFinished(reply);
|
|
||||||
}
|
}
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
});
|
});
|
||||||
|
|
@ -129,48 +116,15 @@ QNetworkReply *PictureLoaderWorker::makeRequest(const QUrl &url, PictureLoaderWo
|
||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PictureLoaderWorker::handleRateLimit(const QUrl &url, PictureLoaderWorkerWork *worker)
|
|
||||||
{
|
|
||||||
// Prevent multiple rate-limit handling
|
|
||||||
if (!rateLimited) {
|
|
||||||
int retryAfter = 70;
|
|
||||||
rateLimited = true;
|
|
||||||
qWarning() << "Rate limit exceeded! Queuing requests for" << retryAfter << "seconds.";
|
|
||||||
|
|
||||||
// Start a timer to reset the rate-limited state
|
|
||||||
rateLimitTimer.singleShot(retryAfter * 1000, this, [this]() {
|
|
||||||
qWarning() << "Rate limit expired. Resuming queued requests.";
|
|
||||||
processQueuedRequests();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always queue the request even if already rate-limited
|
|
||||||
requestQueue.append(qMakePair(url, worker));
|
|
||||||
}
|
|
||||||
|
|
||||||
void PictureLoaderWorker::processQueuedRequests()
|
void PictureLoaderWorker::processQueuedRequests()
|
||||||
{
|
{
|
||||||
qWarning() << "Resuming queued requests";
|
for (int i = 0; i < 10; i++) {
|
||||||
rateLimited = false;
|
if (!requestLoadQueue.isEmpty()) {
|
||||||
|
auto request = requestLoadQueue.takeFirst();
|
||||||
if (!requestQueue.isEmpty()) {
|
|
||||||
// Process requests one by one, respecting the URL delay
|
|
||||||
auto request = requestQueue.takeFirst();
|
|
||||||
QDateTime now = QDateTime::currentDateTimeUtc();
|
|
||||||
|
|
||||||
if (lastRequestTime.contains(request.first)) {
|
|
||||||
int elapsedMs = lastRequestTime[request.first].msecsTo(now);
|
|
||||||
if (elapsedMs < 100) {
|
|
||||||
// Delay request if needed
|
|
||||||
requestQueue.prepend(request); // Put back in the queue
|
|
||||||
requestTimer.start(100 - elapsedMs); // Schedule for the remaining time
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
makeRequest(request.first, request.second);
|
makeRequest(request.first, request.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PictureLoaderWorker::enqueueImageLoad(const CardInfoPtr &card)
|
void PictureLoaderWorker::enqueueImageLoad(const CardInfoPtr &card)
|
||||||
{
|
{
|
||||||
|
|
@ -186,7 +140,7 @@ void PictureLoaderWorker::imageLoadedSuccessfully(CardInfoPtr card, const QImage
|
||||||
void PictureLoaderWorker::cacheRedirect(const QUrl &originalUrl, const QUrl &redirectUrl)
|
void PictureLoaderWorker::cacheRedirect(const QUrl &originalUrl, const QUrl &redirectUrl)
|
||||||
{
|
{
|
||||||
redirectCache[originalUrl] = qMakePair(redirectUrl, QDateTime::currentDateTimeUtc());
|
redirectCache[originalUrl] = qMakePair(redirectUrl, QDateTime::currentDateTimeUtc());
|
||||||
// saveRedirectCache();
|
saveRedirectCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
QUrl PictureLoaderWorker::getCachedRedirect(const QUrl &originalUrl) const
|
QUrl PictureLoaderWorker::getCachedRedirect(const QUrl &originalUrl) const
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,16 @@
|
||||||
#define PICTURE_LOADER_WORKER_H
|
#define PICTURE_LOADER_WORKER_H
|
||||||
|
|
||||||
#include "../../../game/cards/card_database.h"
|
#include "../../../game/cards/card_database.h"
|
||||||
#include "picture_loader_worker_work.h"
|
|
||||||
#include "../../../game/cards/card_info.h"
|
#include "../../../game/cards/card_info.h"
|
||||||
|
#include "picture_loader_worker_work.h"
|
||||||
#include "picture_to_load.h"
|
#include "picture_to_load.h"
|
||||||
|
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkDiskCache>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QQueue>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
#define REDIRECT_HEADER_NAME "redirects"
|
#define REDIRECT_HEADER_NAME "redirects"
|
||||||
|
|
@ -27,13 +29,13 @@ class PictureLoaderWorker : public QObject
|
||||||
public:
|
public:
|
||||||
explicit PictureLoaderWorker();
|
explicit PictureLoaderWorker();
|
||||||
~PictureLoaderWorker() override;
|
~PictureLoaderWorker() override;
|
||||||
|
void queueRequest(const QUrl &url, PictureLoaderWorkerWork *worker);
|
||||||
|
|
||||||
void enqueueImageLoad(const CardInfoPtr &card);
|
void enqueueImageLoad(const CardInfoPtr &card);
|
||||||
void clearNetworkCache();
|
void clearNetworkCache();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
QNetworkReply *makeRequest(const QUrl &url, PictureLoaderWorkerWork *workThread);
|
QNetworkReply *makeRequest(const QUrl &url, PictureLoaderWorkerWork *workThread);
|
||||||
void handleRateLimit(const QUrl &url, PictureLoaderWorkerWork *worker);
|
|
||||||
void processQueuedRequests();
|
void processQueuedRequests();
|
||||||
void imageLoadedSuccessfully(CardInfoPtr card, const QImage &image);
|
void imageLoadedSuccessfully(CardInfoPtr card, const QImage &image);
|
||||||
|
|
||||||
|
|
@ -45,6 +47,7 @@ private:
|
||||||
QList<PictureToLoad> loadQueue;
|
QList<PictureToLoad> loadQueue;
|
||||||
QMutex mutex;
|
QMutex mutex;
|
||||||
QNetworkAccessManager *networkManager;
|
QNetworkAccessManager *networkManager;
|
||||||
|
QNetworkDiskCache *cache;
|
||||||
QHash<QUrl, QPair<QUrl, QDateTime>> redirectCache; // Stores redirect and timestamp
|
QHash<QUrl, QPair<QUrl, QDateTime>> redirectCache; // Stores redirect and timestamp
|
||||||
QString cacheFilePath; // Path to persistent storage
|
QString cacheFilePath; // Path to persistent storage
|
||||||
static constexpr int CacheTTLInDays = 30; // TODO: Make user configurable
|
static constexpr int CacheTTLInDays = 30; // TODO: Make user configurable
|
||||||
|
|
@ -52,10 +55,8 @@ private:
|
||||||
PictureToLoad cardBeingLoaded;
|
PictureToLoad cardBeingLoaded;
|
||||||
PictureToLoad cardBeingDownloaded;
|
PictureToLoad cardBeingDownloaded;
|
||||||
bool picDownload, downloadRunning, loadQueueRunning;
|
bool picDownload, downloadRunning, loadQueueRunning;
|
||||||
bool rateLimited = false;
|
QQueue<QPair<QUrl, PictureLoaderWorkerWork *>> requestLoadQueue;
|
||||||
QTimer rateLimitTimer;
|
|
||||||
QList<QPair<QUrl, PictureLoaderWorkerWork *>> requestQueue;
|
QList<QPair<QUrl, PictureLoaderWorkerWork *>> requestQueue;
|
||||||
QHash<QUrl, QDateTime> lastRequestTime; // Tracks the last request time for each URL
|
|
||||||
QTimer requestTimer; // Timer for processing delayed requests
|
QTimer requestTimer; // Timer for processing delayed requests
|
||||||
bool overrideAllCardArtWithPersonalPreference;
|
bool overrideAllCardArtWithPersonalPreference;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ QStringList PictureLoaderWorkerWork::md5Blacklist = QStringList() << "db0c48db40
|
||||||
PictureLoaderWorkerWork::PictureLoaderWorkerWork(PictureLoaderWorker *_worker, const CardInfoPtr &toLoad)
|
PictureLoaderWorkerWork::PictureLoaderWorkerWork(PictureLoaderWorker *_worker, const CardInfoPtr &toLoad)
|
||||||
: QThread(nullptr), worker(_worker), cardToDownload(toLoad)
|
: QThread(nullptr), worker(_worker), cardToDownload(toLoad)
|
||||||
{
|
{
|
||||||
connect(this, &PictureLoaderWorkerWork::requestImageDownload, worker, &PictureLoaderWorker::makeRequest,
|
connect(this, &PictureLoaderWorkerWork::requestImageDownload, worker, &PictureLoaderWorker::queueRequest,
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
connect(this, &PictureLoaderWorkerWork::imageLoaded, worker, &PictureLoaderWorker::imageLoadedSuccessfully,
|
connect(this, &PictureLoaderWorkerWork::imageLoaded, worker, &PictureLoaderWorker::imageLoadedSuccessfully,
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue