mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-23 05:25:50 +03:00
CFAPI: Handle cancelation of hydration requests
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
This commit is contained in:
parent
6abb0b2184
commit
9bf5b5c7ba
7 changed files with 94 additions and 1 deletions
|
@ -342,6 +342,15 @@ void GETFileJob::slotReadyRead()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GETFileJob::cancel()
|
||||||
|
{
|
||||||
|
if (reply()->isRunning()) {
|
||||||
|
reply()->abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
emit canceled();
|
||||||
|
}
|
||||||
|
|
||||||
void GETFileJob::onTimedOut()
|
void GETFileJob::onTimedOut()
|
||||||
{
|
{
|
||||||
qCWarning(lcGetJob) << "Timeout" << (reply() ? reply()->request().url() : path());
|
qCWarning(lcGetJob) << "Timeout" << (reply() ? reply()->request().url() : path());
|
||||||
|
|
|
@ -83,6 +83,8 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cancel();
|
||||||
|
|
||||||
void newReplyHook(QNetworkReply *reply) override;
|
void newReplyHook(QNetworkReply *reply) override;
|
||||||
|
|
||||||
void setBandwidthManager(BandwidthManager *bwm);
|
void setBandwidthManager(BandwidthManager *bwm);
|
||||||
|
@ -108,6 +110,7 @@ public:
|
||||||
void setExpectedContentLength(qint64 size) { _expectedContentLength = size; }
|
void setExpectedContentLength(qint64 size) { _expectedContentLength = size; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
void canceled();
|
||||||
void finishedSignal();
|
void finishedSignal();
|
||||||
void downloadProgress(qint64, qint64);
|
void downloadProgress(qint64, qint64);
|
||||||
private slots:
|
private slots:
|
||||||
|
|
|
@ -58,7 +58,6 @@ void cfApiSendTransferInfo(const CF_CONNECTION_KEY &connectionKey, const CF_TRAN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CALLBACK cfApiFetchDataCallback(const CF_CALLBACK_INFO *callbackInfo, const CF_CALLBACK_PARAMETERS *callbackParameters)
|
void CALLBACK cfApiFetchDataCallback(const CF_CALLBACK_INFO *callbackInfo, const CF_CALLBACK_PARAMETERS *callbackParameters)
|
||||||
{
|
{
|
||||||
qDebug(lcCfApiWrapper) << "Fetch data callback called. File size:" << callbackInfo->FileSize.QuadPart;
|
qDebug(lcCfApiWrapper) << "Fetch data callback called. File size:" << callbackInfo->FileSize.QuadPart;
|
||||||
|
@ -181,8 +180,27 @@ void CALLBACK cfApiFetchDataCallback(const CF_CALLBACK_INFO *callbackInfo, const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CALLBACK cfApiCancelFetchData(const CF_CALLBACK_INFO *callbackInfo, const CF_CALLBACK_PARAMETERS * /*callbackParameters*/)
|
||||||
|
{
|
||||||
|
const auto path = QString(QString::fromWCharArray(callbackInfo->VolumeDosName) + QString::fromWCharArray(callbackInfo->NormalizedPath));
|
||||||
|
|
||||||
|
qInfo(lcCfApiWrapper) << "Cancel fetch data of" << path;
|
||||||
|
|
||||||
|
auto vfs = reinterpret_cast<OCC::VfsCfApi *>(callbackInfo->CallbackContext);
|
||||||
|
Q_ASSERT(vfs->metaObject()->className() == QByteArrayLiteral("OCC::VfsCfApi"));
|
||||||
|
const auto requestId = QString::number(callbackInfo->TransferKey.QuadPart, 16);
|
||||||
|
|
||||||
|
const auto invokeResult = QMetaObject::invokeMethod(
|
||||||
|
vfs, [=] { vfs->cancelHydration(requestId, path); }, Qt::QueuedConnection);
|
||||||
|
if (!invokeResult) {
|
||||||
|
qCritical(lcCfApiWrapper) << "Failed to cancel hydration for" << path << requestId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
CF_CALLBACK_REGISTRATION cfApiCallbacks[] = {
|
CF_CALLBACK_REGISTRATION cfApiCallbacks[] = {
|
||||||
{ CF_CALLBACK_TYPE_FETCH_DATA, cfApiFetchDataCallback },
|
{ CF_CALLBACK_TYPE_FETCH_DATA, cfApiFetchDataCallback },
|
||||||
|
{ CF_CALLBACK_TYPE_CANCEL_FETCH_DATA, cfApiCancelFetchData },
|
||||||
CF_CALLBACK_REGISTRATION_END
|
CF_CALLBACK_REGISTRATION_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,15 @@ void OCC::HydrationJob::start()
|
||||||
connect(_server, &QLocalServer::newConnection, this, &HydrationJob::onNewConnection);
|
connect(_server, &QLocalServer::newConnection, this, &HydrationJob::onNewConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OCC::HydrationJob::cancel()
|
||||||
|
{
|
||||||
|
if (!_job) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_job->cancel();
|
||||||
|
}
|
||||||
|
|
||||||
void OCC::HydrationJob::emitFinished(Status status)
|
void OCC::HydrationJob::emitFinished(Status status)
|
||||||
{
|
{
|
||||||
_status = status;
|
_status = status;
|
||||||
|
@ -131,6 +140,16 @@ void OCC::HydrationJob::emitFinished(Status status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OCC::HydrationJob::emitCanceled()
|
||||||
|
{
|
||||||
|
connect(_socket, &QLocalSocket::disconnected, this, [=] {
|
||||||
|
_socket->close();
|
||||||
|
});
|
||||||
|
_socket->disconnectFromServer();
|
||||||
|
|
||||||
|
emit canceled(this);
|
||||||
|
}
|
||||||
|
|
||||||
void OCC::HydrationJob::onNewConnection()
|
void OCC::HydrationJob::onNewConnection()
|
||||||
{
|
{
|
||||||
Q_ASSERT(!_socket);
|
Q_ASSERT(!_socket);
|
||||||
|
@ -140,9 +159,16 @@ void OCC::HydrationJob::onNewConnection()
|
||||||
_socket = _server->nextPendingConnection();
|
_socket = _server->nextPendingConnection();
|
||||||
_job = new GETFileJob(_account, _remotePath + _folderPath, _socket, {}, {}, 0, this);
|
_job = new GETFileJob(_account, _remotePath + _folderPath, _socket, {}, {}, 0, this);
|
||||||
connect(_job, &GETFileJob::finishedSignal, this, &HydrationJob::onGetFinished);
|
connect(_job, &GETFileJob::finishedSignal, this, &HydrationJob::onGetFinished);
|
||||||
|
connect(_job, &GETFileJob::canceled, this, &HydrationJob::onGetCanceled);
|
||||||
_job->start();
|
_job->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OCC::HydrationJob::onGetCanceled()
|
||||||
|
{
|
||||||
|
qCInfo(lcHydration) << "GETFileJob canceled" << _requestId << _folderPath << _job->reply()->error();
|
||||||
|
emitCanceled();
|
||||||
|
}
|
||||||
|
|
||||||
void OCC::HydrationJob::onGetFinished()
|
void OCC::HydrationJob::onGetFinished()
|
||||||
{
|
{
|
||||||
qCInfo(lcHydration) << "GETFileJob finished" << _requestId << _folderPath << _job->reply()->error();
|
qCInfo(lcHydration) << "GETFileJob finished" << _requestId << _folderPath << _job->reply()->error();
|
||||||
|
|
|
@ -57,15 +57,19 @@ public:
|
||||||
Status status() const;
|
Status status() const;
|
||||||
|
|
||||||
void start();
|
void start();
|
||||||
|
void cancel();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void finished(HydrationJob *job);
|
void finished(HydrationJob *job);
|
||||||
|
void canceled(HydrationJob *job);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void emitFinished(Status status);
|
void emitFinished(Status status);
|
||||||
|
void emitCanceled();
|
||||||
|
|
||||||
void onNewConnection();
|
void onNewConnection();
|
||||||
void onGetFinished();
|
void onGetFinished();
|
||||||
|
void onGetCanceled();
|
||||||
|
|
||||||
AccountPtr _account;
|
AccountPtr _account;
|
||||||
QString _remotePath;
|
QString _remotePath;
|
||||||
|
|
|
@ -264,6 +264,19 @@ Vfs::AvailabilityResult VfsCfApi::availability(const QString &folderPath)
|
||||||
return AvailabilityError::NoSuchItem;
|
return AvailabilityError::NoSuchItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VfsCfApi::cancelHydration(const QString &requestId, const QString & /*path*/)
|
||||||
|
{
|
||||||
|
// Find matching hydration job for request id
|
||||||
|
const auto hydrationJobsIter = std::find_if(d->hydrationJobs.cbegin(), d->hydrationJobs.cend(), [&](const HydrationJob *job) {
|
||||||
|
return job->requestId() == requestId;
|
||||||
|
});
|
||||||
|
|
||||||
|
// If found, cancel it
|
||||||
|
if (hydrationJobsIter != d->hydrationJobs.cend()) {
|
||||||
|
(*hydrationJobsIter)->cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void VfsCfApi::requestHydration(const QString &requestId, const QString &path)
|
void VfsCfApi::requestHydration(const QString &requestId, const QString &path)
|
||||||
{
|
{
|
||||||
qCInfo(lcCfApi) << "Received request to hydrate" << path << requestId;
|
qCInfo(lcCfApi) << "Received request to hydrate" << path << requestId;
|
||||||
|
@ -331,6 +344,7 @@ void VfsCfApi::scheduleHydrationJob(const QString &requestId, const QString &fol
|
||||||
job->setRequestId(requestId);
|
job->setRequestId(requestId);
|
||||||
job->setFolderPath(folderPath);
|
job->setFolderPath(folderPath);
|
||||||
connect(job, &HydrationJob::finished, this, &VfsCfApi::onHydrationJobFinished);
|
connect(job, &HydrationJob::finished, this, &VfsCfApi::onHydrationJobFinished);
|
||||||
|
connect(job, &HydrationJob::canceled, this, &VfsCfApi::onHydrationJobCanceled);
|
||||||
d->hydrationJobs << job;
|
d->hydrationJobs << job;
|
||||||
job->start();
|
job->start();
|
||||||
emit hydrationRequestReady(requestId);
|
emit hydrationRequestReady(requestId);
|
||||||
|
@ -347,6 +361,22 @@ void VfsCfApi::onHydrationJobFinished(HydrationJob *job)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VfsCfApi::onHydrationJobCanceled(HydrationJob *job)
|
||||||
|
{
|
||||||
|
const auto folderPath = job->localPath();
|
||||||
|
const auto folderRelativePath = job->folderPath();
|
||||||
|
|
||||||
|
// Remove placeholder file because there might be already pumped
|
||||||
|
// some data into it
|
||||||
|
QFile::remove(folderPath + folderRelativePath);
|
||||||
|
|
||||||
|
// Create a new placeholder file
|
||||||
|
SyncJournalFileRecord record;
|
||||||
|
params().journal->getFileRecord(folderRelativePath, &record);
|
||||||
|
const auto item = SyncFileItem::fromSyncJournalFileRecord(record);
|
||||||
|
createPlaceholder(*item);
|
||||||
|
}
|
||||||
|
|
||||||
VfsCfApi::HydratationAndPinStates VfsCfApi::computeRecursiveHydrationAndPinStates(const QString &folderPath, const Optional<PinState> &basePinState)
|
VfsCfApi::HydratationAndPinStates VfsCfApi::computeRecursiveHydrationAndPinStates(const QString &folderPath, const Optional<PinState> &basePinState)
|
||||||
{
|
{
|
||||||
Q_ASSERT(!folderPath.endsWith('/'));
|
Q_ASSERT(!folderPath.endsWith('/'));
|
||||||
|
|
|
@ -53,6 +53,8 @@ public:
|
||||||
Optional<PinState> pinState(const QString &folderPath) override;
|
Optional<PinState> pinState(const QString &folderPath) override;
|
||||||
AvailabilityResult availability(const QString &folderPath) override;
|
AvailabilityResult availability(const QString &folderPath) override;
|
||||||
|
|
||||||
|
void cancelHydration(const QString &requestId, const QString &path);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void requestHydration(const QString &requestId, const QString &path);
|
void requestHydration(const QString &requestId, const QString &path);
|
||||||
void fileStatusChanged(const QString &systemFileName, SyncFileStatus fileStatus) override;
|
void fileStatusChanged(const QString &systemFileName, SyncFileStatus fileStatus) override;
|
||||||
|
@ -68,6 +70,7 @@ protected:
|
||||||
private:
|
private:
|
||||||
void scheduleHydrationJob(const QString &requestId, const QString &folderPath);
|
void scheduleHydrationJob(const QString &requestId, const QString &folderPath);
|
||||||
void onHydrationJobFinished(HydrationJob *job);
|
void onHydrationJobFinished(HydrationJob *job);
|
||||||
|
void onHydrationJobCanceled(HydrationJob *job);
|
||||||
|
|
||||||
struct HasHydratedDehydrated {
|
struct HasHydratedDehydrated {
|
||||||
bool hasHydrated = false;
|
bool hasHydrated = false;
|
||||||
|
|
Loading…
Reference in a new issue