diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index a8311c6146..8faf7082cd 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -14,6 +14,7 @@ #include "AssetClient.h" #include "AssetUtils.h" #include "MappingRequest.h" +#include AssetResourceRequest::~AssetResourceRequest() { if (_assetMappingRequest) { @@ -23,6 +24,10 @@ AssetResourceRequest::~AssetResourceRequest() { if (_assetRequest) { _assetRequest->deleteLater(); } + + if (_sendTimer) { + cleanupTimer(); + } } bool AssetResourceRequest::urlIsAssetHash() const { @@ -32,6 +37,25 @@ bool AssetResourceRequest::urlIsAssetHash() const { return hashRegex.exactMatch(_url.toString()); } +void AssetResourceRequest::setupTimer() { + Q_ASSERT(!_sendTimer); + static const int TIMEOUT_MS = 2000; + + _sendTimer = new QTimer(); + connect(this, &QObject::destroyed, _sendTimer, &QTimer::deleteLater); + connect(_sendTimer, &QTimer::timeout, this, &AssetResourceRequest::onTimeout); + + _sendTimer->setSingleShot(true); + _sendTimer->start(TIMEOUT_MS); +} + +void AssetResourceRequest::cleanupTimer() { + Q_ASSERT(_sendTimer); + disconnect(_sendTimer, 0, this, 0); + _sendTimer->deleteLater(); + _sendTimer = nullptr; +} + void AssetResourceRequest::doSend() { // We'll either have a hash or an ATP path to a file (that maps to a hash) if (urlIsAssetHash()) { @@ -58,6 +82,8 @@ void AssetResourceRequest::requestMappingForPath(const AssetPath& path) { Q_ASSERT(_state == InProgress); Q_ASSERT(request == _assetMappingRequest); + cleanupTimer(); + switch (request->getError()) { case MappingRequest::NoError: // we have no error, we should have a resulting hash - use that to send of a request for that asset @@ -93,6 +119,7 @@ void AssetResourceRequest::requestMappingForPath(const AssetPath& path) { _assetMappingRequest = nullptr; }); + setupTimer(); _assetMappingRequest->start(); } @@ -102,11 +129,15 @@ void AssetResourceRequest::requestHash(const AssetHash& hash) { auto assetClient = DependencyManager::get(); _assetRequest = assetClient->createRequest(hash); - connect(_assetRequest, &AssetRequest::progress, this, &AssetResourceRequest::progress); + connect(_assetRequest, &AssetRequest::progress, this, &AssetResourceRequest::onDownloadProgress); connect(_assetRequest, &AssetRequest::finished, this, [this](AssetRequest* req) { Q_ASSERT(_state == InProgress); Q_ASSERT(req == _assetRequest); Q_ASSERT(req->getState() == AssetRequest::Finished); + + cleanupTimer(); + + qDebug() << "Asset request finished, " << req->getHash() << "error: " << req->getError(); switch (req->getError()) { case AssetRequest::Error::NoError: @@ -134,9 +165,35 @@ void AssetResourceRequest::requestHash(const AssetHash& hash) { _assetRequest = nullptr; }); + setupTimer(); _assetRequest->start(); } void AssetResourceRequest::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { + Q_ASSERT(_state == InProgress); + + // We've received data, so reset the timer + _sendTimer->start(); + emit progress(bytesReceived, bytesTotal); } + +void AssetResourceRequest::onTimeout() { + if (_state == InProgress) { + qWarning() << "Asset request timed out: " << _url; + if (_assetRequest) { + disconnect(_assetRequest, 0, this, 0); + _assetRequest->deleteLater(); + _assetRequest = nullptr; + } + if (_assetMappingRequest) { + disconnect(_assetMappingRequest, 0, this, 0); + _assetMappingRequest->deleteLater(); + _assetMappingRequest = nullptr; + } + _result = Timeout; + _state = Finished; + emit finished(); + } + cleanupTimer(); +} diff --git a/libraries/networking/src/AssetResourceRequest.h b/libraries/networking/src/AssetResourceRequest.h index 6839db0628..c462fbc3f8 100644 --- a/libraries/networking/src/AssetResourceRequest.h +++ b/libraries/networking/src/AssetResourceRequest.h @@ -28,13 +28,19 @@ protected: private slots: void onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); + void onTimeout(); private: + void setupTimer(); + void cleanupTimer(); + bool urlIsAssetHash() const; void requestMappingForPath(const AssetPath& path); void requestHash(const AssetHash& hash); + QTimer* _sendTimer { nullptr }; + GetMappingRequest* _assetMappingRequest { nullptr }; AssetRequest* _assetRequest { nullptr }; };