From 93f5d4058d17c21352002986a59e7a658c1c8508 Mon Sep 17 00:00:00 2001 From: "Vladimir Golovnev (qlassez)" Date: Sun, 20 Aug 2017 18:00:23 +0300 Subject: [PATCH] Improve BandwidthScheduler Don't disable scheduler when manually switching speed limits. Closes #7306. --- .../bittorrent/private/bandwidthscheduler.cpp | 75 ++++++++++--------- .../bittorrent/private/bandwidthscheduler.h | 22 ++++-- src/base/bittorrent/session.cpp | 71 ++++++++++-------- src/base/bittorrent/session.h | 5 +- src/gui/mainwindow.cpp | 4 +- src/gui/optionsdlg.cpp | 4 +- 6 files changed, 100 insertions(+), 81 deletions(-) diff --git a/src/base/bittorrent/private/bandwidthscheduler.cpp b/src/base/bittorrent/private/bandwidthscheduler.cpp index ee009ac55..9e5126668 100644 --- a/src/base/bittorrent/private/bandwidthscheduler.cpp +++ b/src/base/bittorrent/private/bandwidthscheduler.cpp @@ -1,6 +1,7 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2010 Christophe Dumez + * Copyright (C) 2017 Vladimir Golovnev + * Copyright (C) 2010 Christophe Dumez * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -24,72 +25,78 @@ * modify file(s), you may extend this exception to your version of the file(s), * but you are not obligated to do so. If you do not wish to do so, delete this * exception statement from your version. - * - * Contact : chris@qbittorrent.org */ +#include "bandwidthscheduler.h" + +#include + +#include #include -#include -#include "base/bittorrent/session.h" #include "base/preferences.h" -#include "bandwidthscheduler.h" BandwidthScheduler::BandwidthScheduler(QObject *parent) - : QTimer(parent) + : QObject(parent) + , m_lastAlternative(false) { - // Single shot, we call start() again manually - setSingleShot(true); - // Connect Signals/Slots - connect(this, SIGNAL(timeout()), this, SLOT(start())); + connect(&m_timer, &QTimer::timeout, this, &BandwidthScheduler::onTimeout); } void BandwidthScheduler::start() +{ + m_lastAlternative = isTimeForAlternative(); + emit bandwidthLimitRequested(m_lastAlternative); + + // Timeout regularly to accommodate for external system clock changes + // eg from the user or from a timesync utility + m_timer.start(30000); +} + +bool BandwidthScheduler::isTimeForAlternative() const { const Preferences* const pref = Preferences::instance(); - bool alt_bw_enabled = BitTorrent::Session::instance()->isAltGlobalSpeedLimitEnabled(); QTime start = pref->getSchedulerStartTime(); QTime end = pref->getSchedulerEndTime(); - QTime now = QTime::currentTime(); - int sched_days = pref->getSchedulerDays(); - int day = QDateTime::currentDateTime().toLocalTime().date().dayOfWeek(); - bool new_mode = false; - bool reverse = false; + const QTime now = QTime::currentTime(); + const int schedulerDays = pref->getSchedulerDays(); + const int day = QDate::currentDate().dayOfWeek(); + bool alternative = false; if (start > end) { - QTime temp = start; - start = end; - end = temp; - reverse = true; + std::swap(start, end); + alternative = true; } if ((start <= now) && (end >= now)) { - switch(sched_days) { + switch (schedulerDays) { case EVERY_DAY: - new_mode = true; + alternative = !alternative; break; case WEEK_ENDS: if ((day == 6) || (day == 7)) - new_mode = true; + alternative = !alternative; break; case WEEK_DAYS: if ((day != 6) && (day != 7)) - new_mode = true; + alternative = !alternative; break; default: - if (day == (sched_days - 2)) - new_mode = true; + if (day == (schedulerDays - 2)) + alternative = !alternative; } } - if (reverse) - new_mode = !new_mode; + return alternative; +} - if (new_mode != alt_bw_enabled) - emit switchToAlternativeMode(new_mode); +void BandwidthScheduler::onTimeout() +{ + bool alternative = isTimeForAlternative(); - // Timeout regularly to accommodate for external system clock changes - // eg from the user or from a timesync utility - QTimer::start(1500); + if (alternative != m_lastAlternative) { + m_lastAlternative = alternative; + emit bandwidthLimitRequested(alternative); + } } diff --git a/src/base/bittorrent/private/bandwidthscheduler.h b/src/base/bittorrent/private/bandwidthscheduler.h index 5b68f82b6..602bcade5 100644 --- a/src/base/bittorrent/private/bandwidthscheduler.h +++ b/src/base/bittorrent/private/bandwidthscheduler.h @@ -1,6 +1,7 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2010 Christophe Dumez + * Copyright (C) 2017 Vladimir Golovnev + * Copyright (C) 2010 Christophe Dumez * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -24,27 +25,32 @@ * modify file(s), you may extend this exception to your version of the file(s), * but you are not obligated to do so. If you do not wish to do so, delete this * exception statement from your version. - * - * Contact : chris@qbittorrent.org */ #ifndef BANDWIDTHSCHEDULER_H #define BANDWIDTHSCHEDULER_H +#include #include -class BandwidthScheduler : public QTimer +class BandwidthScheduler: public QObject { Q_OBJECT + Q_DISABLE_COPY(BandwidthScheduler) public: - BandwidthScheduler(QObject *parent = 0); - -public slots: + explicit BandwidthScheduler(QObject *parent = nullptr); void start(); signals: - void switchToAlternativeMode(bool alternative); + void bandwidthLimitRequested(bool alternative); + +private: + bool isTimeForAlternative() const; + void onTimeout(); + + QTimer m_timer; + bool m_lastAlternative; }; #endif // BANDWIDTHSCHEDULER_H diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index a156a45c7..6b357a31f 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -441,6 +441,9 @@ Session::Session(QObject *parent) .arg(encryption() == 0 ? tr("ON") : encryption() == 1 ? tr("FORCED") : tr("OFF")) , Log::INFO); + if (isBandwidthSchedulerEnabled()) + enableBandwidthScheduler(); + if (isIPFilteringEnabled()) { // Manually banned IPs are handled in that function too(in the slots) enableIPFilter(); @@ -953,13 +956,8 @@ Session::~Session() void Session::initInstance() { - if (!m_instance) { + if (!m_instance) m_instance = new Session; - - // BandwidthScheduler::start() depends on Session being fully constructed - if (m_instance->isBandwidthSchedulerEnabled()) - m_instance->enableBandwidthScheduler(); - } } void Session::freeInstance() @@ -990,6 +988,19 @@ void Session::adjustLimits() } } +void Session::applyBandwidthLimits() +{ +#if LIBTORRENT_VERSION_NUM < 10100 + libt::session_settings sessionSettings(m_nativeSession->settings()); + applyBandwidthLimits(sessionSettings); + m_nativeSession->set_settings(sessionSettings); +#else + libt::settings_pack settingsPack = m_nativeSession->get_settings(); + applyBandwidthLimits(settingsPack); + m_nativeSession->apply_settings(settingsPack); +#endif +} + // Set BitTorrent session configuration void Session::configure() { @@ -1042,6 +1053,13 @@ void Session::adjustLimits(libt::settings_pack &settingsPack) , maxActive > -1 ? maxActive + m_extraLimit : maxActive); } +void Session::applyBandwidthLimits(libtorrent::settings_pack &settingsPack) +{ + const bool altSpeedLimitEnabled = isAltGlobalSpeedLimitEnabled(); + settingsPack.set_int(libt::settings_pack::download_rate_limit, altSpeedLimitEnabled ? altGlobalDownloadSpeedLimit() : globalDownloadSpeedLimit()); + settingsPack.set_int(libt::settings_pack::upload_rate_limit, altSpeedLimitEnabled ? altGlobalUploadSpeedLimit() : globalUploadSpeedLimit()); +} + void Session::initMetrics() { m_metricIndices.net.hasIncomingConnections = libt::find_metric_idx("net.has_incoming_connections"); @@ -1185,9 +1203,7 @@ void Session::configure(libtorrent::settings_pack &settingsPack) m_listenInterfaceChanged = false; } - const bool altSpeedLimitEnabled = isAltGlobalSpeedLimitEnabled(); - settingsPack.set_int(libt::settings_pack::download_rate_limit, altSpeedLimitEnabled ? altGlobalDownloadSpeedLimit() : globalDownloadSpeedLimit()); - settingsPack.set_int(libt::settings_pack::upload_rate_limit, altSpeedLimitEnabled ? altGlobalUploadSpeedLimit() : globalUploadSpeedLimit()); + applyBandwidthLimits(settingsPack); // The most secure, rc4 only so that all streams are encrypted settingsPack.set_int(libt::settings_pack::allowed_enc_level, libt::settings_pack::pe_rc4); @@ -1397,11 +1413,16 @@ void Session::adjustLimits(libt::session_settings &sessionSettings) sessionSettings.active_limit = maxActive > -1 ? maxActive + m_extraLimit : maxActive; } -void Session::configure(libtorrent::session_settings &sessionSettings) +void Session::applyBandwidthLimits(libt::session_settings &sessionSettings) { const bool altSpeedLimitEnabled = isAltGlobalSpeedLimitEnabled(); sessionSettings.download_rate_limit = altSpeedLimitEnabled ? altGlobalDownloadSpeedLimit() : globalDownloadSpeedLimit(); sessionSettings.upload_rate_limit = altSpeedLimitEnabled ? altGlobalUploadSpeedLimit() : globalUploadSpeedLimit(); +} + +void Session::configure(libtorrent::session_settings &sessionSettings) +{ + applyBandwidthLimits(sessionSettings); // The most secure, rc4 only so that all streams are encrypted libt::pe_settings encryptionSettings; @@ -1568,7 +1589,8 @@ void Session::enableBandwidthScheduler() { if (!m_bwScheduler) { m_bwScheduler = new BandwidthScheduler(this); - connect(m_bwScheduler.data(), SIGNAL(switchToAlternativeMode(bool)), this, SLOT(switchToAlternativeMode(bool))); + connect(m_bwScheduler.data(), &BandwidthScheduler::bandwidthLimitRequested + , this, &Session::setAltGlobalSpeedLimitEnabled); } m_bwScheduler->start(); } @@ -1650,11 +1672,6 @@ void Session::handleRedirectedToMagnet(const QString &url, const QString &magnet addTorrent_impl(m_downloadedTorrents.take(url), MagnetUri(magnetUri)); } -void Session::switchToAlternativeMode(bool alternative) -{ - changeSpeedLimitMode_impl(alternative); -} - // Add to BitTorrent session the downloaded torrent file void Session::handleDownloadFinished(const QString &url, const QString &filePath) { @@ -2147,18 +2164,6 @@ void Session::exportTorrentFile(TorrentHandle *const torrent, TorrentExportFolde } } -void Session::changeSpeedLimitMode_impl(bool alternative) -{ - qDebug() << Q_FUNC_INFO << alternative; - if (alternative == isAltGlobalSpeedLimitEnabled()) return; - - // Save new state to remember it on startup - m_isAltGlobalSpeedLimitEnabled = alternative; - configureDeferred(); - // Notify - emit speedLimitModeChanged(alternative); -} - void Session::generateResumeData(bool final) { foreach (TorrentHandle *const torrent, m_torrents) { @@ -2488,11 +2493,13 @@ bool Session::isAltGlobalSpeedLimitEnabled() const void Session::setAltGlobalSpeedLimitEnabled(bool enabled) { - // Stop the scheduler when the user has manually changed the bandwidth mode - if (isBandwidthSchedulerEnabled()) - setBandwidthSchedulerEnabled(false); + if (enabled == isAltGlobalSpeedLimitEnabled()) return; - changeSpeedLimitMode_impl(enabled); + // Save new state to remember it on startup + m_isAltGlobalSpeedLimitEnabled = enabled; + applyBandwidthLimits(); + // Notify + emit speedLimitModeChanged(m_isAltGlobalSpeedLimitEnabled); } bool Session::isBandwidthSchedulerEnabled() const diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index 8a982e248..ba17d5df8 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -480,7 +480,6 @@ namespace BitTorrent void handleDownloadFinished(const QString &url, const QString &filePath); void handleDownloadFailed(const QString &url, const QString &reason); void handleRedirectedToMagnet(const QString &url, const QString &magnetUri); - void switchToAlternativeMode(bool alternative); // Session reconfiguration triggers void networkOnlineStateChanged(const bool online); @@ -500,17 +499,19 @@ namespace BitTorrent #if LIBTORRENT_VERSION_NUM < 10100 void configure(libtorrent::session_settings &sessionSettings); void adjustLimits(libtorrent::session_settings &sessionSettings); + void applyBandwidthLimits(libtorrent::session_settings &sessionSettings); #else void configure(libtorrent::settings_pack &settingsPack); void configurePeerClasses(); void adjustLimits(libtorrent::settings_pack &settingsPack); + void applyBandwidthLimits(libtorrent::settings_pack &settingsPack); void initMetrics(); #endif void adjustLimits(); + void applyBandwidthLimits(); void processBannedIPs(libtorrent::ip_filter &filter); const QStringList getListeningIPs(); void configureListeningInterface(); - void changeSpeedLimitMode_impl(bool alternative); void enableTracker(bool enable); void enableBandwidthScheduler(); void populateAdditionalTrackers(); diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index cd9faa6bb..b06095cb3 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -1293,7 +1293,7 @@ static bool dockClickHandler(id self, SEL cmd, ...) } void MainWindow::setupDockClickHandler() -{ +{ dockMainWindowHandle = this; overrideDockClickHandler(dockClickHandler); } @@ -1831,8 +1831,6 @@ void MainWindow::handleUpdateCheckFinished(bool updateAvailable, QString newVers void MainWindow::toggleAlternativeSpeeds() { BitTorrent::Session *const session = BitTorrent::Session::instance(); - if (session->isBandwidthSchedulerEnabled()) - m_statusBar->showMessage(tr("Manual change of rate limits mode. The scheduler is disabled."), 5000); session->setAltGlobalSpeedLimitEnabled(!session->isAltGlobalSpeedLimitEnabled()); } diff --git a/src/gui/optionsdlg.cpp b/src/gui/optionsdlg.cpp index 5cec23c3c..2ed485218 100644 --- a/src/gui/optionsdlg.cpp +++ b/src/gui/optionsdlg.cpp @@ -84,7 +84,7 @@ OptionsDialog::OptionsDialog(QWidget *parent) #if (defined(Q_OS_UNIX)) setWindowTitle(tr("Preferences")); #endif - + // Icons m_ui->tabSelection->item(TAB_UI)->setIcon(GuiIconProvider::instance()->getIcon("preferences-desktop")); m_ui->tabSelection->item(TAB_BITTORRENT)->setIcon(GuiIconProvider::instance()->getIcon("preferences-system-network")); @@ -586,10 +586,10 @@ void OptionsDialog::saveOptions() const QPair alt_down_up_limit = getAltGlobalBandwidthLimits(); session->setAltGlobalDownloadSpeedLimit(alt_down_up_limit.first); session->setAltGlobalUploadSpeedLimit(alt_down_up_limit.second); - session->setBandwidthSchedulerEnabled(m_ui->check_schedule->isChecked()); pref->setSchedulerStartTime(m_ui->schedule_from->time()); pref->setSchedulerEndTime(m_ui->schedule_to->time()); pref->setSchedulerDays(static_cast(m_ui->schedule_days->currentIndex())); + session->setBandwidthSchedulerEnabled(m_ui->check_schedule->isChecked()); auto proxyConfigManager = Net::ProxyConfigurationManager::instance(); Net::ProxyConfiguration proxyConf;