зеркало из https://github.com/nextcloud/desktop.git
SyncEngine: Introduce overall errors that are not tied to a file #5746
For now we use them for: * csync errors: This allows them to appear in the sync issues tab * insufficient local disk space, as a summary of individual file errors Insufficient remote space will use them too, as might other issues that are bigger than a single sync item.
This commit is contained in:
Родитель
d34dbbdb0b
Коммит
5ca743dd25
|
@ -106,6 +106,7 @@ Folder::Folder(const FolderDefinition &definition,
|
||||||
connect(_engine.data(), SIGNAL(seenLockedFile(QString)), FolderMan::instance(), SLOT(slotSyncOnceFileUnlocks(QString)));
|
connect(_engine.data(), SIGNAL(seenLockedFile(QString)), FolderMan::instance(), SLOT(slotSyncOnceFileUnlocks(QString)));
|
||||||
connect(_engine.data(), SIGNAL(aboutToPropagate(SyncFileItemVector &)),
|
connect(_engine.data(), SIGNAL(aboutToPropagate(SyncFileItemVector &)),
|
||||||
SLOT(slotLogPropagationStart()));
|
SLOT(slotLogPropagationStart()));
|
||||||
|
connect(_engine.data(), SIGNAL(summaryError(QString)), SLOT(slotSyncError(QString)));
|
||||||
|
|
||||||
_scheduleSelfTimer.setSingleShot(true);
|
_scheduleSelfTimer.setSingleShot(true);
|
||||||
_scheduleSelfTimer.setInterval(SyncEngine::minimumFileAgeForUpload);
|
_scheduleSelfTimer.setInterval(SyncEngine::minimumFileAgeForUpload);
|
||||||
|
@ -721,10 +722,10 @@ void Folder::setDirtyNetworkLimits()
|
||||||
_engine->setNetworkLimits(uploadLimit, downloadLimit);
|
_engine->setNetworkLimits(uploadLimit, downloadLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Folder::slotSyncError(const QString &message)
|
||||||
void Folder::slotSyncError(const QString &err)
|
|
||||||
{
|
{
|
||||||
_syncResult.appendErrorString(err);
|
_syncResult.appendErrorString(message);
|
||||||
|
emit ProgressDispatcher::instance()->syncError(alias(), message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Folder::slotSyncStarted()
|
void Folder::slotSyncStarted()
|
||||||
|
|
|
@ -278,11 +278,16 @@ public slots:
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void slotSyncStarted();
|
void slotSyncStarted();
|
||||||
void slotSyncError(const QString &);
|
|
||||||
void slotCsyncUnavailable();
|
|
||||||
void slotSyncFinished(bool);
|
void slotSyncFinished(bool);
|
||||||
|
|
||||||
|
/** Adds a error message that's not tied to a specific item.
|
||||||
|
*/
|
||||||
|
void slotSyncError(const QString &message);
|
||||||
|
|
||||||
|
void slotCsyncUnavailable();
|
||||||
|
|
||||||
void slotFolderDiscovered(bool local, QString folderName);
|
void slotFolderDiscovered(bool local, QString folderName);
|
||||||
|
|
||||||
void slotTransmissionProgress(const ProgressInfo &pi);
|
void slotTransmissionProgress(const ProgressInfo &pi);
|
||||||
void slotItemCompleted(const SyncFileItemPtr &);
|
void slotItemCompleted(const SyncFileItemPtr &);
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,8 @@ IssuesWidget::IssuesWidget(QWidget *parent)
|
||||||
this, SLOT(slotProgressInfo(QString, ProgressInfo)));
|
this, SLOT(slotProgressInfo(QString, ProgressInfo)));
|
||||||
connect(ProgressDispatcher::instance(), SIGNAL(itemCompleted(QString, SyncFileItemPtr)),
|
connect(ProgressDispatcher::instance(), SIGNAL(itemCompleted(QString, SyncFileItemPtr)),
|
||||||
this, SLOT(slotItemCompleted(QString, SyncFileItemPtr)));
|
this, SLOT(slotItemCompleted(QString, SyncFileItemPtr)));
|
||||||
|
connect(ProgressDispatcher::instance(), SIGNAL(syncError(QString, QString)),
|
||||||
|
this, SLOT(addLine(QString, QString)));
|
||||||
|
|
||||||
connect(_ui->_treeWidget, SIGNAL(itemActivated(QTreeWidgetItem *, int)), SLOT(slotOpenFile(QTreeWidgetItem *, int)));
|
connect(_ui->_treeWidget, SIGNAL(itemActivated(QTreeWidgetItem *, int)), SLOT(slotOpenFile(QTreeWidgetItem *, int)));
|
||||||
connect(_ui->copyIssuesButton, SIGNAL(clicked()), SIGNAL(copyToClipboard()));
|
connect(_ui->copyIssuesButton, SIGNAL(clicked()), SIGNAL(copyToClipboard()));
|
||||||
|
@ -132,6 +134,15 @@ void IssuesWidget::cleanItems(const QString &folder)
|
||||||
emit(issueCountUpdated(_ui->_treeWidget->topLevelItemCount()));
|
emit(issueCountUpdated(_ui->_treeWidget->topLevelItemCount()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IssuesWidget::addItem(QTreeWidgetItem *item)
|
||||||
|
{
|
||||||
|
if (!item)
|
||||||
|
return;
|
||||||
|
_ui->_treeWidget->insertTopLevelItem(0, item);
|
||||||
|
item->setHidden(!shouldBeVisible(item, currentAccountFilter(), currentFolderFilter()));
|
||||||
|
emit issueCountUpdated(_ui->_treeWidget->topLevelItemCount());
|
||||||
|
}
|
||||||
|
|
||||||
void IssuesWidget::slotOpenFile(QTreeWidgetItem *item, int)
|
void IssuesWidget::slotOpenFile(QTreeWidgetItem *item, int)
|
||||||
{
|
{
|
||||||
QString folderName = item->data(2, Qt::UserRole).toString();
|
QString folderName = item->data(2, Qt::UserRole).toString();
|
||||||
|
@ -164,10 +175,7 @@ void IssuesWidget::slotItemCompleted(const QString &folder, const SyncFileItemPt
|
||||||
QTreeWidgetItem *line = ProtocolWidget::createCompletedTreewidgetItem(folder, *item);
|
QTreeWidgetItem *line = ProtocolWidget::createCompletedTreewidgetItem(folder, *item);
|
||||||
if (!line)
|
if (!line)
|
||||||
return;
|
return;
|
||||||
|
addItem(line);
|
||||||
_ui->_treeWidget->insertTopLevelItem(0, line);
|
|
||||||
line->setHidden(!shouldBeVisible(line, currentAccountFilter(), currentFolderFilter()));
|
|
||||||
emit issueCountUpdated(_ui->_treeWidget->topLevelItemCount());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IssuesWidget::slotRefreshIssues()
|
void IssuesWidget::slotRefreshIssues()
|
||||||
|
@ -328,4 +336,41 @@ void IssuesWidget::showFolderErrors(const QString &folderAlias)
|
||||||
_ui->showIgnores->setChecked(false);
|
_ui->showIgnores->setChecked(false);
|
||||||
_ui->showWarnings->setChecked(false);
|
_ui->showWarnings->setChecked(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IssuesWidget::addLine(const QString &folderAlias, const QString &message)
|
||||||
|
{
|
||||||
|
SyncFileItem::Status status = SyncFileItem::NormalError;
|
||||||
|
|
||||||
|
auto folder = FolderMan::instance()->folder(folderAlias);
|
||||||
|
if (!folder)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QStringList columns;
|
||||||
|
QDateTime timestamp = QDateTime::currentDateTime();
|
||||||
|
const QString timeStr = ProtocolWidget::timeString(timestamp);
|
||||||
|
const QString longTimeStr = ProtocolWidget::timeString(timestamp, QLocale::LongFormat);
|
||||||
|
|
||||||
|
columns << timeStr;
|
||||||
|
columns << tr("<global error>");
|
||||||
|
columns << folder->shortGuiLocalPath();
|
||||||
|
columns << message;
|
||||||
|
|
||||||
|
QIcon icon;
|
||||||
|
if (status == SyncFileItem::NormalError
|
||||||
|
|| status == SyncFileItem::FatalError) {
|
||||||
|
icon = Theme::instance()->syncStateIcon(SyncResult::Error);
|
||||||
|
} else if (Progress::isWarningKind(status)) {
|
||||||
|
icon = Theme::instance()->syncStateIcon(SyncResult::Problem);
|
||||||
|
}
|
||||||
|
|
||||||
|
QTreeWidgetItem *twitem = new QTreeWidgetItem(columns);
|
||||||
|
twitem->setData(0, Qt::SizeHintRole, QSize(0, ActivityItemDelegate::rowHeight()));
|
||||||
|
twitem->setIcon(0, icon);
|
||||||
|
twitem->setToolTip(0, longTimeStr);
|
||||||
|
twitem->setToolTip(3, message);
|
||||||
|
twitem->setData(0, Qt::UserRole, status);
|
||||||
|
twitem->setData(2, Qt::UserRole, folderAlias);
|
||||||
|
|
||||||
|
addItem(twitem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,7 @@ public:
|
||||||
void showFolderErrors(const QString &folderAlias);
|
void showFolderErrors(const QString &folderAlias);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
void addLine(const QString &folderAlias, const QString &message);
|
||||||
void slotProgressInfo(const QString &folder, const ProgressInfo &progress);
|
void slotProgressInfo(const QString &folder, const ProgressInfo &progress);
|
||||||
void slotItemCompleted(const QString &folder, const SyncFileItemPtr &item);
|
void slotItemCompleted(const QString &folder, const SyncFileItemPtr &item);
|
||||||
void slotOpenFile(QTreeWidgetItem *item, int);
|
void slotOpenFile(QTreeWidgetItem *item, int);
|
||||||
|
@ -75,6 +76,7 @@ private:
|
||||||
bool shouldBeVisible(QTreeWidgetItem *item, AccountState *filterAccount,
|
bool shouldBeVisible(QTreeWidgetItem *item, AccountState *filterAccount,
|
||||||
const QString &filterFolderAlias) const;
|
const QString &filterFolderAlias) const;
|
||||||
void cleanItems(const QString &folder);
|
void cleanItems(const QString &folder);
|
||||||
|
void addItem(QTreeWidgetItem *item);
|
||||||
|
|
||||||
Ui::IssuesWidget *_ui;
|
Ui::IssuesWidget *_ui;
|
||||||
};
|
};
|
||||||
|
|
|
@ -238,6 +238,7 @@ void PropagateItemJob::done(SyncFileItem::Status statusArg, const QString &error
|
||||||
_item->_status = SyncFileItem::SoftError;
|
_item->_status = SyncFileItem::SoftError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Blacklist handling
|
||||||
switch (_item->_status) {
|
switch (_item->_status) {
|
||||||
case SyncFileItem::SoftError:
|
case SyncFileItem::SoftError:
|
||||||
case SyncFileItem::FatalError:
|
case SyncFileItem::FatalError:
|
||||||
|
|
|
@ -417,7 +417,6 @@ public:
|
||||||
*/
|
*/
|
||||||
DiskSpaceResult diskSpaceCheck() const;
|
DiskSpaceResult diskSpaceCheck() const;
|
||||||
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
/** Emit the finished signal and make sure it is only emitted once */
|
/** Emit the finished signal and make sure it is only emitted once */
|
||||||
|
@ -445,6 +444,8 @@ signals:
|
||||||
*/
|
*/
|
||||||
void touchedFile(const QString &fileName);
|
void touchedFile(const QString &fileName);
|
||||||
|
|
||||||
|
void insufficientLocalStorage();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AccountPtr _account;
|
AccountPtr _account;
|
||||||
QScopedPointer<PropagateDirectory> _rootJob;
|
QScopedPointer<PropagateDirectory> _rootJob;
|
||||||
|
|
|
@ -249,6 +249,11 @@ signals:
|
||||||
*/
|
*/
|
||||||
void itemCompleted(const QString &folder, const SyncFileItemPtr &item);
|
void itemCompleted(const QString &folder, const SyncFileItemPtr &item);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A new folder-wide sync error was seen.
|
||||||
|
*/
|
||||||
|
void syncError(const QString &folder, const QString &message);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setProgressInfo(const QString &folder, const ProgressInfo &progress);
|
void setProgressInfo(const QString &folder, const ProgressInfo &progress);
|
||||||
|
|
||||||
|
|
|
@ -427,9 +427,12 @@ void PropagateDownloadFile::startDownload()
|
||||||
const auto diskSpaceResult = propagator()->diskSpaceCheck();
|
const auto diskSpaceResult = propagator()->diskSpaceCheck();
|
||||||
if (diskSpaceResult != OwncloudPropagator::DiskSpaceOk) {
|
if (diskSpaceResult != OwncloudPropagator::DiskSpaceOk) {
|
||||||
if (diskSpaceResult == OwncloudPropagator::DiskSpaceFailure) {
|
if (diskSpaceResult == OwncloudPropagator::DiskSpaceFailure) {
|
||||||
_item->_errorMayBeBlacklisted = true;
|
// Using BlacklistedError here will make the error not pop up in the account
|
||||||
done(SyncFileItem::NormalError,
|
// tab: instead we'll generate a general "disk space low" message and show
|
||||||
tr("The download would reduce free disk space below %1").arg(Utility::octetsToString(freeSpaceLimit())));
|
// these detail errors only in the error view.
|
||||||
|
done(SyncFileItem::BlacklistedError,
|
||||||
|
tr("The download would reduce free local disk space below the limit"));
|
||||||
|
emit propagator()->insufficientLocalStorage();
|
||||||
} else if (diskSpaceResult == OwncloudPropagator::DiskSpaceCritical) {
|
} else if (diskSpaceResult == OwncloudPropagator::DiskSpaceCritical) {
|
||||||
done(SyncFileItem::FatalError,
|
done(SyncFileItem::FatalError,
|
||||||
tr("Free space on disk is less than %1").arg(Utility::octetsToString(criticalFreeSpaceLimit())));
|
tr("Free space on disk is less than %1").arg(Utility::octetsToString(criticalFreeSpaceLimit())));
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "csync_private.h"
|
#include "csync_private.h"
|
||||||
#include "filesystem.h"
|
#include "filesystem.h"
|
||||||
#include "propagateremotedelete.h"
|
#include "propagateremotedelete.h"
|
||||||
|
#include "propagatedownload.h"
|
||||||
#include "asserts.h"
|
#include "asserts.h"
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
|
@ -1025,6 +1026,7 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
||||||
connect(_propagator.data(), SIGNAL(finished(bool)), this, SLOT(slotFinished(bool)), Qt::QueuedConnection);
|
connect(_propagator.data(), SIGNAL(finished(bool)), this, SLOT(slotFinished(bool)), Qt::QueuedConnection);
|
||||||
connect(_propagator.data(), SIGNAL(seenLockedFile(QString)), SIGNAL(seenLockedFile(QString)));
|
connect(_propagator.data(), SIGNAL(seenLockedFile(QString)), SIGNAL(seenLockedFile(QString)));
|
||||||
connect(_propagator.data(), SIGNAL(touchedFile(QString)), SLOT(slotAddTouchedFile(QString)));
|
connect(_propagator.data(), SIGNAL(touchedFile(QString)), SLOT(slotAddTouchedFile(QString)));
|
||||||
|
connect(_propagator.data(), SIGNAL(insufficientLocalStorage()), SLOT(slotInsufficientLocalStorage()));
|
||||||
|
|
||||||
// apply the network limits to the propagator
|
// apply the network limits to the propagator
|
||||||
setNetworkLimits(_uploadLimit, _downloadLimit);
|
setNetworkLimits(_uploadLimit, _downloadLimit);
|
||||||
|
@ -1135,6 +1137,7 @@ void SyncEngine::finalize(bool success)
|
||||||
_seenFiles.clear();
|
_seenFiles.clear();
|
||||||
_temporarilyUnavailablePaths.clear();
|
_temporarilyUnavailablePaths.clear();
|
||||||
_renamedFolders.clear();
|
_renamedFolders.clear();
|
||||||
|
_uniqueErrors.clear();
|
||||||
|
|
||||||
_clearTouchedFilesTimer.start();
|
_clearTouchedFilesTimer.start();
|
||||||
}
|
}
|
||||||
|
@ -1523,4 +1526,21 @@ void SyncEngine::abort()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SyncEngine::slotSummaryError(const QString &message)
|
||||||
|
{
|
||||||
|
if (_uniqueErrors.contains(message))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_uniqueErrors.insert(message);
|
||||||
|
emit summaryError(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SyncEngine::slotInsufficientLocalStorage()
|
||||||
|
{
|
||||||
|
slotSummaryError(
|
||||||
|
tr("Disk space is low: Downloads that would reduce free space "
|
||||||
|
"below %1 were skipped.")
|
||||||
|
.arg(Utility::octetsToString(freeSpaceLimit())));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace OCC
|
} // namespace OCC
|
||||||
|
|
|
@ -121,6 +121,9 @@ signals:
|
||||||
|
|
||||||
void transmissionProgress(const ProgressInfo &progress);
|
void transmissionProgress(const ProgressInfo &progress);
|
||||||
|
|
||||||
|
/// We've produced a new summary error.
|
||||||
|
void summaryError(const QString &message);
|
||||||
|
|
||||||
void finished(bool success);
|
void finished(bool success);
|
||||||
void started();
|
void started();
|
||||||
|
|
||||||
|
@ -160,6 +163,11 @@ private slots:
|
||||||
/** Wipes the _touchedFiles hash */
|
/** Wipes the _touchedFiles hash */
|
||||||
void slotClearTouchedFiles();
|
void slotClearTouchedFiles();
|
||||||
|
|
||||||
|
/** Emit a summary error, unless it was seen before */
|
||||||
|
void slotSummaryError(const QString &message);
|
||||||
|
|
||||||
|
void slotInsufficientLocalStorage();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void handleSyncError(CSYNC *ctx, const char *state);
|
void handleSyncError(CSYNC *ctx, const char *state);
|
||||||
|
|
||||||
|
@ -267,6 +275,9 @@ private:
|
||||||
|
|
||||||
/** For clearing the _touchedFiles variable after sync finished */
|
/** For clearing the _touchedFiles variable after sync finished */
|
||||||
QTimer _clearTouchedFilesTimer;
|
QTimer _clearTouchedFilesTimer;
|
||||||
|
|
||||||
|
/** List of unique errors that occurred in a sync run. */
|
||||||
|
QSet<QString> _uniqueErrors;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче