From ccc0000fd0cee4ec5eb1feaaf26fe1de94c6e243 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 3 Aug 2015 16:26:16 -0700 Subject: [PATCH] Update ResourceCache to use ResourceRequest --- libraries/networking/src/ResourceCache.cpp | 266 ++++++++++++--------- libraries/networking/src/ResourceCache.h | 17 +- 2 files changed, 157 insertions(+), 126 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index e127380630..2903e810f2 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -155,6 +155,7 @@ void ResourceCache::clearUnusedResource() { void ResourceCache::attemptRequest(Resource* resource) { auto sharedItems = DependencyManager::get(); if (_requestLimit <= 0) { + qDebug() << "REQUEST LIMIT REACHED, queueing: " << resource->getURL(); // wait until a slot becomes available sharedItems->_pendingRequests.append(resource); return; @@ -187,6 +188,7 @@ void ResourceCache::requestCompleted(Resource* resource) { i++; } if (highestIndex >= 0) { + qDebug() << "trying to attempt a pending request"; attemptRequest(sharedItems->_pendingRequests.takeAt(highestIndex)); } } @@ -196,24 +198,22 @@ int ResourceCache::_requestLimit = DEFAULT_REQUEST_LIMIT; Resource::Resource(const QUrl& url, bool delayLoad) : _url(url), - _request(url) { + _request(nullptr) { init(); - _request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); - _request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); - // start loading immediately unless instructed otherwise if (!(_startedLoading || delayLoad)) { - attemptRequest(); + QTimer::singleShot(1, this, &Resource::attemptRequest); + //attemptRequest(); } } Resource::~Resource() { - if (_reply) { + if (_request) { ResourceCache::requestCompleted(this); - delete _reply; - _reply = nullptr; + _request->deleteLater(); + _request = nullptr; } } @@ -259,21 +259,20 @@ float Resource::getLoadPriority() { } void Resource::refresh() { - if (_reply && !(_loaded || _failedToLoad)) { + if (_request && !(_loaded || _failedToLoad)) { return; } - if (_reply) { + if (_request) { + _request->disconnect(this); + // _requestTimer->disconnect(this); + _request->deleteLater(); + _request = nullptr; + // _requestTimer->deleteLater(); + // _requestTimer = nullptr; ResourceCache::requestCompleted(this); - _reply->disconnect(this); - _replyTimer->disconnect(this); - _reply->deleteLater(); - _reply = nullptr; - _replyTimer->deleteLater(); - _replyTimer = nullptr; } init(); - _request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); ensureLoading(); emit onRefresh(); } @@ -331,34 +330,34 @@ void Resource::reinsert() { _cache->_resources.insert(_url, _self); } -static const int REPLY_TIMEOUT_MS = 5000; -void Resource::handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { - if (!_reply->isFinished()) { - _bytesReceived = bytesReceived; - _bytesTotal = bytesTotal; - _replyTimer->start(REPLY_TIMEOUT_MS); - return; - } - _reply->disconnect(this); - _replyTimer->disconnect(this); - QNetworkReply* reply = _reply; - _reply = nullptr; - _replyTimer->deleteLater(); - _replyTimer = nullptr; - ResourceCache::requestCompleted(this); - - downloadFinished(reply); -} - -void Resource::handleReplyError() { - handleReplyError(_reply->error(), qDebug() << _reply->errorString()); -} - -void Resource::handleReplyTimeout() { - handleReplyError(QNetworkReply::TimeoutError, qDebug() << "Timed out loading" << _reply->url() << - "received" << _bytesReceived << "total" << _bytesTotal); -} - +// static const int REPLY_TIMEOUT_MS = 5000; +// void Resource::handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { +// if (!_reply->isFinished()) { +// _bytesReceived = bytesReceived; +// _bytesTotal = bytesTotal; +// _replyTimer->start(REPLY_TIMEOUT_MS); +// return; +// } +// _reply->disconnect(this); +// _replyTimer->disconnect(this); +// QNetworkReply* reply = _reply; +// _reply = nullptr; +// _replyTimer->deleteLater(); +// _replyTimer = nullptr; +// ResourceCache::requestCompleted(this); +// +// // downloadFinished(reply); +// } +// +// void Resource::handleReplyError() { +// handleReplyError(_reply->error(), qDebug() << _reply->errorString()); +// } +// +// void Resource::handleReplyTimeout() { +// handleReplyError(QNetworkReply::TimeoutError, qDebug() << "Timed out loading" << _reply->url() << +// "received" << _bytesReceived << "total" << _bytesTotal); +// } +// void Resource::maybeRefresh() { if (Q_LIKELY(NetworkAccessManager::getInstance().cache())) { QNetworkReply* reply = qobject_cast(sender()); @@ -383,87 +382,116 @@ void Resource::maybeRefresh() { } } +// #include "AssetManager.h" void Resource::makeRequest() { - _reply = NetworkAccessManager::getInstance().get(_request); - - connect(_reply, SIGNAL(downloadProgress(qint64,qint64)), SLOT(handleDownloadProgress(qint64,qint64))); - connect(_reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(handleReplyError())); - connect(_reply, SIGNAL(finished()), SLOT(handleReplyFinished())); - - 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); - } - } + auto request = ResourceManager::createResourceRequest(this, _url); + _request = request; + if (!_request) { + qDebug() << "Failed to get request for " << _url; + return; } - _replyTimer = new QTimer(this); - connect(_replyTimer, SIGNAL(timeout()), SLOT(handleReplyTimeout())); - _replyTimer->setSingleShot(true); - _replyTimer->start(REPLY_TIMEOUT_MS); + qDebug() << "Starting request for: " << _url; + + connect(request, &ResourceRequest::finished, this, &Resource::handleReplyFinished); + // 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; } -void Resource::handleReplyError(QNetworkReply::NetworkError error, QDebug debug) { - _reply->disconnect(this); - _replyTimer->disconnect(this); - _reply->deleteLater(); - _reply = nullptr; - _replyTimer->deleteLater(); - _replyTimer = nullptr; - ResourceCache::requestCompleted(this); - - // retry for certain types of failures - switch (error) { - case QNetworkReply::RemoteHostClosedError: - case QNetworkReply::TimeoutError: - case QNetworkReply::TemporaryNetworkFailureError: - case QNetworkReply::ProxyConnectionClosedError: - case QNetworkReply::ProxyTimeoutError: - case QNetworkReply::UnknownNetworkError: - case QNetworkReply::UnknownProxyError: - case QNetworkReply::UnknownContentError: - case QNetworkReply::ProtocolFailure: { - // retry with increasing delays - const int MAX_ATTEMPTS = 8; - const int BASE_DELAY_MS = 1000; - if (++_attempts < MAX_ATTEMPTS) { - QTimer::singleShot(BASE_DELAY_MS * (int)pow(2.0, _attempts), this, SLOT(attemptRequest())); - debug << "-- retrying..."; - return; - } - // fall through to final failure - } - default: - finishedLoading(false); - break; - } -} - +// void Resource::handleReplyError(QNetworkReply::NetworkError error, QDebug debug) { +// _reply->disconnect(this); +// _replyTimer->disconnect(this); +// _reply->deleteLater(); +// _reply = nullptr; +// _replyTimer->deleteLater(); +// _replyTimer = nullptr; +// ResourceCache::requestCompleted(this); +// +// // retry for certain types of failures +// switch (error) { +// case QNetworkReply::RemoteHostClosedError: +// case QNetworkReply::TimeoutError: +// case QNetworkReply::TemporaryNetworkFailureError: +// case QNetworkReply::ProxyConnectionClosedError: +// case QNetworkReply::ProxyTimeoutError: +// case QNetworkReply::UnknownNetworkError: +// case QNetworkReply::UnknownProxyError: +// case QNetworkReply::UnknownContentError: +// case QNetworkReply::ProtocolFailure: { +// // retry with increasing delays +// const int MAX_ATTEMPTS = 8; +// const int BASE_DELAY_MS = 1000; +// if (++_attempts < MAX_ATTEMPTS) { +// QTimer::singleShot(BASE_DELAY_MS * (int)pow(2.0, _attempts), this, SLOT(attemptRequest())); +// debug << "-- retrying..."; +// return; +// } +// // fall through to final failure +// } +// default: +// finishedLoading(false); +// break; +// } +// } +// void Resource::handleReplyFinished() { - qCDebug(networking) << "Got finished without download progress/error?" << _url; - handleDownloadProgress(0, 0); + // _request->disconnect(this); + // _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& value, uint seed) { diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 93ddfe77be..59192449b8 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -26,6 +26,8 @@ #include +#include "ResourceManager.h" + class QNetworkReply; class QTimer; @@ -102,7 +104,7 @@ protected: void reserveUnusedResource(qint64 resourceSize); void clearUnusedResource(); - static void attemptRequest(Resource* resource); + Q_INVOKABLE static void attemptRequest(Resource* resource); static void requestCompleted(Resource* resource); private: @@ -188,7 +190,7 @@ protected: virtual void init(); /// 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. Q_INVOKABLE void finishedLoading(bool success); @@ -197,19 +199,21 @@ protected: virtual void reinsert(); QUrl _url; - QNetworkRequest _request; + ResourceRequest* _request = nullptr; + //QNetworkRequest _request; bool _startedLoading = false; bool _failedToLoad = false; bool _loaded = false; QHash, float> _loadPriorities; QWeakPointer _self; QPointer _cache; + QByteArray _data; private slots: - void handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); - void handleReplyError(); + // void handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); + // void handleReplyError(); void handleReplyFinished(); - void handleReplyTimeout(); + // void handleReplyTimeout(); private: void setLRUKey(int lruKey) { _lruKey = lruKey; } @@ -221,7 +225,6 @@ private: friend class ResourceCache; int _lruKey = 0; - QNetworkReply* _reply = nullptr; QTimer* _replyTimer = nullptr; qint64 _bytesReceived = 0; qint64 _bytesTotal = 0;