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

Support fetching tracker list from URL #21828

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/base/bittorrent/session.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,12 @@ namespace BitTorrent
virtual Path finishedTorrentExportDirectory() const = 0;
virtual void setFinishedTorrentExportDirectory(const Path &path) = 0;

virtual bool isAddTrackersFromURLEnabled() const = 0;
virtual void setAddTrackersFromURLEnabled(bool enabled) = 0;
virtual QString additionalTrackersURL() const = 0;
virtual void setAdditionalTrackersURL(const QString &url) = 0;
virtual QString additionalTrackersFromURL() const = 0;

virtual int globalDownloadSpeedLimit() const = 0;
virtual void setGlobalDownloadSpeedLimit(int limit) = 0;
virtual int globalUploadSpeedLimit() const = 0;
Expand Down
112 changes: 112 additions & 0 deletions src/base/bittorrent/sessionimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
#include "base/algorithm.h"
#include "base/global.h"
#include "base/logger.h"
#include "base/net/downloadmanager.h"
#include "base/net/proxyconfigurationmanager.h"
#include "base/preferences.h"
#include "base/profile.h"
Expand Down Expand Up @@ -460,6 +461,8 @@ SessionImpl::SessionImpl(QObject *parent)
, m_blockPeersOnPrivilegedPorts(BITTORRENT_SESSION_KEY(u"BlockPeersOnPrivilegedPorts"_s), false)
, m_isAddTrackersEnabled(BITTORRENT_SESSION_KEY(u"AddTrackersEnabled"_s), false)
, m_additionalTrackers(BITTORRENT_SESSION_KEY(u"AdditionalTrackers"_s))
, m_isAddTrackersFromURLEnabled(BITTORRENT_SESSION_KEY(u"AddTrackersFromURLEnabled"_s), false)
, m_additionalTrackersURL(BITTORRENT_SESSION_KEY(u"AdditionalTrackersURL"_s))
, m_globalMaxRatio(BITTORRENT_SESSION_KEY(u"GlobalMaxRatio"_s), -1, [](qreal r) { return r < 0 ? -1. : r;})
, m_globalMaxSeedingMinutes(BITTORRENT_SESSION_KEY(u"GlobalMaxSeedingMinutes"_s), -1, lowerLimited(-1))
, m_globalMaxInactiveSeedingMinutes(BITTORRENT_SESSION_KEY(u"GlobalMaxInactiveSeedingMinutes"_s), -1, lowerLimited(-1))
Expand Down Expand Up @@ -614,6 +617,15 @@ SessionImpl::SessionImpl(QObject *parent)
enableTracker(isTrackerEnabled());

prepareStartup();

m_updateTrackersFromURLTimer = new QTimer(this);
m_updateTrackersFromURLTimer->setInterval(24h);
connect(m_updateTrackersFromURLTimer, &QTimer::timeout, this, &SessionImpl::updateTrackersFromURL);
if (isAddTrackersFromURLEnabled())
{
updateTrackersFromURL();
m_updateTrackersFromURLTimer->start();
}
}

SessionImpl::~SessionImpl()
Expand Down Expand Up @@ -2261,6 +2273,11 @@ void SessionImpl::populateAdditionalTrackers()
m_additionalTrackerEntries = parseTrackerEntries(additionalTrackers());
}

void SessionImpl::populateAdditionalTrackersFromURL()
{
m_additionalTrackerEntriesFromURL = parseTrackerEntries(additionalTrackersFromURL());
}

void SessionImpl::processTorrentShareLimits(TorrentImpl *torrent)
{
if (!torrent->isFinished() || torrent->isForced())
Expand Down Expand Up @@ -2880,6 +2897,21 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr
}
}

if (isAddTrackersFromURLEnabled() && !(hasMetadata && p.ti->priv()))
{
const auto maxTierIter = std::max_element(p.tracker_tiers.cbegin(), p.tracker_tiers.cend());
const int baseTier = (maxTierIter != p.tracker_tiers.cend()) ? (*maxTierIter + 1) : 0;

p.trackers.reserve(p.trackers.size() + static_cast<std::size_t>(m_additionalTrackerEntriesFromURL.size()));
p.tracker_tiers.reserve(p.trackers.size() + static_cast<std::size_t>(m_additionalTrackerEntriesFromURL.size()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

copy paste error?

Suggested change
p.tracker_tiers.reserve(p.trackers.size() + static_cast<std::size_t>(m_additionalTrackerEntriesFromURL.size()));
p.tracker_tiers.reserve(p.tracker_tiers.size() + static_cast<std::size_t>(m_additionalTrackerEntriesFromURL.size()));

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is copied from the code block directly above, though I believe it's intentional so that p.trackers and p.tracker_tiers are always the same size.

p.tracker_tiers.resize(p.trackers.size(), 0);
for (const TrackerEntry &trackerEntry : asConst(m_additionalTrackerEntriesFromURL))
{
p.trackers.emplace_back(trackerEntry.url.toStdString());
p.tracker_tiers.emplace_back(Utils::Number::clampingAdd(trackerEntry.tier, baseTier));
}
}

p.upload_limit = addTorrentParams.uploadLimit;
p.download_limit = addTorrentParams.downloadLimit;

Expand Down Expand Up @@ -3872,6 +3904,86 @@ void SessionImpl::setAdditionalTrackers(const QString &trackers)
populateAdditionalTrackers();
}

bool SessionImpl::isAddTrackersFromURLEnabled() const
{
return m_isAddTrackersFromURLEnabled;
}

void SessionImpl::setAddTrackersFromURLEnabled(const bool enabled)
{
if (enabled != isAddTrackersFromURLEnabled())
{
m_isAddTrackersFromURLEnabled = enabled;
if (enabled)
{
updateTrackersFromURL();
m_updateTrackersFromURLTimer->start();
}
else
{
m_updateTrackersFromURLTimer->stop();
setAdditionalTrackersFromURL({});
}
}
}

QString SessionImpl::additionalTrackersURL() const
{
return m_additionalTrackersURL;
}

void SessionImpl::setAdditionalTrackersURL(const QString &url)
{
if (url != additionalTrackersURL())
{
m_additionalTrackersURL = url.trimmed();
if (isAddTrackersFromURLEnabled())
updateTrackersFromURL();
}
}

QString SessionImpl::additionalTrackersFromURL() const
{
return m_additionalTrackersFromURL;
}

void SessionImpl::setAdditionalTrackersFromURL(const QString &trackers)
{
if (trackers != additionalTrackersFromURL())
{
m_additionalTrackersFromURL = trackers;
populateAdditionalTrackersFromURL();
}
}

void SessionImpl::updateTrackersFromURL()
{
const QString &url = additionalTrackersURL();
if (url.isEmpty())
{
setAdditionalTrackersFromURL({});
}
else
{
Preferences *const pref = Preferences::instance();
Net::DownloadManager::instance()->download(Net::DownloadRequest(url)
, pref->useProxyForGeneralPurposes(), this, &SessionImpl::handleTrackersFromURLDownloadFinished);
}
}

void SessionImpl::handleTrackersFromURLDownloadFinished(const Net::DownloadResult &result)
{
if (result.status == Net::DownloadStatus::Success)
{
setAdditionalTrackersFromURL(QString::fromUtf8(result.data));
LogMsg(tr("Tracker list updated"), Log::INFO);
}
else
{
LogMsg(tr("Failed to update tracker list. Reason: \"%1\"").arg(result.errorString), Log::WARNING);
}
}

bool SessionImpl::isIPFilteringEnabled() const
{
return m_isIPFilteringEnabled;
Expand Down
23 changes: 23 additions & 0 deletions src/base/bittorrent/sessionimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ class FileSearcher;
class FilterParserThread;
class NativeSessionExtension;

namespace Net
{
struct DownloadResult;
}

namespace BitTorrent
{
enum class MoveStorageMode;
Expand Down Expand Up @@ -490,6 +495,12 @@ namespace BitTorrent
m_asyncWorker->start(std::forward<Func>(func));
}

bool isAddTrackersFromURLEnabled() const override;
void setAddTrackersFromURLEnabled(bool enabled) override;
QString additionalTrackersURL() const override;
void setAdditionalTrackersURL(const QString &url) override;
QString additionalTrackersFromURL() const override;

signals:
void addTorrentAlertsReceived(qsizetype count);

Expand All @@ -502,6 +513,7 @@ namespace BitTorrent
void handleIPFilterError();
void fileSearchFinished(const TorrentID &id, const Path &savePath, const PathList &fileNames);
void torrentContentRemovingFinished(const QString &torrentName, const QString &errorMessage);
void handleTrackersFromURLDownloadFinished(const Net::DownloadResult &result);

private:
struct ResumeSessionContext;
Expand Down Expand Up @@ -596,6 +608,8 @@ namespace BitTorrent
void saveTorrentsQueue();
void removeTorrentsQueue();

void populateAdditionalTrackersFromURL();

std::vector<lt::alert *> getPendingAlerts(lt::time_duration time = lt::time_duration::zero()) const;

void moveTorrentStorage(const MoveStorageJob &job) const;
Expand All @@ -614,6 +628,9 @@ namespace BitTorrent

void handleRemovedTorrent(const TorrentID &torrentID, const QString &partfileRemoveError = {});

void setAdditionalTrackersFromURL(const QString &trackers);
void updateTrackersFromURL();

CachedSettingValue<QString> m_DHTBootstrapNodes;
CachedSettingValue<bool> m_isDHTEnabled;
CachedSettingValue<bool> m_isLSDEnabled;
Expand Down Expand Up @@ -676,6 +693,8 @@ namespace BitTorrent
CachedSettingValue<bool> m_blockPeersOnPrivilegedPorts;
CachedSettingValue<bool> m_isAddTrackersEnabled;
CachedSettingValue<QString> m_additionalTrackers;
CachedSettingValue<bool> m_isAddTrackersFromURLEnabled;
CachedSettingValue<QString> m_additionalTrackersURL;
CachedSettingValue<qreal> m_globalMaxRatio;
CachedSettingValue<int> m_globalMaxSeedingMinutes;
CachedSettingValue<int> m_globalMaxInactiveSeedingMinutes;
Expand Down Expand Up @@ -749,6 +768,9 @@ namespace BitTorrent
bool m_IPFilteringConfigured = false;
mutable bool m_listenInterfaceConfigured = false;

QString m_additionalTrackersFromURL;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems you don't really need this since you already have m_additionalTrackerEntriesFromURL.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is mostly useful for the comparison against the existing tracker list to determine if we need to call populateAdditionalTrackersFromURL(), though it's also used to get the list of trackers to display. We could instead do the comparison against QList<TrackerEntry> m_additionalTrackerEntriesFromURL and parse this every time, but it seemed easier to keep around the QString.

QTimer *m_updateTrackersFromURLTimer = nullptr;

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

Expand All @@ -759,6 +781,7 @@ namespace BitTorrent

int m_numResumeData = 0;
QList<TrackerEntry> m_additionalTrackerEntries;
QList<TrackerEntry> m_additionalTrackerEntriesFromURL;
QList<QRegularExpression> m_excludedFileNamesRegExpList;

// Statistics
Expand Down
11 changes: 11 additions & 0 deletions src/gui/optionsdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#include "base/bittorrent/sharelimitaction.h"
#include "base/exceptions.h"
#include "base/global.h"
#include "base/net/downloadmanager.h"
#include "base/net/portforwarder.h"
#include "base/net/proxyconfigurationmanager.h"
#include "base/path.h"
Expand Down Expand Up @@ -1148,6 +1149,10 @@ void OptionsDialog::loadBittorrentTabOptions()
m_ui->checkEnableAddTrackers->setChecked(session->isAddTrackersEnabled());
m_ui->textTrackers->setPlainText(session->additionalTrackers());

m_ui->checkAddTrackersFromURL->setChecked(session->isAddTrackersFromURLEnabled());
m_ui->textTrackersURL->setText(session->additionalTrackersURL());
m_ui->textTrackersFromURL->setPlainText(session->additionalTrackersFromURL());

connect(m_ui->checkDHT, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->checkPeX, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->checkLSD, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
Expand Down Expand Up @@ -1181,6 +1186,9 @@ void OptionsDialog::loadBittorrentTabOptions()

connect(m_ui->checkEnableAddTrackers, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->textTrackers, &QPlainTextEdit::textChanged, this, &ThisType::enableApplyButton);

connect(m_ui->checkAddTrackersFromURL, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->textTrackersURL, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
}

void OptionsDialog::saveBittorrentTabOptions() const
Expand Down Expand Up @@ -1218,6 +1226,9 @@ void OptionsDialog::saveBittorrentTabOptions() const

session->setAddTrackersEnabled(m_ui->checkEnableAddTrackers->isChecked());
session->setAdditionalTrackers(m_ui->textTrackers->toPlainText());

session->setAddTrackersFromURLEnabled(m_ui->checkAddTrackersFromURL->isChecked());
session->setAdditionalTrackersURL(m_ui->textTrackersURL->text());
}

void OptionsDialog::loadRSSTabOptions()
Expand Down
43 changes: 43 additions & 0 deletions src/gui/optionsdialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -3131,6 +3131,49 @@ Disable encryption: Only connect to peers without protocol encryption</string>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="checkAddTrackersFromURL">
<property name="title">
<string>Automatically append trackers from URL to new downloads:</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="checkAddTrackersFromURLLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_21">
<item>
<widget class="QLabel" name="labelCustomizeTrackersListUrl">
<property name="text">
<string>URL:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="textTrackersURL"/>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="labeltrackersFromURL">
<property name="text">
<string>Fetched trackers</string>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="textTrackersFromURL">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_8">
<property name="orientation">
Expand Down
7 changes: 7 additions & 0 deletions src/webui/api/appcontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,9 @@ void AppController::preferencesAction()
// Add trackers
data[u"add_trackers_enabled"_s] = session->isAddTrackersEnabled();
data[u"add_trackers"_s] = session->additionalTrackers();
data[u"add_trackers_from_url_enabled"_s] = session->isAddTrackersFromURLEnabled();
data[u"add_trackers_url"_s] = session->additionalTrackersURL();
data[u"add_trackers_url_list"_s] = session->additionalTrackersFromURL();

// WebUI
// HTTP Server
Expand Down Expand Up @@ -860,6 +863,10 @@ void AppController::setPreferencesAction()
session->setAddTrackersEnabled(it.value().toBool());
if (hasKey(u"add_trackers"_s))
session->setAdditionalTrackers(it.value().toString());
if (hasKey(u"add_trackers_from_url_enabled"_s))
session->setAddTrackersFromURLEnabled(it.value().toBool());
if (hasKey(u"add_trackers_url"_s))
session->setAdditionalTrackersURL(it.value().toString());

// WebUI
// HTTP Server
Expand Down
Loading
Loading