Revise Tracker related classes

And also rename them.

PR #20489.
This commit is contained in:
Chocobo1
2024-04-01 19:17:35 +08:00
committed by GitHub
parent 4967f977c5
commit 90383567b2
24 changed files with 529 additions and 345 deletions

View File

@@ -71,6 +71,7 @@
#include "peeraddress.h"
#include "peerinfo.h"
#include "sessionimpl.h"
#include "trackerentry.h"
#if defined(Q_OS_MACOS) || defined(Q_OS_WIN)
#include "base/utils/os.h"
@@ -101,15 +102,15 @@ namespace
return QString::fromStdString((std::stringstream() << ltTCPEndpoint).str());
}
void updateTrackerEntry(TrackerEntry &trackerEntry, const lt::announce_entry &nativeEntry
void updateTrackerEntryStatus(TrackerEntryStatus &trackerEntryStatus, const lt::announce_entry &nativeEntry
, const QSet<int> &btProtocols, const QHash<lt::tcp::endpoint, QMap<int, int>> &updateInfo)
{
Q_ASSERT(trackerEntry.url == QString::fromStdString(nativeEntry.url));
Q_ASSERT(trackerEntryStatus.url == QString::fromStdString(nativeEntry.url));
trackerEntry.tier = nativeEntry.tier;
trackerEntryStatus.tier = nativeEntry.tier;
// remove outdated endpoints
trackerEntry.endpointEntries.removeIf([&nativeEntry](const QHash<std::pair<QString, int>, TrackerEndpointEntry>::iterator &iter)
trackerEntryStatus.endpoints.removeIf([&nativeEntry](const QHash<std::pair<QString, int>, TrackerEndpointStatus>::iterator &iter)
{
return std::none_of(nativeEntry.endpoints.cbegin(), nativeEntry.endpoints.cend()
, [&endpointName = std::get<0>(iter.key())](const auto &existingEndpoint)
@@ -141,61 +142,61 @@ namespace
const lt::announce_endpoint &ltAnnounceInfo = ltAnnounceEndpoint;
#endif
const QMap<int, int> &endpointUpdateInfo = updateInfo[ltAnnounceEndpoint.local_endpoint];
TrackerEndpointEntry &trackerEndpointEntry = trackerEntry.endpointEntries[std::make_pair(endpointName, protocolVersion)];
TrackerEndpointStatus &trackerEndpointStatus = trackerEntryStatus.endpoints[std::make_pair(endpointName, protocolVersion)];
trackerEndpointEntry.name = endpointName;
trackerEndpointEntry.btVersion = protocolVersion;
trackerEndpointEntry.numPeers = endpointUpdateInfo.value(protocolVersion, trackerEndpointEntry.numPeers);
trackerEndpointEntry.numSeeds = ltAnnounceInfo.scrape_complete;
trackerEndpointEntry.numLeeches = ltAnnounceInfo.scrape_incomplete;
trackerEndpointEntry.numDownloaded = ltAnnounceInfo.scrape_downloaded;
trackerEndpointEntry.nextAnnounceTime = fromLTTimePoint32(ltAnnounceInfo.next_announce);
trackerEndpointEntry.minAnnounceTime = fromLTTimePoint32(ltAnnounceInfo.min_announce);
trackerEndpointStatus.name = endpointName;
trackerEndpointStatus.btVersion = protocolVersion;
trackerEndpointStatus.numPeers = endpointUpdateInfo.value(protocolVersion, trackerEndpointStatus.numPeers);
trackerEndpointStatus.numSeeds = ltAnnounceInfo.scrape_complete;
trackerEndpointStatus.numLeeches = ltAnnounceInfo.scrape_incomplete;
trackerEndpointStatus.numDownloaded = ltAnnounceInfo.scrape_downloaded;
trackerEndpointStatus.nextAnnounceTime = fromLTTimePoint32(ltAnnounceInfo.next_announce);
trackerEndpointStatus.minAnnounceTime = fromLTTimePoint32(ltAnnounceInfo.min_announce);
if (ltAnnounceInfo.updating)
{
trackerEndpointEntry.status = TrackerEntryStatus::Updating;
trackerEndpointStatus.state = TrackerEndpointState::Updating;
++numUpdating;
}
else if (ltAnnounceInfo.fails > 0)
{
if (ltAnnounceInfo.last_error == lt::errors::tracker_failure)
{
trackerEndpointEntry.status = TrackerEntryStatus::TrackerError;
trackerEndpointStatus.state = TrackerEndpointState::TrackerError;
++numTrackerError;
}
else if (ltAnnounceInfo.last_error == lt::errors::announce_skipped)
{
trackerEndpointEntry.status = TrackerEntryStatus::Unreachable;
trackerEndpointStatus.state = TrackerEndpointState::Unreachable;
++numUnreachable;
}
else
{
trackerEndpointEntry.status = TrackerEntryStatus::NotWorking;
trackerEndpointStatus.state = TrackerEndpointState::NotWorking;
++numNotWorking;
}
}
else if (nativeEntry.verified)
{
trackerEndpointEntry.status = TrackerEntryStatus::Working;
trackerEndpointStatus.state = TrackerEndpointState::Working;
++numWorking;
}
else
{
trackerEndpointEntry.status = TrackerEntryStatus::NotContacted;
trackerEndpointStatus.state = TrackerEndpointState::NotContacted;
}
if (!ltAnnounceInfo.message.empty())
{
trackerEndpointEntry.message = QString::fromStdString(ltAnnounceInfo.message);
trackerEndpointStatus.message = QString::fromStdString(ltAnnounceInfo.message);
}
else if (ltAnnounceInfo.last_error)
{
trackerEndpointEntry.message = QString::fromLocal8Bit(ltAnnounceInfo.last_error.message());
trackerEndpointStatus.message = QString::fromLocal8Bit(ltAnnounceInfo.last_error.message());
}
else
{
trackerEndpointEntry.message.clear();
trackerEndpointStatus.message.clear();
}
}
}
@@ -204,58 +205,58 @@ namespace
{
if (numUpdating > 0)
{
trackerEntry.status = TrackerEntryStatus::Updating;
trackerEntryStatus.state = TrackerEndpointState::Updating;
}
else if (numWorking > 0)
{
trackerEntry.status = TrackerEntryStatus::Working;
trackerEntryStatus.state = TrackerEndpointState::Working;
}
else if (numTrackerError > 0)
{
trackerEntry.status = TrackerEntryStatus::TrackerError;
trackerEntryStatus.state = TrackerEndpointState::TrackerError;
}
else if (numUnreachable == numEndpoints)
{
trackerEntry.status = TrackerEntryStatus::Unreachable;
trackerEntryStatus.state = TrackerEndpointState::Unreachable;
}
else if ((numUnreachable + numNotWorking) == numEndpoints)
{
trackerEntry.status = TrackerEntryStatus::NotWorking;
trackerEntryStatus.state = TrackerEndpointState::NotWorking;
}
}
trackerEntry.numPeers = -1;
trackerEntry.numSeeds = -1;
trackerEntry.numLeeches = -1;
trackerEntry.numDownloaded = -1;
trackerEntry.nextAnnounceTime = QDateTime();
trackerEntry.minAnnounceTime = QDateTime();
trackerEntry.message.clear();
trackerEntryStatus.numPeers = -1;
trackerEntryStatus.numSeeds = -1;
trackerEntryStatus.numLeeches = -1;
trackerEntryStatus.numDownloaded = -1;
trackerEntryStatus.nextAnnounceTime = QDateTime();
trackerEntryStatus.minAnnounceTime = QDateTime();
trackerEntryStatus.message.clear();
for (const TrackerEndpointEntry &endpointEntry : asConst(trackerEntry.endpointEntries))
for (const TrackerEndpointStatus &endpointStatus : asConst(trackerEntryStatus.endpoints))
{
trackerEntry.numPeers = std::max(trackerEntry.numPeers, endpointEntry.numPeers);
trackerEntry.numSeeds = std::max(trackerEntry.numSeeds, endpointEntry.numSeeds);
trackerEntry.numLeeches = std::max(trackerEntry.numLeeches, endpointEntry.numLeeches);
trackerEntry.numDownloaded = std::max(trackerEntry.numDownloaded, endpointEntry.numDownloaded);
trackerEntryStatus.numPeers = std::max(trackerEntryStatus.numPeers, endpointStatus.numPeers);
trackerEntryStatus.numSeeds = std::max(trackerEntryStatus.numSeeds, endpointStatus.numSeeds);
trackerEntryStatus.numLeeches = std::max(trackerEntryStatus.numLeeches, endpointStatus.numLeeches);
trackerEntryStatus.numDownloaded = std::max(trackerEntryStatus.numDownloaded, endpointStatus.numDownloaded);
if (endpointEntry.status == trackerEntry.status)
if (endpointStatus.state == trackerEntryStatus.state)
{
if (!trackerEntry.nextAnnounceTime.isValid() || (trackerEntry.nextAnnounceTime > endpointEntry.nextAnnounceTime))
if (!trackerEntryStatus.nextAnnounceTime.isValid() || (trackerEntryStatus.nextAnnounceTime > endpointStatus.nextAnnounceTime))
{
trackerEntry.nextAnnounceTime = endpointEntry.nextAnnounceTime;
trackerEntry.minAnnounceTime = endpointEntry.minAnnounceTime;
if ((endpointEntry.status != TrackerEntryStatus::Working)
|| !endpointEntry.message.isEmpty())
trackerEntryStatus.nextAnnounceTime = endpointStatus.nextAnnounceTime;
trackerEntryStatus.minAnnounceTime = endpointStatus.minAnnounceTime;
if ((endpointStatus.state != TrackerEndpointState::Working)
|| !endpointStatus.message.isEmpty())
{
trackerEntry.message = endpointEntry.message;
trackerEntryStatus.message = endpointStatus.message;
}
}
if (endpointEntry.status == TrackerEntryStatus::Working)
if (endpointStatus.state == TrackerEndpointState::Working)
{
if (trackerEntry.message.isEmpty())
trackerEntry.message = endpointEntry.message;
if (trackerEntryStatus.message.isEmpty())
trackerEntryStatus.message = endpointStatus.message;
}
}
}
@@ -347,9 +348,9 @@ TorrentImpl::TorrentImpl(SessionImpl *session, lt::session *nativeSession
setStopCondition(params.stopCondition);
const auto *extensionData = static_cast<ExtensionData *>(m_ltAddTorrentParams.userdata);
m_trackerEntries.reserve(static_cast<decltype(m_trackerEntries)::size_type>(extensionData->trackers.size()));
m_trackerEntryStatuses.reserve(static_cast<decltype(m_trackerEntryStatuses)::size_type>(extensionData->trackers.size()));
for (const lt::announce_entry &announceEntry : extensionData->trackers)
m_trackerEntries.append({QString::fromStdString(announceEntry.url), announceEntry.tier});
m_trackerEntryStatuses.append({QString::fromStdString(announceEntry.url), announceEntry.tier});
m_urlSeeds.reserve(static_cast<decltype(m_urlSeeds)::size_type>(extensionData->urlSeeds.size()));
for (const std::string &urlSeed : extensionData->urlSeeds)
m_urlSeeds.append(QString::fromStdString(urlSeed));
@@ -601,27 +602,32 @@ Path TorrentImpl::makeUserPath(const Path &path) const
return userPath;
}
QVector<TrackerEntry> TorrentImpl::trackers() const
QVector<TrackerEntryStatus> TorrentImpl::trackers() const
{
return m_trackerEntries;
return m_trackerEntryStatuses;
}
void TorrentImpl::addTrackers(QVector<TrackerEntry> trackers)
{
trackers.removeIf([](const TrackerEntry &entry) { return entry.url.isEmpty(); });
trackers.removeIf([](const TrackerEntry &trackerEntry) { return trackerEntry.url.isEmpty(); });
const auto newTrackers = QSet<TrackerEntry>(trackers.cbegin(), trackers.cend())
- QSet<TrackerEntry>(m_trackerEntries.cbegin(), m_trackerEntries.cend());
if (newTrackers.isEmpty())
QSet<TrackerEntry> currentTrackerSet;
currentTrackerSet.reserve(m_trackerEntryStatuses.size());
for (const TrackerEntryStatus &status : asConst(m_trackerEntryStatuses))
currentTrackerSet.insert({.url = status.url, .tier = status.tier});
const auto newTrackerSet = QSet<TrackerEntry>(trackers.cbegin(), trackers.cend()) - currentTrackerSet;
if (newTrackerSet.isEmpty())
return;
trackers = QVector<TrackerEntry>(newTrackers.cbegin(), newTrackers.cend());
for (const TrackerEntry &tracker : trackers)
trackers = QVector<TrackerEntry>(newTrackerSet.cbegin(), newTrackerSet.cend());
for (const TrackerEntry &tracker : asConst(trackers))
{
m_nativeHandle.add_tracker(makeNativeAnnounceEntry(tracker.url, tracker.tier));
m_trackerEntries.append(trackers);
std::sort(m_trackerEntries.begin(), m_trackerEntries.end()
, [](const TrackerEntry &lhs, const TrackerEntry &rhs) { return lhs.tier < rhs.tier; });
m_trackerEntryStatuses.append({tracker.url, tracker.tier});
}
std::sort(m_trackerEntryStatuses.begin(), m_trackerEntryStatuses.end()
, [](const TrackerEntryStatus &left, const TrackerEntryStatus &right) { return left.tier < right.tier; });
deferredRequestResumeData();
m_session->handleTorrentTrackersAdded(this, trackers);
@@ -632,13 +638,13 @@ void TorrentImpl::removeTrackers(const QStringList &trackers)
QStringList removedTrackers = trackers;
for (const QString &tracker : trackers)
{
if (!m_trackerEntries.removeOne({tracker}))
if (!m_trackerEntryStatuses.removeOne({tracker}))
removedTrackers.removeOne(tracker);
}
std::vector<lt::announce_entry> nativeTrackers;
nativeTrackers.reserve(m_trackerEntries.size());
for (const TrackerEntry &tracker : asConst(m_trackerEntries))
nativeTrackers.reserve(m_trackerEntryStatuses.size());
for (const TrackerEntryStatus &tracker : asConst(m_trackerEntryStatuses))
nativeTrackers.emplace_back(makeNativeAnnounceEntry(tracker.url, tracker.tier));
if (!removedTrackers.isEmpty())
@@ -652,20 +658,25 @@ void TorrentImpl::removeTrackers(const QStringList &trackers)
void TorrentImpl::replaceTrackers(QVector<TrackerEntry> trackers)
{
trackers.removeIf([](const TrackerEntry &entry) { return entry.url.isEmpty(); });
trackers.removeIf([](const TrackerEntry &trackerEntry) { return trackerEntry.url.isEmpty(); });
// Filter out duplicate trackers
const auto uniqueTrackers = QSet<TrackerEntry>(trackers.cbegin(), trackers.cend());
trackers = QVector<TrackerEntry>(uniqueTrackers.cbegin(), uniqueTrackers.cend());
std::sort(trackers.begin(), trackers.end()
, [](const TrackerEntry &lhs, const TrackerEntry &rhs) { return lhs.tier < rhs.tier; });
, [](const TrackerEntry &left, const TrackerEntry &right) { return left.tier < right.tier; });
std::vector<lt::announce_entry> nativeTrackers;
nativeTrackers.reserve(trackers.size());
m_trackerEntryStatuses.clear();
for (const TrackerEntry &tracker : trackers)
{
nativeTrackers.emplace_back(makeNativeAnnounceEntry(tracker.url, tracker.tier));
m_trackerEntryStatuses.append({tracker.url, tracker.tier});
}
m_nativeHandle.replace_trackers(nativeTrackers);
m_trackerEntries = trackers;
// Clear the peer list if it's a private torrent since
// we do not want to keep connecting with peers from old tracker.
@@ -1679,16 +1690,16 @@ void TorrentImpl::fileSearchFinished(const Path &savePath, const PathList &fileN
endReceivedMetadataHandling(savePath, fileNames);
}
TrackerEntry TorrentImpl::updateTrackerEntry(const lt::announce_entry &announceEntry, const QHash<lt::tcp::endpoint, QMap<int, int>> &updateInfo)
TrackerEntryStatus TorrentImpl::updateTrackerEntryStatus(const lt::announce_entry &announceEntry, const QHash<lt::tcp::endpoint, QMap<int, int>> &updateInfo)
{
const auto it = std::find_if(m_trackerEntries.begin(), m_trackerEntries.end()
, [&announceEntry](const TrackerEntry &trackerEntry)
const auto it = std::find_if(m_trackerEntryStatuses.begin(), m_trackerEntryStatuses.end()
, [&announceEntry](const TrackerEntryStatus &trackerEntryStatus)
{
return (trackerEntry.url == QString::fromStdString(announceEntry.url));
return (trackerEntryStatus.url == QString::fromStdString(announceEntry.url));
});
Q_ASSERT(it != m_trackerEntries.end());
if (it == m_trackerEntries.end()) [[unlikely]]
Q_ASSERT(it != m_trackerEntryStatuses.end());
if (it == m_trackerEntryStatuses.end()) [[unlikely]]
return {};
#ifdef QBT_USES_LIBTORRENT2
@@ -1701,14 +1712,21 @@ TrackerEntry TorrentImpl::updateTrackerEntry(const lt::announce_entry &announceE
#else
const QSet<int> btProtocols {1};
#endif
::updateTrackerEntry(*it, announceEntry, btProtocols, updateInfo);
::updateTrackerEntryStatus(*it, announceEntry, btProtocols, updateInfo);
return *it;
}
void TorrentImpl::resetTrackerEntries()
void TorrentImpl::resetTrackerEntryStatuses()
{
for (auto &trackerEntry : m_trackerEntries)
trackerEntry = {trackerEntry.url, trackerEntry.tier};
for (TrackerEntryStatus &status : m_trackerEntryStatuses)
{
const QString tempUrl = status.url;
const int tempTier = status.tier;
status.clear();
status.url = tempUrl;
status.tier = tempTier;
}
}
std::shared_ptr<const libtorrent::torrent_info> TorrentImpl::nativeTorrentInfo() const
@@ -2738,7 +2756,7 @@ QString TorrentImpl::createMagnetURI() const
ret += u"&dn=" + QString::fromLatin1(QUrl::toPercentEncoding(displayName));
}
for (const TrackerEntry &tracker : asConst(trackers()))
for (const TrackerEntryStatus &tracker : asConst(trackers()))
{
ret += u"&tr=" + QString::fromLatin1(QUrl::toPercentEncoding(tracker.url));
}
@@ -2766,8 +2784,8 @@ nonstd::expected<lt::entry, QString> TorrentImpl::exportTorrent() const
#endif
lt::create_torrent creator {*torrentInfo};
for (const TrackerEntry &entry : asConst(trackers()))
creator.add_tracker(entry.url.toStdString(), entry.tier);
for (const TrackerEntryStatus &status : asConst(trackers()))
creator.add_tracker(status.url.toStdString(), status.tier);
return creator.generate();
}