Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to pause/resume entire BitTorrent session #20757

Merged
merged 5 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/base/bittorrent/session.h
Original file line number Diff line number Diff line change
Expand Up @@ -430,9 +430,15 @@ namespace BitTorrent
virtual void setResumeDataStorageType(ResumeDataStorageType type) = 0;
virtual bool isMergeTrackersEnabled() const = 0;
virtual void setMergeTrackersEnabled(bool enabled) = 0;
virtual bool isStartPaused() const = 0;
virtual void setStartPaused(bool value) = 0;

virtual bool isRestored() const = 0;

virtual bool isPaused() const = 0;
virtual void pause() = 0;
virtual void resume() = 0;

virtual Torrent *getTorrent(const TorrentID &id) const = 0;
virtual Torrent *findTorrent(const InfoHash &infoHash) const = 0;
virtual QVector<Torrent *> torrents() const = 0;
Expand Down Expand Up @@ -466,6 +472,8 @@ namespace BitTorrent
void loadTorrentFailed(const QString &error);
void metadataDownloaded(const TorrentInfo &info);
void restored();
void paused();
void resumed();
void speedLimitModeChanged(bool alternative);
void statsUpdated();
void subcategoriesSupportChanged();
Expand Down
47 changes: 46 additions & 1 deletion src/base/bittorrent/sessionimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,7 @@ SessionImpl::SessionImpl(QObject *parent)
, m_I2POutboundQuantity {BITTORRENT_SESSION_KEY(u"I2P/OutboundQuantity"_s), 3}
, m_I2PInboundLength {BITTORRENT_SESSION_KEY(u"I2P/InboundLength"_s), 3}
, m_I2POutboundLength {BITTORRENT_SESSION_KEY(u"I2P/OutboundLength"_s), 3}
, m_startPaused {BITTORRENT_SESSION_KEY(u"StartPaused"_s)}
, m_seedingLimitTimer {new QTimer(this)}
, m_resumeDataTimer {new QTimer(this)}
, m_ioThread {new QThread}
Expand Down Expand Up @@ -1540,7 +1541,9 @@ void SessionImpl::endStartup(ResumeSessionContext *context)
context->deleteLater();
connect(context, &QObject::destroyed, this, [this]
{
m_nativeSession->resume();
if (!m_isPaused)
m_nativeSession->resume();

if (m_refreshEnqueued)
m_refreshEnqueued = false;
else
Expand Down Expand Up @@ -3913,6 +3916,16 @@ void SessionImpl::setMergeTrackersEnabled(const bool enabled)
m_isMergeTrackersEnabled = enabled;
}

bool SessionImpl::isStartPaused() const
{
return m_startPaused.get(false);
}

void SessionImpl::setStartPaused(const bool value)
{
m_startPaused = value;
}

QStringList SessionImpl::bannedIPs() const
{
return m_bannedIPs;
Expand All @@ -3923,6 +3936,35 @@ bool SessionImpl::isRestored() const
return m_isRestored;
}

bool SessionImpl::isPaused() const
{
return m_isPaused;
}

void SessionImpl::pause()
{
if (!m_isPaused)
{
if (isRestored())
m_nativeSession->pause();

m_isPaused = true;
emit paused();
}
}

void SessionImpl::resume()
{
if (m_isPaused)
{
if (isRestored())
m_nativeSession->resume();

m_isPaused = false;
emit resumed();
}
}

int SessionImpl::maxConnectionsPerTorrent() const
{
return m_maxConnectionsPerTorrent;
Expand Down Expand Up @@ -4370,6 +4412,9 @@ void SessionImpl::setQueueingSystemEnabled(const bool enabled)
m_torrentsQueueChanged = true;
else
removeTorrentsQueue();

for (TorrentImpl *torrent : asConst(m_torrents))
torrent->handleQueueingModeChanged();
}
}

Expand Down
8 changes: 8 additions & 0 deletions src/base/bittorrent/sessionimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -407,9 +407,15 @@ namespace BitTorrent
void setResumeDataStorageType(ResumeDataStorageType type) override;
bool isMergeTrackersEnabled() const override;
void setMergeTrackersEnabled(bool enabled) override;
bool isStartPaused() const override;
void setStartPaused(bool value) override;

bool isRestored() const override;

bool isPaused() const override;
void pause() override;
void resume() override;

Torrent *getTorrent(const TorrentID &id) const override;
Torrent *findTorrent(const InfoHash &infoHash) const override;
QVector<Torrent *> torrents() const override;
Expand Down Expand Up @@ -722,8 +728,10 @@ namespace BitTorrent
CachedSettingValue<int> m_I2POutboundQuantity;
CachedSettingValue<int> m_I2PInboundLength;
CachedSettingValue<int> m_I2POutboundLength;
SettingValue<bool> m_startPaused;

bool m_isRestored = false;
bool m_isPaused = isStartPaused();

// Order is important. This needs to be declared after its CachedSettingsValue
// counterpart, because it uses it for initialization in the constructor
Expand Down
14 changes: 11 additions & 3 deletions src/base/bittorrent/torrentimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -999,6 +999,9 @@ bool TorrentImpl::isStopped() const

bool TorrentImpl::isQueued() const
{
if (!m_session->isQueueingSystemEnabled())
return false;

// Torrent is Queued if it isn't in Stopped state but paused internally
return (!isStopped()
&& (m_nativeStatus.flags & lt::torrent_flags::auto_managed)
Expand Down Expand Up @@ -1153,7 +1156,7 @@ void TorrentImpl::updateState()
{
if (isStopped())
m_state = TorrentState::StoppedDownloading;
else if (m_session->isQueueingSystemEnabled() && isQueued())
else if (isQueued())
m_state = TorrentState::QueuedDownloading;
else
m_state = isForced() ? TorrentState::ForcedDownloadingMetadata : TorrentState::DownloadingMetadata;
Expand All @@ -1167,7 +1170,7 @@ void TorrentImpl::updateState()
{
if (isStopped())
m_state = TorrentState::StoppedUploading;
else if (m_session->isQueueingSystemEnabled() && isQueued())
else if (isQueued())
m_state = TorrentState::QueuedUploading;
else if (isForced())
m_state = TorrentState::ForcedUploading;
Expand All @@ -1180,7 +1183,7 @@ void TorrentImpl::updateState()
{
if (isStopped())
m_state = TorrentState::StoppedDownloading;
else if (m_session->isQueueingSystemEnabled() && isQueued())
else if (isQueued())
m_state = TorrentState::QueuedDownloading;
else if (isForced())
m_state = TorrentState::ForcedDownloading;
Expand Down Expand Up @@ -1953,6 +1956,11 @@ void TorrentImpl::handleStateUpdate(const lt::torrent_status &nativeStatus)
updateStatus(nativeStatus);
}

void TorrentImpl::handleQueueingModeChanged()
{
updateState();
}

void TorrentImpl::handleMoveStorageJobFinished(const Path &path, const MoveStorageContext context, const bool hasOutstandingJob)
{
if (context == MoveStorageContext::ChangeSavePath)
Expand Down
1 change: 1 addition & 0 deletions src/base/bittorrent/torrentimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ namespace BitTorrent

void handleAlert(const lt::alert *a);
void handleStateUpdate(const lt::torrent_status &nativeStatus);
void handleQueueingModeChanged();
void handleCategoryOptionsChanged();
void handleAppendExtensionToggled();
void handleUnwantedFolderToggled();
Expand Down
13 changes: 0 additions & 13 deletions src/base/preferences.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1397,19 +1397,6 @@ void Preferences::setConfirmRemoveAllTags(const bool enabled)
setValue(u"Preferences/Advanced/confirmRemoveAllTags"_s, enabled);
}

bool Preferences::confirmPauseAndResumeAll() const
{
return value(u"GUI/ConfirmActions/PauseAndResumeAllTorrents"_s, true);
}

void Preferences::setConfirmPauseAndResumeAll(const bool enabled)
{
if (enabled == confirmPauseAndResumeAll())
return;

setValue(u"GUI/ConfirmActions/PauseAndResumeAllTorrents"_s, enabled);
}

bool Preferences::confirmMergeTrackers() const
{
return value(u"GUI/ConfirmActions/MergeTrackers"_s, true);
Expand Down
2 changes: 0 additions & 2 deletions src/base/preferences.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,8 +305,6 @@ class Preferences final : public QObject
void setConfirmTorrentRecheck(bool enabled);
bool confirmRemoveAllTags() const;
void setConfirmRemoveAllTags(bool enabled);
bool confirmPauseAndResumeAll() const;
void setConfirmPauseAndResumeAll(bool enabled);
bool confirmMergeTrackers() const;
void setConfirmMergeTrackers(bool enabled);
bool confirmRemoveTrackerFromAllTorrents() const;
Expand Down
8 changes: 7 additions & 1 deletion src/gui/advancedsettings.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2016 qBittorrent project
* Copyright (C) 2016-2024 qBittorrent project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
Expand Down Expand Up @@ -105,6 +105,7 @@ namespace
ENABLE_MARK_OF_THE_WEB,
#endif // Q_OS_MACOS || Q_OS_WIN
PYTHON_EXECUTABLE_PATH,
START_SESSION_PAUSED,

// libtorrent section
LIBTORRENT_HEADER,
Expand Down Expand Up @@ -331,6 +332,8 @@ void AdvancedSettings::saveAdvancedSettings() const
#endif // Q_OS_MACOS || Q_OS_WIN
// Python executable path
pref->setPythonExecutablePath(Path(m_pythonExecutablePath.text().trimmed()));
// Start session paused
session->setStartPaused(m_checkBoxStartSessionPaused.isChecked());
// Choking algorithm
session->setChokingAlgorithm(m_comboBoxChokingAlgorithm.currentData().value<BitTorrent::ChokingAlgorithm>());
// Seed choking algorithm
Expand Down Expand Up @@ -843,6 +846,9 @@ void AdvancedSettings::loadAdvancedSettings()
m_pythonExecutablePath.setPlaceholderText(tr("(Auto detect if empty)"));
m_pythonExecutablePath.setText(pref->getPythonExecutablePath().toString());
addRow(PYTHON_EXECUTABLE_PATH, tr("Python executable path (may require restart)"), &m_pythonExecutablePath);
// Start session paused
m_checkBoxStartSessionPaused.setChecked(session->isStartPaused());
addRow(START_SESSION_PAUSED, tr("Start session in paused state"), &m_checkBoxStartSessionPaused);
// Choking algorithm
m_comboBoxChokingAlgorithm.addItem(tr("Fixed slots"), QVariant::fromValue(BitTorrent::ChokingAlgorithm::FixedSlots));
m_comboBoxChokingAlgorithm.addItem(tr("Upload rate based"), QVariant::fromValue(BitTorrent::ChokingAlgorithm::RateBased));
Expand Down
4 changes: 2 additions & 2 deletions src/gui/advancedsettings.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 qBittorrent project
* Copyright (C) 2015-2024 qBittorrent project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
Expand Down Expand Up @@ -79,7 +79,7 @@ private slots:
m_checkBoxProgramNotifications, m_checkBoxTorrentAddedNotifications, m_checkBoxReannounceWhenAddressChanged, m_checkBoxTrackerFavicon, m_checkBoxTrackerStatus,
m_checkBoxTrackerPortForwarding, m_checkBoxConfirmTorrentRecheck, m_checkBoxConfirmRemoveAllTags, m_checkBoxAnnounceAllTrackers, m_checkBoxAnnounceAllTiers,
m_checkBoxMultiConnectionsPerIp, m_checkBoxValidateHTTPSTrackerCertificate, m_checkBoxSSRFMitigation, m_checkBoxBlockPeersOnPrivilegedPorts, m_checkBoxPieceExtentAffinity,
m_checkBoxSuggestMode, m_checkBoxSpeedWidgetEnabled, m_checkBoxIDNSupport, m_checkBoxConfirmRemoveTrackerFromAllTorrents;
m_checkBoxSuggestMode, m_checkBoxSpeedWidgetEnabled, m_checkBoxIDNSupport, m_checkBoxConfirmRemoveTrackerFromAllTorrents, m_checkBoxStartSessionPaused;
QComboBox m_comboBoxInterface, m_comboBoxInterfaceAddress, m_comboBoxDiskIOReadMode, m_comboBoxDiskIOWriteMode, m_comboBoxUtpMixedMode, m_comboBoxChokingAlgorithm,
m_comboBoxSeedChokingAlgorithm, m_comboBoxResumeDataStorage;
QLineEdit m_lineEditAppInstanceName, m_pythonExecutablePath, m_lineEditAnnounceIP, m_lineEditDHTBootstrapNodes;
Expand Down