diff --git a/src/common/vfs.h b/src/common/vfs.h index 39bf0c03a44ce..b6f92dacbd54f 100644 --- a/src/common/vfs.h +++ b/src/common/vfs.h @@ -265,6 +265,8 @@ public slots: void beginHydrating(); /// Emitted when the hydration ends void doneHydrating(); + // Emitted when hydration fails + void failureHydrating(int errorCode, int statusCode, const QString &errorString); protected: /** Setup the plugin for the folder. diff --git a/src/gui/folder.cpp b/src/gui/folder.cpp index e4984f53a7c70..b693a84bd1cb7 100644 --- a/src/gui/folder.cpp +++ b/src/gui/folder.cpp @@ -506,6 +506,7 @@ void Folder::startVfs() connect(_vfs.data(), &Vfs::beginHydrating, this, &Folder::slotHydrationStarts); connect(_vfs.data(), &Vfs::doneHydrating, this, &Folder::slotHydrationDone); + connect(_vfs.data(), &Vfs::failureHydrating, this, &Folder::slotHydrationFailed); connect(&_engine->syncFileStatusTracker(), &SyncFileStatusTracker::fileStatusChanged, _vfs.data(), &Vfs::fileStatusChanged); @@ -1510,6 +1511,27 @@ void Folder::slotHydrationDone() emit syncStateChange(); } +void Folder::slotHydrationFailed(int errorCode, int statusCode, const QString &errorString) +{ + _syncResult.setStatus(SyncResult::Error); + const auto errorMessage = tr("Virtual file download failed with code %1, status %2 and error message %3") + .arg(errorCode) + .arg(statusCode) + .arg(errorString); + const auto errorCategory = statusCode != 200 && statusCode != 204 ? ErrorCategory::NetworkError : ErrorCategory::GenericError; + slotSyncError(errorMessage, errorCategory); + + const auto errorMessageBox = new QMessageBox; + errorMessageBox->setAttribute(Qt::WA_DeleteOnClose); + errorMessageBox->setText(tr("Virtual file download failed")); + errorMessageBox->setInformativeText(errorMessage); + errorMessageBox->setIcon(QMessageBox::Critical); + errorMessageBox->addButton(QMessageBox::StandardButton::Ok); + errorMessageBox->show(); + errorMessageBox->activateWindow(); + errorMessageBox->raise(); +} + void Folder::slotCapabilitiesChanged() { if (_accountState->account()->capabilities().filesLockAvailable()) { diff --git a/src/gui/folder.h b/src/gui/folder.h index 4b4e6e15a3b65..0149c2ec682ab 100644 --- a/src/gui/folder.h +++ b/src/gui/folder.h @@ -449,6 +449,9 @@ private slots: /** Unblocks normal sync operation */ void slotHydrationDone(); + /* Hydration failed, perform required steps to notify user */ + void slotHydrationFailed(int errorCode, int statusCode, const QString &errorString); + void slotCapabilitiesChanged(); private: diff --git a/src/libsync/vfs/cfapi/hydrationjob.cpp b/src/libsync/vfs/cfapi/hydrationjob.cpp index daaf657394eef..58e30c22b5710 100644 --- a/src/libsync/vfs/cfapi/hydrationjob.cpp +++ b/src/libsync/vfs/cfapi/hydrationjob.cpp @@ -116,6 +116,21 @@ OCC::HydrationJob::Status OCC::HydrationJob::status() const return _status; } +int OCC::HydrationJob::errorCode() const +{ + return _errorCode; +} + +int OCC::HydrationJob::statusCode() const +{ + return _statusCode; +} + +QString OCC::HydrationJob::errorString() const +{ + return _errorString; +} + void OCC::HydrationJob::start() { Q_ASSERT(_account); @@ -334,16 +349,21 @@ void OCC::HydrationJob::finalize(OCC::VfsCfApi *vfs) void OCC::HydrationJob::onGetFinished() { - qCInfo(lcHydration) << "GETFileJob finished" << _requestId << _folderPath << _job->reply()->error(); + _errorCode = _job->reply()->error(); + _statusCode = _job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + _errorString = _job->reply()->errorString(); - const auto isGetJobResultError = _job->reply()->error(); + qCInfo(lcHydration) << "GETFileJob finished" << _requestId << _folderPath << _errorCode << _statusCode << _errorString; // GETFileJob deletes itself after this signal was handled _job = nullptr; if (_isCancelled) { + _errorCode = 0; + _statusCode = 0; + _errorString.clear(); return; } - if (isGetJobResultError) { + if (_errorCode) { emitFinished(Error); return; } diff --git a/src/libsync/vfs/cfapi/hydrationjob.h b/src/libsync/vfs/cfapi/hydrationjob.h index c13cd7b5021a3..153da71f913f5 100644 --- a/src/libsync/vfs/cfapi/hydrationjob.h +++ b/src/libsync/vfs/cfapi/hydrationjob.h @@ -71,6 +71,10 @@ class HydrationJob : public QObject Status status() const; + [[nodiscard]] int errorCode() const; + [[nodiscard]] int statusCode() const; + [[nodiscard]] QString errorString() const; + void start(); void cancel(); void finalize(OCC::VfsCfApi *vfs); @@ -114,6 +118,9 @@ public slots: QLocalSocket *_signalSocket = nullptr; GETFileJob *_job = nullptr; Status _status = Success; + int _errorCode = 0; + int _statusCode = 0; + QString _errorString; }; } // namespace OCC diff --git a/src/libsync/vfs/cfapi/vfs_cfapi.cpp b/src/libsync/vfs/cfapi/vfs_cfapi.cpp index 7763a2fd85a4f..a83963d87089b 100644 --- a/src/libsync/vfs/cfapi/vfs_cfapi.cpp +++ b/src/libsync/vfs/cfapi/vfs_cfapi.cpp @@ -448,6 +448,9 @@ void VfsCfApi::onHydrationJobFinished(HydrationJob *job) Q_ASSERT(d->hydrationJobs.contains(job)); qCInfo(lcCfApi) << "Hydration job finished" << job->requestId() << job->folderPath() << job->status(); emit hydrationRequestFinished(job->requestId()); + if (!job->errorString().isEmpty()) { + emit failureHydrating(job->errorCode(), job->statusCode(), job->errorString()); + } } int VfsCfApi::finalizeHydrationJob(const QString &requestId)