Update ResourceCache to use ResourceRequest

This commit is contained in:
Ryan Huffman 2015-08-03 16:26:16 -07:00
parent fc9cd836ce
commit ccc0000fd0
2 changed files with 157 additions and 126 deletions

View file

@ -155,6 +155,7 @@ void ResourceCache::clearUnusedResource() {
void ResourceCache::attemptRequest(Resource* resource) { void ResourceCache::attemptRequest(Resource* resource) {
auto sharedItems = DependencyManager::get<ResourceCacheSharedItems>(); auto sharedItems = DependencyManager::get<ResourceCacheSharedItems>();
if (_requestLimit <= 0) { if (_requestLimit <= 0) {
qDebug() << "REQUEST LIMIT REACHED, queueing: " << resource->getURL();
// wait until a slot becomes available // wait until a slot becomes available
sharedItems->_pendingRequests.append(resource); sharedItems->_pendingRequests.append(resource);
return; return;
@ -187,6 +188,7 @@ void ResourceCache::requestCompleted(Resource* resource) {
i++; i++;
} }
if (highestIndex >= 0) { if (highestIndex >= 0) {
qDebug() << "trying to attempt a pending request";
attemptRequest(sharedItems->_pendingRequests.takeAt(highestIndex)); attemptRequest(sharedItems->_pendingRequests.takeAt(highestIndex));
} }
} }
@ -196,24 +198,22 @@ int ResourceCache::_requestLimit = DEFAULT_REQUEST_LIMIT;
Resource::Resource(const QUrl& url, bool delayLoad) : Resource::Resource(const QUrl& url, bool delayLoad) :
_url(url), _url(url),
_request(url) { _request(nullptr) {
init(); init();
_request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
_request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
// start loading immediately unless instructed otherwise // start loading immediately unless instructed otherwise
if (!(_startedLoading || delayLoad)) { if (!(_startedLoading || delayLoad)) {
attemptRequest(); QTimer::singleShot(1, this, &Resource::attemptRequest);
//attemptRequest();
} }
} }
Resource::~Resource() { Resource::~Resource() {
if (_reply) { if (_request) {
ResourceCache::requestCompleted(this); ResourceCache::requestCompleted(this);
delete _reply; _request->deleteLater();
_reply = nullptr; _request = nullptr;
} }
} }
@ -259,21 +259,20 @@ float Resource::getLoadPriority() {
} }
void Resource::refresh() { void Resource::refresh() {
if (_reply && !(_loaded || _failedToLoad)) { if (_request && !(_loaded || _failedToLoad)) {
return; return;
} }
if (_reply) { if (_request) {
_request->disconnect(this);
// _requestTimer->disconnect(this);
_request->deleteLater();
_request = nullptr;
// _requestTimer->deleteLater();
// _requestTimer = nullptr;
ResourceCache::requestCompleted(this); ResourceCache::requestCompleted(this);
_reply->disconnect(this);
_replyTimer->disconnect(this);
_reply->deleteLater();
_reply = nullptr;
_replyTimer->deleteLater();
_replyTimer = nullptr;
} }
init(); init();
_request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork);
ensureLoading(); ensureLoading();
emit onRefresh(); emit onRefresh();
} }
@ -331,34 +330,34 @@ void Resource::reinsert() {
_cache->_resources.insert(_url, _self); _cache->_resources.insert(_url, _self);
} }
static const int REPLY_TIMEOUT_MS = 5000; // static const int REPLY_TIMEOUT_MS = 5000;
void Resource::handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { // void Resource::handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) {
if (!_reply->isFinished()) { // if (!_reply->isFinished()) {
_bytesReceived = bytesReceived; // _bytesReceived = bytesReceived;
_bytesTotal = bytesTotal; // _bytesTotal = bytesTotal;
_replyTimer->start(REPLY_TIMEOUT_MS); // _replyTimer->start(REPLY_TIMEOUT_MS);
return; // return;
} // }
_reply->disconnect(this); // _reply->disconnect(this);
_replyTimer->disconnect(this); // _replyTimer->disconnect(this);
QNetworkReply* reply = _reply; // QNetworkReply* reply = _reply;
_reply = nullptr; // _reply = nullptr;
_replyTimer->deleteLater(); // _replyTimer->deleteLater();
_replyTimer = nullptr; // _replyTimer = nullptr;
ResourceCache::requestCompleted(this); // ResourceCache::requestCompleted(this);
//
downloadFinished(reply); // // downloadFinished(reply);
} // }
//
void Resource::handleReplyError() { // void Resource::handleReplyError() {
handleReplyError(_reply->error(), qDebug() << _reply->errorString()); // handleReplyError(_reply->error(), qDebug() << _reply->errorString());
} // }
//
void Resource::handleReplyTimeout() { // void Resource::handleReplyTimeout() {
handleReplyError(QNetworkReply::TimeoutError, qDebug() << "Timed out loading" << _reply->url() << // handleReplyError(QNetworkReply::TimeoutError, qDebug() << "Timed out loading" << _reply->url() <<
"received" << _bytesReceived << "total" << _bytesTotal); // "received" << _bytesReceived << "total" << _bytesTotal);
} // }
//
void Resource::maybeRefresh() { void Resource::maybeRefresh() {
if (Q_LIKELY(NetworkAccessManager::getInstance().cache())) { if (Q_LIKELY(NetworkAccessManager::getInstance().cache())) {
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender()); QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
@ -383,87 +382,116 @@ void Resource::maybeRefresh() {
} }
} }
// #include "AssetManager.h"
void Resource::makeRequest() { void Resource::makeRequest() {
_reply = NetworkAccessManager::getInstance().get(_request); auto request = ResourceManager::createResourceRequest(this, _url);
_request = request;
connect(_reply, SIGNAL(downloadProgress(qint64,qint64)), SLOT(handleDownloadProgress(qint64,qint64))); if (!_request) {
connect(_reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(handleReplyError())); qDebug() << "Failed to get request for " << _url;
connect(_reply, SIGNAL(finished()), SLOT(handleReplyFinished())); return;
if (_reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool()) {
// If the file as been updated since it was cached, refresh it
QNetworkRequest request(_request);
request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork);
request.setAttribute(QNetworkRequest::CacheSaveControlAttribute, false);
QNetworkReply* reply = NetworkAccessManager::getInstance().head(request);
connect(reply, &QNetworkReply::finished, this, &Resource::maybeRefresh);
} else {
if (Q_LIKELY(NetworkAccessManager::getInstance().cache())) {
QNetworkCacheMetaData metaData = NetworkAccessManager::getInstance().cache()->metaData(_url);
bool needUpdate = false;
if (metaData.expirationDate().isNull() || metaData.expirationDate() <= QDateTime::currentDateTime()) {
// If the expiration date is NULL or in the past,
// put one far enough away that it won't be an issue.
metaData.setExpirationDate(QDateTime::currentDateTime().addYears(100));
needUpdate = true;
}
if (metaData.lastModified().isNull()) {
// If the lastModified date is NULL, set it to now.
metaData.setLastModified(QDateTime::currentDateTime());
needUpdate = true;
}
if (needUpdate) {
NetworkAccessManager::getInstance().cache()->updateMetaData(metaData);
}
}
} }
_replyTimer = new QTimer(this); qDebug() << "Starting request for: " << _url;
connect(_replyTimer, SIGNAL(timeout()), SLOT(handleReplyTimeout()));
_replyTimer->setSingleShot(true); connect(request, &ResourceRequest::finished, this, &Resource::handleReplyFinished);
_replyTimer->start(REPLY_TIMEOUT_MS); // connect(_reply, SIGNAL(downloadProgress(qint64,qint64)), SLOT(handleDownloadProgress(qint64,qint64)));
// connect(_reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(handleReplyError()));
// connect(_reply, SIGNAL(finished()), SLOT(handleReplyFinished()));
// AssetManager::getAsset(_url, [this](AssetRequestUpdateType type, QByteArray data) {
// if (type == AssetRequestUpdateType::COMPLETE) {
// downloadFinished(data);
// } else {
// handleReplyError(QNetworkReply::TimeoutError, qDebug());
// }
// });
//
request->send();
// if (_reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool()) {
// // If the file as been updated since it was cached, refresh it
// QNetworkRequest request(_request);
// request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork);
// request.setAttribute(QNetworkRequest::CacheSaveControlAttribute, false);
// QNetworkReply* reply = NetworkAccessManager::getInstance().head(request);
// connect(reply, &QNetworkReply::finished, this, &Resource::maybeRefresh);
// } else {
// if (Q_LIKELY(NetworkAccessManager::getInstance().cache())) {
// QNetworkCacheMetaData metaData = NetworkAccessManager::getInstance().cache()->metaData(_url);
// bool needUpdate = false;
// if (metaData.expirationDate().isNull() || metaData.expirationDate() <= QDateTime::currentDateTime()) {
// // If the expiration date is NULL or in the past,
// // put one far enough away that it won't be an issue.
// metaData.setExpirationDate(QDateTime::currentDateTime().addYears(100));
// needUpdate = true;
// }
// if (metaData.lastModified().isNull()) {
// // If the lastModified date is NULL, set it to now.
// metaData.setLastModified(QDateTime::currentDateTime());
// needUpdate = true;
// }
// if (needUpdate) {
// NetworkAccessManager::getInstance().cache()->updateMetaData(metaData);
// }
// }
// }
// _replyTimer = new QTimer(this);
// connect(_replyTimer, SIGNAL(timeout()), SLOT(handleReplyTimeout()));
// _replyTimer->setSingleShot(true);
// _replyTimer->start(REPLY_TIMEOUT_MS);
_bytesReceived = _bytesTotal = 0; _bytesReceived = _bytesTotal = 0;
} }
void Resource::handleReplyError(QNetworkReply::NetworkError error, QDebug debug) { // void Resource::handleReplyError(QNetworkReply::NetworkError error, QDebug debug) {
_reply->disconnect(this); // _reply->disconnect(this);
_replyTimer->disconnect(this); // _replyTimer->disconnect(this);
_reply->deleteLater(); // _reply->deleteLater();
_reply = nullptr; // _reply = nullptr;
_replyTimer->deleteLater(); // _replyTimer->deleteLater();
_replyTimer = nullptr; // _replyTimer = nullptr;
ResourceCache::requestCompleted(this); // ResourceCache::requestCompleted(this);
//
// retry for certain types of failures // // retry for certain types of failures
switch (error) { // switch (error) {
case QNetworkReply::RemoteHostClosedError: // case QNetworkReply::RemoteHostClosedError:
case QNetworkReply::TimeoutError: // case QNetworkReply::TimeoutError:
case QNetworkReply::TemporaryNetworkFailureError: // case QNetworkReply::TemporaryNetworkFailureError:
case QNetworkReply::ProxyConnectionClosedError: // case QNetworkReply::ProxyConnectionClosedError:
case QNetworkReply::ProxyTimeoutError: // case QNetworkReply::ProxyTimeoutError:
case QNetworkReply::UnknownNetworkError: // case QNetworkReply::UnknownNetworkError:
case QNetworkReply::UnknownProxyError: // case QNetworkReply::UnknownProxyError:
case QNetworkReply::UnknownContentError: // case QNetworkReply::UnknownContentError:
case QNetworkReply::ProtocolFailure: { // case QNetworkReply::ProtocolFailure: {
// retry with increasing delays // // retry with increasing delays
const int MAX_ATTEMPTS = 8; // const int MAX_ATTEMPTS = 8;
const int BASE_DELAY_MS = 1000; // const int BASE_DELAY_MS = 1000;
if (++_attempts < MAX_ATTEMPTS) { // if (++_attempts < MAX_ATTEMPTS) {
QTimer::singleShot(BASE_DELAY_MS * (int)pow(2.0, _attempts), this, SLOT(attemptRequest())); // QTimer::singleShot(BASE_DELAY_MS * (int)pow(2.0, _attempts), this, SLOT(attemptRequest()));
debug << "-- retrying..."; // debug << "-- retrying...";
return; // return;
} // }
// fall through to final failure // // fall through to final failure
} // }
default: // default:
finishedLoading(false); // finishedLoading(false);
break; // break;
} // }
} // }
//
void Resource::handleReplyFinished() { void Resource::handleReplyFinished() {
qCDebug(networking) << "Got finished without download progress/error?" << _url; // _request->disconnect(this);
handleDownloadProgress(0, 0); // _request->deleteLater();
// _request = nullptr;
Q_ASSERT(_request);
if (_request->getResult() == ResourceRequest::SUCCESS) {
_data = _request->moveData();
_request->disconnect(this);
_request->deleteLater();
_request = nullptr;
downloadFinished(_data);
}
ResourceCache::requestCompleted(this);
} }
uint qHash(const QPointer<QObject>& value, uint seed) { uint qHash(const QPointer<QObject>& value, uint seed) {

View file

@ -26,6 +26,8 @@
#include <DependencyManager.h> #include <DependencyManager.h>
#include "ResourceManager.h"
class QNetworkReply; class QNetworkReply;
class QTimer; class QTimer;
@ -102,7 +104,7 @@ protected:
void reserveUnusedResource(qint64 resourceSize); void reserveUnusedResource(qint64 resourceSize);
void clearUnusedResource(); void clearUnusedResource();
static void attemptRequest(Resource* resource); Q_INVOKABLE static void attemptRequest(Resource* resource);
static void requestCompleted(Resource* resource); static void requestCompleted(Resource* resource);
private: private:
@ -188,7 +190,7 @@ protected:
virtual void init(); virtual void init();
/// Called when the download has finished. The recipient should delete the reply when done with it. /// Called when the download has finished. The recipient should delete the reply when done with it.
virtual void downloadFinished(QNetworkReply* reply) = 0; virtual void downloadFinished(const QByteArray& data) = 0;
/// Should be called by subclasses when all the loading that will be done has been done. /// Should be called by subclasses when all the loading that will be done has been done.
Q_INVOKABLE void finishedLoading(bool success); Q_INVOKABLE void finishedLoading(bool success);
@ -197,19 +199,21 @@ protected:
virtual void reinsert(); virtual void reinsert();
QUrl _url; QUrl _url;
QNetworkRequest _request; ResourceRequest* _request = nullptr;
//QNetworkRequest _request;
bool _startedLoading = false; bool _startedLoading = false;
bool _failedToLoad = false; bool _failedToLoad = false;
bool _loaded = false; bool _loaded = false;
QHash<QPointer<QObject>, float> _loadPriorities; QHash<QPointer<QObject>, float> _loadPriorities;
QWeakPointer<Resource> _self; QWeakPointer<Resource> _self;
QPointer<ResourceCache> _cache; QPointer<ResourceCache> _cache;
QByteArray _data;
private slots: private slots:
void handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); // void handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
void handleReplyError(); // void handleReplyError();
void handleReplyFinished(); void handleReplyFinished();
void handleReplyTimeout(); // void handleReplyTimeout();
private: private:
void setLRUKey(int lruKey) { _lruKey = lruKey; } void setLRUKey(int lruKey) { _lruKey = lruKey; }
@ -221,7 +225,6 @@ private:
friend class ResourceCache; friend class ResourceCache;
int _lruKey = 0; int _lruKey = 0;
QNetworkReply* _reply = nullptr;
QTimer* _replyTimer = nullptr; QTimer* _replyTimer = nullptr;
qint64 _bytesReceived = 0; qint64 _bytesReceived = 0;
qint64 _bytesTotal = 0; qint64 _bytesTotal = 0;