Skip to content

Commit

Permalink
Pause sync when on a metered Internet connection
Browse files Browse the repository at this point in the history
Add an advanced configuration setting to pause synchronization when a
metered internet connection is detected.

Fixes: #4808
  • Loading branch information
erikjv committed Oct 30, 2023
1 parent c1f138c commit 614caef
Show file tree
Hide file tree
Showing 11 changed files with 115 additions and 3 deletions.
3 changes: 3 additions & 0 deletions src/gui/accountsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,9 @@ void AccountSettings::slotAccountStateChanged()
case AccountState::Disconnected:
showConnectionLabel(tr("Disconnected from: %1.").arg(server));
break;
case AccountState::PausedDueToMetered:
showConnectionLabel(tr("Sync to %1 is paused due to metered internet connection.").arg(server));
break;
}

// Disabling expansion of folders might require hiding the selective
Expand Down
12 changes: 12 additions & 0 deletions src/gui/accountstate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,18 @@ AccountState::AccountState(AccountPtr account)
break;
}
});

connect(qNetInfo, &QNetworkInformation::isMeteredChanged, this, [this](bool isMetered) {
if (ConfigFile().pauseSyncWhenMetered()) {
if (state() == State::Connected && isMetered) {
qCInfo(lcAccountState) << "Network switched to a metered connection, setting account state to PausedDueToMetered";
setState(State::PausedDueToMetered);
} else if (state() == State::PausedDueToMetered && !isMetered) {
qCInfo(lcAccountState) << "Network switched to a NON-metered connection, setting account state to Connected";
setState(State::Connected);
}
}
});
}
#endif
// as a fallback and to recover after server issues we also poll
Expand Down
5 changes: 5 additions & 0 deletions src/gui/accountstate.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ class AccountState : public QObject
/// We are currently asking the user for credentials
AskingCredentials,

/// We are on a metered internet connection, and the user preference
/// is to pause syncing in this case. This state is entered from and
/// left to a `Connected` state.
PausedDueToMetered,

Connecting
};
Q_ENUM(State)
Expand Down
5 changes: 4 additions & 1 deletion src/gui/folder.h
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,9 @@ class Folder : public QObject
{
return *_engine;
}

void abort(const QString &reason);

Vfs &vfs()
{
OC_ENFORCE(_vfs);
Expand Down Expand Up @@ -363,7 +366,7 @@ public slots:
/**
* terminate the current sync run
*/
void slotTerminateSync();
void slotTerminateSync(const QString &reason);

// connected to the corresponding signals in the SyncEngine
void slotAboutToRemoveAllFiles(SyncFileItem::Direction);
Expand Down
24 changes: 24 additions & 0 deletions src/gui/networksettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "theme.h"

#include <QList>
#include <QNetworkInformation>
#include <QNetworkProxy>
#include <QString>
#include <QtGui/QtEvents>
Expand Down Expand Up @@ -69,6 +70,7 @@ NetworkSettings::NetworkSettings(QWidget *parent)

loadProxySettings();
loadBWLimitSettings();
loadMeteredSettings();

// proxy
connect(_ui->typeComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &NetworkSettings::saveProxySettings);
Expand All @@ -92,6 +94,8 @@ NetworkSettings::NetworkSettings(QWidget *parent)
connect(_ui->hostLineEdit, &QLineEdit::textChanged, this, &NetworkSettings::checkEmptyProxyHost);
checkEmptyProxyHost();
checkAccountLocalhost();

connect(_ui->pauseSyncWhenMeteredCheckbox, &QAbstractButton::clicked, this, &NetworkSettings::saveMeteredSettings);
}

NetworkSettings::~NetworkSettings()
Expand Down Expand Up @@ -177,6 +181,19 @@ void NetworkSettings::loadBWLimitSettings()
_ui->uploadSpinBox->setValue(cfgFile.uploadLimit());
}

void NetworkSettings::loadMeteredSettings()
{
if (QNetworkInformation *qNetInfo = QNetworkInformation::instance()) {
if (qNetInfo->supports(QNetworkInformation::Feature::Metered)) {
_ui->pauseSyncWhenMeteredCheckbox->setChecked(ConfigFile().pauseSyncWhenMetered());
return;
}
}

_ui->pauseSyncWhenMeteredCheckbox->setEnabled(false);
_ui->pauseSyncWhenMeteredCheckbox->setToolTip(tr("Querying metered connection status is not supported on this platform"));
}

void NetworkSettings::saveProxySettings()
{
ConfigFile cfgFile;
Expand Down Expand Up @@ -231,6 +248,13 @@ void NetworkSettings::saveBWLimitSettings()
FolderMan::instance()->setDirtyNetworkLimits();
}

void NetworkSettings::saveMeteredSettings()
{
bool pauseSyncWhenMetered = _ui->pauseSyncWhenMeteredCheckbox->isChecked();
ConfigFile().setPauseSyncWhenMetered(pauseSyncWhenMetered);
FolderMan::instance()->scheduler()->setPauseSyncWhenMetered(pauseSyncWhenMetered);
}

void NetworkSettings::checkEmptyProxyHost()
{
if (_ui->hostLineEdit->isEnabled() && _ui->hostLineEdit->text().isEmpty()) {
Expand Down
2 changes: 2 additions & 0 deletions src/gui/networksettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class NetworkSettings : public QWidget
private slots:
void saveProxySettings();
void saveBWLimitSettings();
void saveMeteredSettings();

/// Red marking of host field if empty and enabled
void checkEmptyProxyHost();
Expand All @@ -53,6 +54,7 @@ private slots:
private:
void loadProxySettings();
void loadBWLimitSettings();
void loadMeteredSettings();
CredentialManager *_credentialManager;


Expand Down
7 changes: 7 additions & 0 deletions src/gui/networksettings.ui
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,13 @@
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="pauseSyncWhenMeteredCheckbox">
<property name="text">
<string>Pause synchronization when the Internet connection is metered</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
Expand Down
38 changes: 36 additions & 2 deletions src/gui/scheduling/syncscheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#include "libsync/configfile.h"
#include "libsync/syncengine.h"

#include <QNetworkInformation>

using namespace std::chrono_literals;

using namespace OCC;
Expand Down Expand Up @@ -98,6 +100,7 @@ class FolderPriorityQueue

SyncScheduler::SyncScheduler(FolderMan *parent)
: QObject(parent)
, _pauseSyncWhenMetered(ConfigFile().pauseSyncWhenMetered())
, _queue(new FolderPriorityQueue)
{
new ETagWatcher(parent, this);
Expand Down Expand Up @@ -134,15 +137,38 @@ void SyncScheduler::enqueueFolder(Folder *folder, Priority priority)
}
}

void SyncScheduler::startNext()
bool SyncScheduler::canRun() const
{
if (!_running) {
qCInfo(lcSyncScheduler) << "Scheduler is paused, next sync is not started";
return;
return false;
}

if (_pauseSyncWhenMetered && isMetered()) {
qCInfo(lcSyncScheduler) << "Scheduler is paused due to metered internet connection, next sync is not started";
return false;
}

if (!_currentSync.isNull()) {
qCInfo(lcSyncScheduler) << "Another sync is already running, waiting for that to finish before starting a new sync";
return false;
}

return true;
}

bool SyncScheduler::isMetered() const
{
if (auto *qNetInfo = QNetworkInformation::instance()) {
return qNetInfo->isMetered();
}

return false;
}

void SyncScheduler::startNext()
{
if (!canRun()) {
return;
}

Expand Down Expand Up @@ -205,3 +231,11 @@ bool SyncScheduler::hasCurrentRunningSyncRunning() const
{
return _currentSync;
}

void SyncScheduler::setPauseSyncWhenMetered(bool pauseSyncWhenMetered)
{
_pauseSyncWhenMetered = pauseSyncWhenMetered;
if (!pauseSyncWhenMetered) {
startNext();
}
}
5 changes: 5 additions & 0 deletions src/gui/scheduling/syncscheduler.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,16 @@ class SyncScheduler : public QObject

bool hasCurrentRunningSyncRunning() const;

void setPauseSyncWhenMetered(bool pauseSyncWhenMetered);


private:
void startNext();
bool canRun() const;
bool isMetered() const;

bool _running = false;
bool _pauseSyncWhenMetered;
QPointer<Folder> _currentSync;
FolderPriorityQueue *_queue;
};
Expand Down
14 changes: 14 additions & 0 deletions src/libsync/configfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ const QString downloadLimitC() { return QStringLiteral("BWLimit/downloadLimit");
const QString newBigFolderSizeLimitC() { return QStringLiteral("newBigFolderSizeLimit"); }
const QString useNewBigFolderSizeLimitC() { return QStringLiteral("useNewBigFolderSizeLimit"); }
const QString confirmExternalStorageC() { return QStringLiteral("confirmExternalStorage"); }
const QString pauseSyncWhenMeteredC()
{
return QStringLiteral("pauseWhenMetered");
}
const QString moveToTrashC() { return QStringLiteral("moveToTrash"); }

const QString issuesWidgetFilterC()
Expand Down Expand Up @@ -719,6 +723,16 @@ void ConfigFile::setConfirmExternalStorage(bool isChecked)
setValue(confirmExternalStorageC(), isChecked);
}

bool ConfigFile::pauseSyncWhenMetered() const
{
return getValue(pauseSyncWhenMeteredC(), {}, false).toBool();
}

void ConfigFile::setPauseSyncWhenMetered(bool isChecked)
{
setValue(pauseSyncWhenMeteredC(), isChecked);
}

bool ConfigFile::moveToTrash() const
{
return getValue(moveToTrashC(), QString(), false).toBool();
Expand Down
3 changes: 3 additions & 0 deletions src/libsync/configfile.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ class OWNCLOUDSYNC_EXPORT ConfigFile
bool confirmExternalStorage() const;
void setConfirmExternalStorage(bool);

bool pauseSyncWhenMetered() const;
void setPauseSyncWhenMetered(bool isChecked);

/** If we should move the files deleted on the server in the trash */
bool moveToTrash() const;
void setMoveToTrash(bool);
Expand Down

0 comments on commit 614caef

Please sign in to comment.