Improve tracker entries handling

PR #19468.

* Use QHash to map tracker endpoints
* Don't clear numPeers unexpectedly
* Remove outdated tracker entry endpoints
* Move presentation logic from Core to GUI code
* Show all endpoints per tracker in tree structure

---------

Co-authored-by: Kacper Michajłow <kasper93@gmail.com>
This commit is contained in:
Vladimir Golovnev
2023-08-21 10:27:19 +03:00
committed by GitHub
parent 34d30ed031
commit c805606524
8 changed files with 176 additions and 91 deletions

View File

@@ -5920,7 +5920,7 @@ void SessionImpl::handleTrackerAlert(const lt::tracker_alert *a)
if (!torrent)
return;
QMap<TrackerEntry::Endpoint, int> &updateInfo = m_updatedTrackerEntries[torrent->nativeHandle()][std::string(a->tracker_url())];
QHash<TrackerEntry::Endpoint, int> &updateInfo = m_updatedTrackerEntries[torrent->nativeHandle()][std::string(a->tracker_url())];
if (a->type() == lt::tracker_reply_alert::alert_type)
{
@@ -6004,7 +6004,7 @@ void SessionImpl::processTrackerStatuses()
if (updatedTrackersIter == updatedTrackers.end())
continue;
const QMap<TrackerEntry::Endpoint, int> &updateInfo = updatedTrackersIter.value();
const QHash<TrackerEntry::Endpoint, int> &updateInfo = updatedTrackersIter.value();
TrackerEntry trackerEntry = torrent->updateTrackerEntry(announceEntry, updateInfo);
const QString url = trackerEntry.url;
updatedTrackerEntries.emplace(url, std::move(trackerEntry));

View File

@@ -746,7 +746,7 @@ namespace BitTorrent
// This field holds amounts of peers reported by trackers in their responses to announces
// (torrent.tracker_name.tracker_local_endpoint.num_peers)
QHash<lt::torrent_handle, QHash<std::string, QMap<TrackerEntry::Endpoint, int>>> m_updatedTrackerEntries;
QHash<lt::torrent_handle, QHash<std::string, QHash<TrackerEntry::Endpoint, int>>> m_updatedTrackerEntries;
// I/O errored torrents
QSet<TorrentID> m_recentErroredTorrents;

View File

@@ -80,16 +80,26 @@ namespace
#ifdef QBT_USES_LIBTORRENT2
void updateTrackerEntry(TrackerEntry &trackerEntry, const lt::announce_entry &nativeEntry
, const lt::info_hash_t &hashes, const QMap<TrackerEntry::Endpoint, int> &updateInfo)
, const lt::info_hash_t &hashes, const QHash<TrackerEntry::Endpoint, int> &updateInfo)
#else
void updateTrackerEntry(TrackerEntry &trackerEntry, const lt::announce_entry &nativeEntry
, const QMap<TrackerEntry::Endpoint, int> &updateInfo)
, const QHash<TrackerEntry::Endpoint, int> &updateInfo)
#endif
{
Q_ASSERT(trackerEntry.url == QString::fromStdString(nativeEntry.url));
trackerEntry.tier = nativeEntry.tier;
// remove outdated endpoints
trackerEntry.stats.removeIf([&nativeEntry](const decltype(trackerEntry.stats)::iterator &iter)
{
return std::none_of(nativeEntry.endpoints.cbegin(), nativeEntry.endpoints.cend()
, [&endpoint = iter.key()](const auto &existingEndpoint)
{
return (endpoint == existingEndpoint.local_endpoint);
});
});
int numUpdating = 0;
int numWorking = 0;
int numNotWorking = 0;
@@ -99,13 +109,17 @@ namespace
const auto numEndpoints = static_cast<qsizetype>(nativeEntry.endpoints.size()) * ((hashes.has_v1() && hashes.has_v2()) ? 2 : 1);
for (const lt::announce_endpoint &endpoint : nativeEntry.endpoints)
{
const auto endpointName = QString::fromStdString((std::stringstream() << endpoint.local_endpoint).str());
for (const auto protocolVersion : {lt::protocol_version::V1, lt::protocol_version::V2})
{
if (hashes.has(protocolVersion))
{
const lt::announce_infohash &infoHash = endpoint.info_hashes[protocolVersion];
TrackerEntry::EndpointStats trackerEndpoint;
TrackerEntry::EndpointStats &trackerEndpoint = trackerEntry.stats[endpoint.local_endpoint][(protocolVersion == lt::protocol_version::V1) ? 1 : 2];
trackerEndpoint.name = endpointName;
trackerEndpoint.numPeers = updateInfo.value(endpoint.local_endpoint, trackerEndpoint.numPeers);
trackerEndpoint.numSeeds = infoHash.scrape_complete;
trackerEndpoint.numLeeches = infoHash.scrape_incomplete;
@@ -131,20 +145,18 @@ namespace
trackerEndpoint.status = TrackerEntry::NotContacted;
}
const QString trackerMessage = QString::fromStdString(infoHash.message);
const QString errorMessage = QString::fromLocal8Bit(infoHash.last_error.message().c_str());
trackerEndpoint.message = (!trackerMessage.isEmpty() ? trackerMessage : errorMessage);
trackerEntry.stats[endpoint.local_endpoint][(protocolVersion == lt::protocol_version::V1) ? 1 : 2] = trackerEndpoint;
trackerEntry.numPeers = std::max(trackerEntry.numPeers, trackerEndpoint.numPeers);
trackerEntry.numSeeds = std::max(trackerEntry.numSeeds, trackerEndpoint.numSeeds);
trackerEntry.numLeeches = std::max(trackerEntry.numLeeches, trackerEndpoint.numLeeches);
trackerEntry.numDownloaded = std::max(trackerEntry.numDownloaded, trackerEndpoint.numDownloaded);
if (firstTrackerMessage.isEmpty())
firstTrackerMessage = trackerMessage;
if (firstErrorMessage.isEmpty())
firstErrorMessage = errorMessage;
if (!infoHash.message.empty())
{
trackerEndpoint.message = QString::fromStdString(infoHash.message);
if (firstTrackerMessage.isEmpty())
firstTrackerMessage = trackerEndpoint.message;
}
else if (infoHash.last_error)
{
trackerEndpoint.message = QString::fromLocal8Bit(infoHash.last_error.message());
if (firstErrorMessage.isEmpty())
firstErrorMessage = trackerEndpoint.message;
}
}
}
}
@@ -152,7 +164,9 @@ namespace
const auto numEndpoints = static_cast<qsizetype>(nativeEntry.endpoints.size());
for (const lt::announce_endpoint &endpoint : nativeEntry.endpoints)
{
TrackerEntry::EndpointStats trackerEndpoint;
TrackerEntry::EndpointStats &trackerEndpoint = trackerEntry.stats[endpoint.local_endpoint][1];
trackerEndpoint.name = QString::fromStdString((std::stringstream() << endpoint.local_endpoint).str());
trackerEndpoint.numPeers = updateInfo.value(endpoint.local_endpoint, trackerEndpoint.numPeers);
trackerEndpoint.numSeeds = endpoint.scrape_complete;
trackerEndpoint.numLeeches = endpoint.scrape_incomplete;
@@ -178,20 +192,18 @@ namespace
trackerEndpoint.status = TrackerEntry::NotContacted;
}
const QString trackerMessage = QString::fromStdString(endpoint.message);
const QString errorMessage = QString::fromLocal8Bit(endpoint.last_error.message().c_str());
trackerEndpoint.message = (!trackerMessage.isEmpty() ? trackerMessage : errorMessage);
trackerEntry.stats[endpoint.local_endpoint][1] = trackerEndpoint;
trackerEntry.numPeers = std::max(trackerEntry.numPeers, trackerEndpoint.numPeers);
trackerEntry.numSeeds = std::max(trackerEntry.numSeeds, trackerEndpoint.numSeeds);
trackerEntry.numLeeches = std::max(trackerEntry.numLeeches, trackerEndpoint.numLeeches);
trackerEntry.numDownloaded = std::max(trackerEntry.numDownloaded, trackerEndpoint.numDownloaded);
if (firstTrackerMessage.isEmpty())
firstTrackerMessage = trackerMessage;
if (firstErrorMessage.isEmpty())
firstErrorMessage = errorMessage;
if (!endpoint.message.empty())
{
trackerEndpoint.message = QString::fromStdString(endpoint.message);
if (firstTrackerMessage.isEmpty())
firstTrackerMessage = trackerEndpoint.message;
}
else if (endpoint.last_error)
{
trackerEndpoint.message = QString::fromLocal8Bit(endpoint.last_error.message());
if (firstErrorMessage.isEmpty())
firstErrorMessage = trackerEndpoint.message;
}
}
#endif
@@ -1603,7 +1615,7 @@ void TorrentImpl::fileSearchFinished(const Path &savePath, const PathList &fileN
endReceivedMetadataHandling(savePath, fileNames);
}
TrackerEntry TorrentImpl::updateTrackerEntry(const lt::announce_entry &announceEntry, const QMap<TrackerEntry::Endpoint, int> &updateInfo)
TrackerEntry TorrentImpl::updateTrackerEntry(const lt::announce_entry &announceEntry, const QHash<TrackerEntry::Endpoint, int> &updateInfo)
{
const auto it = std::find_if(m_trackerEntries.begin(), m_trackerEntries.end()
, [&announceEntry](const TrackerEntry &trackerEntry)

View File

@@ -264,7 +264,7 @@ namespace BitTorrent
void saveResumeData(lt::resume_data_flags_t flags = {});
void handleMoveStorageJobFinished(const Path &path, MoveStorageContext context, bool hasOutstandingJob);
void fileSearchFinished(const Path &savePath, const PathList &fileNames);
TrackerEntry updateTrackerEntry(const lt::announce_entry &announceEntry, const QMap<TrackerEntry::Endpoint, int> &updateInfo);
TrackerEntry updateTrackerEntry(const lt::announce_entry &announceEntry, const QHash<TrackerEntry::Endpoint, int> &updateInfo);
private:
using EventTrigger = std::function<void ()>;

View File

@@ -57,20 +57,15 @@ namespace BitTorrent
int numLeeches = -1;
int numDownloaded = -1;
QString message {};
QString name {};
};
QString url {};
int tier = 0;
Status status = NotContacted;
QString message {};
QHash<Endpoint, QHash<int, EndpointStats>> stats {};
// Deprecated fields
Status status = NotContacted;
int numPeers = -1;
int numSeeds = -1;
int numLeeches = -1;
int numDownloaded = -1;
QString message {};
};
QVector<TrackerEntry> parseTrackerEntries(QStringView str);