From dcba9eda009fcb74e8aebbee4a4c5df7248abf06 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Thu, 14 Sep 2023 13:57:34 +0800 Subject: [PATCH] Expose 'DHT bootstrap nodes' setting This allows user to select DHT bootstrap nodes. Or even use their own bootstrap nodes. PR #19594. --- src/base/bittorrent/session.h | 2 ++ src/base/bittorrent/sessionimpl.cpp | 20 ++++++++++++++++++-- src/base/bittorrent/sessionimpl.h | 3 +++ src/gui/advancedsettings.cpp | 9 +++++++++ src/gui/advancedsettings.h | 2 +- src/webui/api/appcontroller.cpp | 5 +++++ src/webui/webapplication.h | 2 +- src/webui/www/private/views/preferences.html | 10 ++++++++++ 8 files changed, 49 insertions(+), 4 deletions(-) diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index a6ff616f2..71697e016 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -205,6 +205,8 @@ namespace BitTorrent virtual void setGlobalMaxSeedingMinutes(int minutes) = 0; virtual int globalMaxInactiveSeedingMinutes() const = 0; virtual void setGlobalMaxInactiveSeedingMinutes(int minutes) = 0; + virtual QString getDHTBootstrapNodes() const = 0; + virtual void setDHTBootstrapNodes(const QString &nodes) = 0; virtual bool isDHTEnabled() const = 0; virtual void setDHTEnabled(bool enabled) = 0; virtual bool isLSDEnabled() const = 0; diff --git a/src/base/bittorrent/sessionimpl.cpp b/src/base/bittorrent/sessionimpl.cpp index 652fb9cc9..a5c5bd50e 100644 --- a/src/base/bittorrent/sessionimpl.cpp +++ b/src/base/bittorrent/sessionimpl.cpp @@ -117,6 +117,7 @@ namespace { const char PEER_ID[] = "qB"; const auto USER_AGENT = QStringLiteral("qBittorrent/" QBT_VERSION_2); + const QString DEFAULT_DHT_BOOTSTRAP_NODES = u"dht.libtorrent.org:25401, dht.transmissionbt.com:6881, router.bittorrent.com:6881, router.utorrent.com:6881, dht.aelitis.com:6881"_s; void torrentQueuePositionUp(const lt::torrent_handle &handle) { @@ -378,6 +379,7 @@ QStringList Session::expandCategory(const QString &category) SessionImpl::SessionImpl(QObject *parent) : Session(parent) + , m_DHTBootstrapNodes(BITTORRENT_SESSION_KEY(u"DHTBootstrapNodes"_s), DEFAULT_DHT_BOOTSTRAP_NODES) , m_isDHTEnabled(BITTORRENT_SESSION_KEY(u"DHTEnabled"_s), true) , m_isLSDEnabled(BITTORRENT_SESSION_KEY(u"LSDEnabled"_s), true) , m_isPeXEnabled(BITTORRENT_SESSION_KEY(u"PeXEnabled"_s), true) @@ -603,6 +605,21 @@ SessionImpl::~SessionImpl() delete m_nativeSession; } +QString SessionImpl::getDHTBootstrapNodes() const +{ + const QString nodes = m_DHTBootstrapNodes; + return !nodes.isEmpty() ? nodes : DEFAULT_DHT_BOOTSTRAP_NODES; +} + +void SessionImpl::setDHTBootstrapNodes(const QString &nodes) +{ + if (nodes == m_DHTBootstrapNodes) + return; + + m_DHTBootstrapNodes = nodes; + configureDeferred(); +} + bool SessionImpl::isDHTEnabled() const { return m_isDHTEnabled; @@ -1885,9 +1902,8 @@ lt::settings_pack SessionImpl::loadLTSettings() const settingsPack.set_bool(lt::settings_pack::apply_ip_filter_to_trackers, isTrackerFilteringEnabled()); + settingsPack.set_str(lt::settings_pack::dht_bootstrap_nodes, getDHTBootstrapNodes().toStdString()); settingsPack.set_bool(lt::settings_pack::enable_dht, isDHTEnabled()); - if (isDHTEnabled()) - settingsPack.set_str(lt::settings_pack::dht_bootstrap_nodes, "dht.libtorrent.org:25401,router.bittorrent.com:6881,router.utorrent.com:6881,dht.transmissionbt.com:6881,dht.aelitis.com:6881"); settingsPack.set_bool(lt::settings_pack::enable_lsd, isLSDEnabled()); switch (chokingAlgorithm()) diff --git a/src/base/bittorrent/sessionimpl.h b/src/base/bittorrent/sessionimpl.h index 64daa9ab6..53bdc0e22 100644 --- a/src/base/bittorrent/sessionimpl.h +++ b/src/base/bittorrent/sessionimpl.h @@ -174,6 +174,8 @@ namespace BitTorrent void setGlobalMaxSeedingMinutes(int minutes) override; int globalMaxInactiveSeedingMinutes() const override; void setGlobalMaxInactiveSeedingMinutes(int minutes) override; + QString getDHTBootstrapNodes() const override; + void setDHTBootstrapNodes(const QString &nodes) override; bool isDHTEnabled() const override; void setDHTEnabled(bool enabled) override; bool isLSDEnabled() const override; @@ -582,6 +584,7 @@ namespace BitTorrent bool m_IPFilteringConfigured = false; mutable bool m_listenInterfaceConfigured = false; + CachedSettingValue m_DHTBootstrapNodes; CachedSettingValue m_isDHTEnabled; CachedSettingValue m_isLSDEnabled; CachedSettingValue m_isPeXEnabled; diff --git a/src/gui/advancedsettings.cpp b/src/gui/advancedsettings.cpp index 71dbd5c7d..c53dac9d2 100644 --- a/src/gui/advancedsettings.cpp +++ b/src/gui/advancedsettings.cpp @@ -156,6 +156,7 @@ namespace PEER_TURNOVER_CUTOFF, PEER_TURNOVER_INTERVAL, REQUEST_QUEUE_SIZE, + DHT_BOOTSTRAP_NODES, #if defined(QBT_USES_LIBTORRENT2) && TORRENT_USE_I2P I2P_INBOUND_QUANTITY, I2P_OUTBOUND_QUANTITY, @@ -333,6 +334,8 @@ void AdvancedSettings::saveAdvancedSettings() const session->setPeerTurnoverInterval(m_spinBoxPeerTurnoverInterval.value()); // Maximum outstanding requests to a single peer session->setRequestQueueSize(m_spinBoxRequestQueueSize.value()); + // DHT bootstrap nodes + session->setDHTBootstrapNodes(m_lineEditDHTBootstrapNodes.text()); #if defined(QBT_USES_LIBTORRENT2) && TORRENT_USE_I2P // I2P session options session->setI2PInboundQuantity(m_spinBoxI2PInboundQuantity.value()); @@ -865,7 +868,13 @@ void AdvancedSettings::loadAdvancedSettings() m_spinBoxRequestQueueSize.setValue(session->requestQueueSize()); addRow(REQUEST_QUEUE_SIZE, (tr("Maximum outstanding requests to a single peer") + u' ' + makeLink(u"https://www.libtorrent.org/reference-Settings.html#max_out_request_queue", u"(?)")) , &m_spinBoxRequestQueueSize); + // DHT bootstrap nodes + m_lineEditDHTBootstrapNodes.setPlaceholderText(tr("Resets to default if empty")); + m_lineEditDHTBootstrapNodes.setText(session->getDHTBootstrapNodes()); + addRow(DHT_BOOTSTRAP_NODES, (tr("DHT bootstrap nodes") + u' ' + makeLink(u"https://www.libtorrent.org/reference-Settings.html#dht_bootstrap_nodes", u"(?)")) + , &m_lineEditDHTBootstrapNodes); #if defined(QBT_USES_LIBTORRENT2) && TORRENT_USE_I2P + // I2P session options m_spinBoxI2PInboundQuantity.setMinimum(1); m_spinBoxI2PInboundQuantity.setMaximum(16); m_spinBoxI2PInboundQuantity.setValue(session->I2PInboundQuantity()); diff --git a/src/gui/advancedsettings.h b/src/gui/advancedsettings.h index 82ff74ca6..2813969b6 100644 --- a/src/gui/advancedsettings.h +++ b/src/gui/advancedsettings.h @@ -81,7 +81,7 @@ private: m_checkBoxSuggestMode, m_checkBoxSpeedWidgetEnabled, m_checkBoxIDNSupport; QComboBox m_comboBoxInterface, m_comboBoxInterfaceAddress, m_comboBoxDiskIOReadMode, m_comboBoxDiskIOWriteMode, m_comboBoxUtpMixedMode, m_comboBoxChokingAlgorithm, m_comboBoxSeedChokingAlgorithm, m_comboBoxResumeDataStorage; - QLineEdit m_lineEditAnnounceIP; + QLineEdit m_lineEditAnnounceIP, m_lineEditDHTBootstrapNodes; #ifndef QBT_USES_LIBTORRENT2 QSpinBox m_spinBoxCache, m_spinBoxCacheTTL; diff --git a/src/webui/api/appcontroller.cpp b/src/webui/api/appcontroller.cpp index 346e9a8d9..700586c40 100644 --- a/src/webui/api/appcontroller.cpp +++ b/src/webui/api/appcontroller.cpp @@ -420,6 +420,8 @@ void AppController::preferencesAction() data[u"peer_turnover_interval"_s] = session->peerTurnoverInterval(); // Maximum outstanding requests to a single peer data[u"request_queue_size"_s] = session->requestQueueSize(); + // DHT bootstrap nodes + data[u"dht_bootstrap_nodes"_s] = session->getDHTBootstrapNodes(); setResult(data); } @@ -1018,6 +1020,9 @@ void AppController::setPreferencesAction() // Maximum outstanding requests to a single peer if (hasKey(u"request_queue_size"_s)) session->setRequestQueueSize(it.value().toInt()); + // DHT bootstrap nodes + if (hasKey(u"dht_bootstrap_nodes"_s)) + session->setDHTBootstrapNodes(it.value().toString()); // Save preferences pref->apply(); diff --git a/src/webui/webapplication.h b/src/webui/webapplication.h index e8fbe8a63..1e5d1c2c8 100644 --- a/src/webui/webapplication.h +++ b/src/webui/webapplication.h @@ -52,7 +52,7 @@ #include "base/utils/version.h" #include "api/isessionmanager.h" -inline const Utils::Version<3, 2> API_VERSION {2, 9, 3}; +inline const Utils::Version<3, 2> API_VERSION {2, 9, 4}; class APIController; class AuthController; diff --git a/src/webui/www/private/views/preferences.html b/src/webui/www/private/views/preferences.html index 1eb726e21..c11170905 100644 --- a/src/webui/www/private/views/preferences.html +++ b/src/webui/www/private/views/preferences.html @@ -1420,6 +1420,14 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD + + + + + + + + @@ -2241,6 +2249,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD $('peerTurnoverCutoff').setProperty('value', pref.peer_turnover_cutoff); $('peerTurnoverInterval').setProperty('value', pref.peer_turnover_interval); $('requestQueueSize').setProperty('value', pref.request_queue_size); + $('dhtBootstrapNodes').setProperty('value', pref.dht_bootstrap_nodes); } } }).send(); @@ -2673,6 +2682,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD settings.set('peer_turnover_cutoff', $('peerTurnoverCutoff').getProperty('value')); settings.set('peer_turnover_interval', $('peerTurnoverInterval').getProperty('value')); settings.set('request_queue_size', $('requestQueueSize').getProperty('value')); + settings.set('dht_bootstrap_nodes', $('dhtBootstrapNodes').getProperty('value')); // Send it to qBT const json_str = JSON.encode(settings);