mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-22 13:05:51 +03:00
let cancel sync and finish sync lambda be reusable methods
will enable implementation of other ways to interrupt sync after discovery to get user feedback Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
This commit is contained in:
parent
80793bbfff
commit
ab2002596e
2 changed files with 138 additions and 115 deletions
|
@ -801,102 +801,6 @@ void SyncEngine::slotDiscoveryFinished()
|
||||||
_progressInfo->_status = ProgressInfo::Reconcile;
|
_progressInfo->_status = ProgressInfo::Reconcile;
|
||||||
emit transmissionProgress(*_progressInfo);
|
emit transmissionProgress(*_progressInfo);
|
||||||
|
|
||||||
// qCInfo(lcEngine) << "Permissions of the root folder: " << _csync_ctx->remote.root_perms.toString();
|
|
||||||
auto finish = [this]{
|
|
||||||
auto databaseFingerprint = _journal->dataFingerprint();
|
|
||||||
// If databaseFingerprint is empty, this means that there was no information in the database
|
|
||||||
// (for example, upgrading from a previous version, or first sync, or server not supporting fingerprint)
|
|
||||||
if (!databaseFingerprint.isEmpty() && _discoveryPhase
|
|
||||||
&& _discoveryPhase->_dataFingerprint != databaseFingerprint) {
|
|
||||||
qCInfo(lcEngine) << "data fingerprint changed, assume restore from backup" << databaseFingerprint << _discoveryPhase->_dataFingerprint;
|
|
||||||
restoreOldFiles(_syncItems);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_discoveryPhase->_anotherSyncNeeded && !_discoveryPhase->_filesNeedingScheduledSync.empty()) {
|
|
||||||
slotScheduleFilesDelayedSync();
|
|
||||||
} else if (_discoveryPhase->_anotherSyncNeeded && _anotherSyncNeeded == NoFollowUpSync) {
|
|
||||||
_anotherSyncNeeded = ImmediateFollowUp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_discoveryPhase->_filesUnscheduleSync.empty()) {
|
|
||||||
slotUnscheduleFilesDelayedSync();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_discoveryPhase->_hasDownloadRemovedItems && _discoveryPhase->_hasUploadErrorItems) {
|
|
||||||
for (const auto &item : qAsConst(_syncItems)) {
|
|
||||||
if (item->_instruction == CSYNC_INSTRUCTION_ERROR && item->_direction == SyncFileItem::Up) {
|
|
||||||
item->_instruction = CSYNC_INSTRUCTION_IGNORE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_anotherSyncNeeded = ImmediateFollowUp;
|
|
||||||
}
|
|
||||||
|
|
||||||
Q_ASSERT(std::is_sorted(_syncItems.begin(), _syncItems.end()));
|
|
||||||
|
|
||||||
qCInfo(lcEngine) << "#### Reconcile (aboutToPropagate) #################################################### " << _stopWatch.addLapTime(QStringLiteral("Reconcile (aboutToPropagate)")) << "ms";
|
|
||||||
|
|
||||||
_localDiscoveryPaths.clear();
|
|
||||||
|
|
||||||
// To announce the beginning of the sync
|
|
||||||
emit aboutToPropagate(_syncItems);
|
|
||||||
|
|
||||||
qCInfo(lcEngine) << "#### Reconcile (aboutToPropagate OK) #################################################### "<< _stopWatch.addLapTime(QStringLiteral("Reconcile (aboutToPropagate OK)")) << "ms";
|
|
||||||
|
|
||||||
// it's important to do this before ProgressInfo::start(), to announce start of new sync
|
|
||||||
_progressInfo->_status = ProgressInfo::Propagation;
|
|
||||||
emit transmissionProgress(*_progressInfo);
|
|
||||||
_progressInfo->startEstimateUpdates();
|
|
||||||
|
|
||||||
// post update phase script: allow to tweak stuff by a custom script in debug mode.
|
|
||||||
if (!qEnvironmentVariableIsEmpty("OWNCLOUD_POST_UPDATE_SCRIPT")) {
|
|
||||||
#ifndef NDEBUG
|
|
||||||
const QString script = qEnvironmentVariable("OWNCLOUD_POST_UPDATE_SCRIPT");
|
|
||||||
|
|
||||||
qCDebug(lcEngine) << "Post Update Script: " << script;
|
|
||||||
auto scriptArgs = script.split(QRegularExpression("\\s+"), Qt::SkipEmptyParts);
|
|
||||||
if (scriptArgs.size() > 0) {
|
|
||||||
const auto scriptExecutable = scriptArgs.takeFirst();
|
|
||||||
QProcess::execute(scriptExecutable, scriptArgs);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
qCWarning(lcEngine) << "**** Attention: POST_UPDATE_SCRIPT installed, but not executed because compiled with NDEBUG";
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// do a database commit
|
|
||||||
_journal->commit(QStringLiteral("post treewalk"));
|
|
||||||
|
|
||||||
_propagator = QSharedPointer<OwncloudPropagator>(
|
|
||||||
new OwncloudPropagator(_account, _localPath, _remotePath, _journal, _bulkUploadBlackList));
|
|
||||||
_propagator->setSyncOptions(_syncOptions);
|
|
||||||
connect(_propagator.data(), &OwncloudPropagator::itemCompleted,
|
|
||||||
this, &SyncEngine::slotItemCompleted);
|
|
||||||
connect(_propagator.data(), &OwncloudPropagator::progress,
|
|
||||||
this, &SyncEngine::slotProgress);
|
|
||||||
connect(_propagator.data(), &OwncloudPropagator::finished, this, &SyncEngine::slotPropagationFinished, Qt::QueuedConnection);
|
|
||||||
connect(_propagator.data(), &OwncloudPropagator::seenLockedFile, this, &SyncEngine::seenLockedFile);
|
|
||||||
connect(_propagator.data(), &OwncloudPropagator::touchedFile, this, &SyncEngine::slotAddTouchedFile);
|
|
||||||
connect(_propagator.data(), &OwncloudPropagator::insufficientLocalStorage, this, &SyncEngine::slotInsufficientLocalStorage);
|
|
||||||
connect(_propagator.data(), &OwncloudPropagator::insufficientRemoteStorage, this, &SyncEngine::slotInsufficientRemoteStorage);
|
|
||||||
connect(_propagator.data(), &OwncloudPropagator::newItem, this, &SyncEngine::slotNewItem);
|
|
||||||
|
|
||||||
// apply the network limits to the propagator
|
|
||||||
setNetworkLimits(_uploadLimit, _downloadLimit);
|
|
||||||
|
|
||||||
deleteStaleDownloadInfos(_syncItems);
|
|
||||||
deleteStaleUploadInfos(_syncItems);
|
|
||||||
deleteStaleErrorBlacklistEntries(_syncItems);
|
|
||||||
_journal->commit(QStringLiteral("post stale entry removal"));
|
|
||||||
|
|
||||||
// Emit the started signal only after the propagator has been set up.
|
|
||||||
if (_needsUpdate)
|
|
||||||
Q_EMIT started();
|
|
||||||
|
|
||||||
_propagator->start(std::move(_syncItems));
|
|
||||||
|
|
||||||
qCInfo(lcEngine) << "#### Post-Reconcile end #################################################### " << _stopWatch.addLapTime(QStringLiteral("Post-Reconcile Finished")) << "ms";
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto displayDialog = ConfigFile().promptDeleteFiles() && !_syncOptions.isCmd();
|
const auto displayDialog = ConfigFile().promptDeleteFiles() && !_syncOptions.isCmd();
|
||||||
if (!_hasNoneFiles && _hasRemoveFile && displayDialog) {
|
if (!_hasNoneFiles && _hasRemoveFile && displayDialog) {
|
||||||
qCInfo(lcEngine) << "All the files are going to be changed, asking the user";
|
qCInfo(lcEngine) << "All the files are going to be changed, asking the user";
|
||||||
|
@ -907,27 +811,14 @@ void SyncEngine::slotDiscoveryFinished()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QPointer<QObject> guard = new QObject();
|
promptUserBeforePropagation([this, side](auto &&callback){
|
||||||
QPointer<QObject> self = this;
|
emit aboutToRemoveAllFiles(side >= 0 ? SyncFileItem::Down : SyncFileItem::Up, callback);
|
||||||
auto callback = [this, self, finish, guard](bool cancel) -> void {
|
});
|
||||||
// use a guard to ensure its only called once...
|
|
||||||
// qpointer to self to ensure we still exist
|
|
||||||
if (!guard || !self) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
guard->deleteLater();
|
|
||||||
if (cancel) {
|
|
||||||
qCInfo(lcEngine) << "User aborted sync";
|
|
||||||
finalize(false);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
emit aboutToRemoveAllFiles(side >= 0 ? SyncFileItem::Down : SyncFileItem::Up, callback);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
finish();
|
|
||||||
|
|
||||||
|
finishSync();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SyncEngine::slotCleanPollsJobAborted(const QString &error, const ErrorCategory errorCategory)
|
void SyncEngine::slotCleanPollsJobAborted(const QString &error, const ErrorCategory errorCategory)
|
||||||
|
@ -1104,6 +995,131 @@ void SyncEngine::restoreOldFiles(SyncFileItemVector &syncItems)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SyncEngine::cancelSyncOrContinue(bool cancel)
|
||||||
|
{
|
||||||
|
if (cancel) {
|
||||||
|
qCInfo(lcEngine) << "User aborted sync";
|
||||||
|
finalize(false);
|
||||||
|
} else {
|
||||||
|
finishSync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SyncEngine::finishSync()
|
||||||
|
{
|
||||||
|
auto databaseFingerprint = _journal->dataFingerprint();
|
||||||
|
// If databaseFingerprint is empty, this means that there was no information in the database
|
||||||
|
// (for example, upgrading from a previous version, or first sync, or server not supporting fingerprint)
|
||||||
|
if (!databaseFingerprint.isEmpty() && _discoveryPhase
|
||||||
|
&& _discoveryPhase->_dataFingerprint != databaseFingerprint) {
|
||||||
|
qCInfo(lcEngine) << "data fingerprint changed, assume restore from backup" << databaseFingerprint << _discoveryPhase->_dataFingerprint;
|
||||||
|
restoreOldFiles(_syncItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_discoveryPhase && _discoveryPhase->_anotherSyncNeeded && !_discoveryPhase->_filesNeedingScheduledSync.empty()) {
|
||||||
|
slotScheduleFilesDelayedSync();
|
||||||
|
} else if (_discoveryPhase && _discoveryPhase->_anotherSyncNeeded && _anotherSyncNeeded == NoFollowUpSync) {
|
||||||
|
_anotherSyncNeeded = ImmediateFollowUp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_discoveryPhase && !_discoveryPhase->_filesUnscheduleSync.empty()) {
|
||||||
|
slotUnscheduleFilesDelayedSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_discoveryPhase && _discoveryPhase->_hasDownloadRemovedItems && _discoveryPhase->_hasUploadErrorItems) {
|
||||||
|
for (const auto &item : qAsConst(_syncItems)) {
|
||||||
|
if (item->_instruction == CSYNC_INSTRUCTION_ERROR && item->_direction == SyncFileItem::Up) {
|
||||||
|
// item->_instruction = CSYNC_INSTRUCTION_IGNORE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_anotherSyncNeeded = ImmediateFollowUp;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_ASSERT(std::is_sorted(_syncItems.begin(), _syncItems.end()));
|
||||||
|
|
||||||
|
qCInfo(lcEngine) << "#### Reconcile (aboutToPropagate) #################################################### " << _stopWatch.addLapTime(QStringLiteral("Reconcile (aboutToPropagate)")) << "ms";
|
||||||
|
|
||||||
|
_localDiscoveryPaths.clear();
|
||||||
|
|
||||||
|
// To announce the beginning of the sync
|
||||||
|
emit aboutToPropagate(_syncItems);
|
||||||
|
|
||||||
|
qCInfo(lcEngine) << "#### Reconcile (aboutToPropagate OK) #################################################### "<< _stopWatch.addLapTime(QStringLiteral("Reconcile (aboutToPropagate OK)")) << "ms";
|
||||||
|
|
||||||
|
// it's important to do this before ProgressInfo::start(), to announce start of new sync
|
||||||
|
_progressInfo->_status = ProgressInfo::Propagation;
|
||||||
|
emit transmissionProgress(*_progressInfo);
|
||||||
|
_progressInfo->startEstimateUpdates();
|
||||||
|
|
||||||
|
// post update phase script: allow to tweak stuff by a custom script in debug mode.
|
||||||
|
if (!qEnvironmentVariableIsEmpty("OWNCLOUD_POST_UPDATE_SCRIPT")) {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
const QString script = qEnvironmentVariable("OWNCLOUD_POST_UPDATE_SCRIPT");
|
||||||
|
|
||||||
|
qCDebug(lcEngine) << "Post Update Script: " << script;
|
||||||
|
auto scriptArgs = script.split(QRegularExpression("\\s+"), Qt::SkipEmptyParts);
|
||||||
|
if (scriptArgs.size() > 0) {
|
||||||
|
const auto scriptExecutable = scriptArgs.takeFirst();
|
||||||
|
QProcess::execute(scriptExecutable, scriptArgs);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
qCWarning(lcEngine) << "**** Attention: POST_UPDATE_SCRIPT installed, but not executed because compiled with NDEBUG";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// do a database commit
|
||||||
|
_journal->commit(QStringLiteral("post treewalk"));
|
||||||
|
|
||||||
|
_propagator = QSharedPointer<OwncloudPropagator>(
|
||||||
|
new OwncloudPropagator(_account, _localPath, _remotePath, _journal, _bulkUploadBlackList));
|
||||||
|
_propagator->setSyncOptions(_syncOptions);
|
||||||
|
connect(_propagator.data(), &OwncloudPropagator::itemCompleted,
|
||||||
|
this, &SyncEngine::slotItemCompleted);
|
||||||
|
connect(_propagator.data(), &OwncloudPropagator::progress,
|
||||||
|
this, &SyncEngine::slotProgress);
|
||||||
|
connect(_propagator.data(), &OwncloudPropagator::finished, this, &SyncEngine::slotPropagationFinished, Qt::QueuedConnection);
|
||||||
|
connect(_propagator.data(), &OwncloudPropagator::seenLockedFile, this, &SyncEngine::seenLockedFile);
|
||||||
|
connect(_propagator.data(), &OwncloudPropagator::touchedFile, this, &SyncEngine::slotAddTouchedFile);
|
||||||
|
connect(_propagator.data(), &OwncloudPropagator::insufficientLocalStorage, this, &SyncEngine::slotInsufficientLocalStorage);
|
||||||
|
connect(_propagator.data(), &OwncloudPropagator::insufficientRemoteStorage, this, &SyncEngine::slotInsufficientRemoteStorage);
|
||||||
|
connect(_propagator.data(), &OwncloudPropagator::newItem, this, &SyncEngine::slotNewItem);
|
||||||
|
|
||||||
|
// apply the network limits to the propagator
|
||||||
|
setNetworkLimits(_uploadLimit, _downloadLimit);
|
||||||
|
|
||||||
|
deleteStaleDownloadInfos(_syncItems);
|
||||||
|
deleteStaleUploadInfos(_syncItems);
|
||||||
|
deleteStaleErrorBlacklistEntries(_syncItems);
|
||||||
|
_journal->commit(QStringLiteral("post stale entry removal"));
|
||||||
|
|
||||||
|
// Emit the started signal only after the propagator has been set up.
|
||||||
|
if (_needsUpdate)
|
||||||
|
Q_EMIT started();
|
||||||
|
|
||||||
|
_propagator->start(std::move(_syncItems));
|
||||||
|
|
||||||
|
qCInfo(lcEngine) << "#### Post-Reconcile end #################################################### " << _stopWatch.addLapTime(QStringLiteral("Post-Reconcile Finished")) << "ms";
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void SyncEngine::promptUserBeforePropagation(T &&lambda)
|
||||||
|
{
|
||||||
|
QPointer<QObject> guard = new QObject();
|
||||||
|
QPointer<QObject> self = this;
|
||||||
|
auto callback = [this, self, guard](bool cancel) -> void {
|
||||||
|
// use a guard to ensure its only called once...
|
||||||
|
// qpointer to self to ensure we still exist
|
||||||
|
if (!guard || !self) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
guard->deleteLater();
|
||||||
|
|
||||||
|
cancelSyncOrContinue(cancel);
|
||||||
|
};
|
||||||
|
|
||||||
|
lambda(callback);
|
||||||
|
}
|
||||||
|
|
||||||
void SyncEngine::slotAddTouchedFile(const QString &fn)
|
void SyncEngine::slotAddTouchedFile(const QString &fn)
|
||||||
{
|
{
|
||||||
QElapsedTimer now;
|
QElapsedTimer now;
|
||||||
|
|
|
@ -361,6 +361,13 @@ private:
|
||||||
*/
|
*/
|
||||||
void restoreOldFiles(SyncFileItemVector &syncItems);
|
void restoreOldFiles(SyncFileItemVector &syncItems);
|
||||||
|
|
||||||
|
void cancelSyncOrContinue(bool cancel);
|
||||||
|
|
||||||
|
void finishSync();
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void promptUserBeforePropagation(T &&lambda);
|
||||||
|
|
||||||
// true if there is at least one file which was not changed on the server
|
// true if there is at least one file which was not changed on the server
|
||||||
bool _hasNoneFiles = false;
|
bool _hasNoneFiles = false;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue