Skip to content

Commit

Permalink
Revamp tracker list widget
Browse files Browse the repository at this point in the history
  • Loading branch information
glassez committed Oct 1, 2023
1 parent 1611149 commit 76bf22a
Show file tree
Hide file tree
Showing 30 changed files with 1,784 additions and 1,104 deletions.
4 changes: 1 addition & 3 deletions src/base/bittorrent/sessionimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4815,15 +4815,13 @@ void SessionImpl::handleTorrentTrackersAdded(TorrentImpl *const torrent, const Q
for (const TrackerEntry &newTracker : newTrackers)
LogMsg(tr("Added tracker to torrent. Torrent: \"%1\". Tracker: \"%2\"").arg(torrent->name(), newTracker.url));
emit trackersAdded(torrent, newTrackers);
emit trackersChanged(torrent);
}

void SessionImpl::handleTorrentTrackersRemoved(TorrentImpl *const torrent, const QStringList &deletedTrackers)
{
for (const QString &deletedTracker : deletedTrackers)
LogMsg(tr("Removed tracker from torrent. Torrent: \"%1\". Tracker: \"%2\"").arg(torrent->name(), deletedTracker));
emit trackersRemoved(torrent, deletedTrackers);
emit trackersChanged(torrent);
}

void SessionImpl::handleTorrentTrackersChanged(TorrentImpl *const torrent)
Expand Down Expand Up @@ -6036,7 +6034,7 @@ void SessionImpl::loadStatistics()
m_previouslyUploaded = value[u"AlltimeUL"_s].toLongLong();
}

void SessionImpl::updateTrackerEntries(lt::torrent_handle torrentHandle, QHash<std::string, QHash<TrackerEntry::Endpoint, QMap<int, int>>> updatedTrackers)
void SessionImpl::updateTrackerEntries(lt::torrent_handle torrentHandle, QHash<std::string, QHash<lt::tcp::endpoint, QMap<int, int>>> updatedTrackers)
{
invokeAsync([this, torrentHandle = std::move(torrentHandle), updatedTrackers = std::move(updatedTrackers)]() mutable
{
Expand Down
4 changes: 2 additions & 2 deletions src/base/bittorrent/sessionimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@ namespace BitTorrent
void saveStatistics() const;
void loadStatistics();

void updateTrackerEntries(lt::torrent_handle torrentHandle, QHash<std::string, QHash<TrackerEntry::Endpoint, QMap<int, int>>> updatedTrackers);
void updateTrackerEntries(lt::torrent_handle torrentHandle, QHash<std::string, QHash<lt::tcp::endpoint, QMap<int, int>>> updatedTrackers);

// BitTorrent
lt::session *m_nativeSession = nullptr;
Expand Down Expand Up @@ -751,7 +751,7 @@ namespace BitTorrent

// This field holds amounts of peers reported by trackers in their responses to announces
// (torrent.tracker_name.tracker_local_endpoint.protocol_version.num_peers)
QHash<lt::torrent_handle, QHash<std::string, QHash<TrackerEntry::Endpoint, QMap<int, int>>>> m_updatedTrackerEntries;
QHash<lt::torrent_handle, QHash<std::string, QHash<lt::tcp::endpoint, QMap<int, int>>>> m_updatedTrackerEntries;

// I/O errored torrents
QSet<TorrentID> m_recentErroredTorrents;
Expand Down
5 changes: 4 additions & 1 deletion src/base/bittorrent/torrent.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015-2022 Vladimir Golovnev <[email protected]>
* Copyright (C) 2015-2023 Vladimir Golovnev <[email protected]>
* Copyright (C) 2006 Christophe Dumez <[email protected]>
*
* This program is free software; you can redistribute it and/or
Expand Down Expand Up @@ -49,6 +49,7 @@ namespace BitTorrent
enum class DownloadPriority;
class InfoHash;
class PeerInfo;
class Session;
class TorrentID;
class TorrentInfo;
struct PeerAddress;
Expand Down Expand Up @@ -131,6 +132,8 @@ namespace BitTorrent

using TorrentContentHandler::TorrentContentHandler;

virtual Session *session() const = 0;

virtual InfoHash infoHash() const = 0;
virtual QString name() const = 0;
virtual QDateTime creationDate() const = 0;
Expand Down
222 changes: 105 additions & 117 deletions src/base/bittorrent/torrentimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,190 +87,167 @@ namespace
return qNow.addSecs(secsSinceNow);
}

#ifdef QBT_USES_LIBTORRENT2
void updateTrackerEntry(TrackerEntry &trackerEntry, const lt::announce_entry &nativeEntry
, const lt::info_hash_t &hashes, const QHash<TrackerEntry::Endpoint, QMap<int, int>> &updateInfo)
#else
QString toString(const lt::tcp::endpoint &ltTCPEndpoint)
{
return QString::fromStdString((std::stringstream() << ltTCPEndpoint).str());
}

void updateTrackerEntry(TrackerEntry &trackerEntry, const lt::announce_entry &nativeEntry
, const QHash<TrackerEntry::Endpoint, QMap<int, int>> &updateInfo)
#endif
, const QSet<int> &btProtocols, const QHash<lt::tcp::endpoint, QMap<int, int>> &updateInfo)
{
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)
trackerEntry.endpointEntries.removeIf([&nativeEntry](const QHash<std::pair<QString, int>, TrackerEndpointEntry>::iterator &iter)
{
return std::none_of(nativeEntry.endpoints.cbegin(), nativeEntry.endpoints.cend()
, [&endpoint = iter.key()](const auto &existingEndpoint)
, [&endpointName = std::get<0>(iter.key())](const auto &existingEndpoint)
{
return (endpoint == existingEndpoint.local_endpoint);
return (endpointName == toString(existingEndpoint.local_endpoint));
});
});

const auto numEndpoints = static_cast<qsizetype>(nativeEntry.endpoints.size()) * btProtocols.size();

int numUpdating = 0;
int numWorking = 0;
int numNotWorking = 0;
int numTrackerError = 0;
int numUnreachable = 0;
#ifdef QBT_USES_LIBTORRENT2
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)

for (const lt::announce_endpoint &ltAnnounceEndpoint : nativeEntry.endpoints)
{
const auto endpointName = QString::fromStdString((std::stringstream() << endpoint.local_endpoint).str());
const auto endpointName = toString(ltAnnounceEndpoint.local_endpoint);

for (const auto protocolVersion : {lt::protocol_version::V1, lt::protocol_version::V2})
for (const auto protocolVersion : btProtocols)
{
if (!hashes.has(protocolVersion))
continue;

const lt::announce_infohash &infoHash = endpoint.info_hashes[protocolVersion];

const int protocolVersionNum = (protocolVersion == lt::protocol_version::V1) ? 1 : 2;
const QMap<int, int> &endpointUpdateInfo = updateInfo[endpoint.local_endpoint];
TrackerEntry::EndpointStats &trackerEndpoint = trackerEntry.stats[endpoint.local_endpoint][protocolVersionNum];

trackerEndpoint.name = endpointName;
trackerEndpoint.numPeers = endpointUpdateInfo.value(protocolVersionNum, trackerEndpoint.numPeers);
trackerEndpoint.numSeeds = infoHash.scrape_complete;
trackerEndpoint.numLeeches = infoHash.scrape_incomplete;
trackerEndpoint.numDownloaded = infoHash.scrape_downloaded;
trackerEndpoint.nextAnnounceTime = fromLTTimePoint32(infoHash.next_announce);
trackerEndpoint.minAnnounceTime = fromLTTimePoint32(infoHash.min_announce);

if (infoHash.updating)
#ifdef QBT_USES_LIBTORRENT2
Q_ASSERT((protocolVersion == 1) || (protocolVersion == 2));
const auto ltProtocolVersion = (protocolVersion == 1) ? lt::protocol_version::V1 : lt::protocol_version::V2;
const lt::announce_infohash &ltAnnounceInfo = ltAnnounceEndpoint.info_hashes[ltProtocolVersion];
#else
Q_ASSERT(protocolVersion == 1);
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)];

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);

if (ltAnnounceInfo.updating)
{
trackerEndpoint.status = TrackerEntry::Updating;
trackerEndpointEntry.status = TrackerEntryStatus::Updating;
++numUpdating;
}
else if (infoHash.fails > 0)
else if (ltAnnounceInfo.fails > 0)
{
if (infoHash.last_error == lt::errors::tracker_failure)
if (ltAnnounceInfo.last_error == lt::errors::tracker_failure)
{
trackerEndpoint.status = TrackerEntry::TrackerError;
trackerEndpointEntry.status = TrackerEntryStatus::TrackerError;
++numTrackerError;
}
else if (infoHash.last_error == lt::errors::announce_skipped)
else if (ltAnnounceInfo.last_error == lt::errors::announce_skipped)
{
trackerEndpoint.status = TrackerEntry::Unreachable;
trackerEndpointEntry.status = TrackerEntryStatus::Unreachable;
++numUnreachable;
}
else
{
trackerEndpoint.status = TrackerEntry::NotWorking;
trackerEndpointEntry.status = TrackerEntryStatus::NotWorking;
++numNotWorking;
}
}
else if (nativeEntry.verified)
{
trackerEndpoint.status = TrackerEntry::Working;
trackerEndpointEntry.status = TrackerEntryStatus::Working;
++numWorking;
}
else
{
trackerEndpoint.status = TrackerEntry::NotContacted;
trackerEndpointEntry.status = TrackerEntryStatus::NotContacted;
}

if (!infoHash.message.empty())
{
trackerEndpoint.message = QString::fromStdString(infoHash.message);
}
else if (infoHash.last_error)
{
trackerEndpoint.message = QString::fromLocal8Bit(infoHash.last_error.message());
}
else
{
trackerEndpoint.message.clear();
}
}
}
#else
const auto numEndpoints = static_cast<qsizetype>(nativeEntry.endpoints.size());
for (const lt::announce_endpoint &endpoint : nativeEntry.endpoints)
{
const int protocolVersionNum = 1;
const QMap<int, int> &endpointUpdateInfo = updateInfo[endpoint.local_endpoint];
TrackerEntry::EndpointStats &trackerEndpoint = trackerEntry.stats[endpoint.local_endpoint][protocolVersionNum];

trackerEndpoint.name = QString::fromStdString((std::stringstream() << endpoint.local_endpoint).str());
trackerEndpoint.numPeers = endpointUpdateInfo.value(protocolVersionNum, trackerEndpoint.numPeers);
trackerEndpoint.numSeeds = endpoint.scrape_complete;
trackerEndpoint.numLeeches = endpoint.scrape_incomplete;
trackerEndpoint.numDownloaded = endpoint.scrape_downloaded;
trackerEndpoint.nextAnnounceTime = fromLTTimePoint32(endpoint.next_announce);
trackerEndpoint.minAnnounceTime = fromLTTimePoint32(endpoint.min_announce);

if (endpoint.updating)
{
trackerEndpoint.status = TrackerEntry::Updating;
++numUpdating;
}
else if (endpoint.fails > 0)
{
if (endpoint.last_error == lt::errors::tracker_failure)
if (!ltAnnounceInfo.message.empty())
{
trackerEndpoint.status = TrackerEntry::TrackerError;
++numTrackerError;
trackerEndpointEntry.message = QString::fromStdString(ltAnnounceInfo.message);
}
else if (endpoint.last_error == lt::errors::announce_skipped)
else if (ltAnnounceInfo.last_error)
{
trackerEndpoint.status = TrackerEntry::Unreachable;
++numUnreachable;
trackerEndpointEntry.message = QString::fromLocal8Bit(ltAnnounceInfo.last_error.message());
}
else
{
trackerEndpoint.status = TrackerEntry::NotWorking;
++numNotWorking;
trackerEndpointEntry.message.clear();
}
}
else if (nativeEntry.verified)
{
trackerEndpoint.status = TrackerEntry::Working;
++numWorking;
}
else
{
trackerEndpoint.status = TrackerEntry::NotContacted;
}

if (!endpoint.message.empty())
{
trackerEndpoint.message = QString::fromStdString(endpoint.message);
}
else if (endpoint.last_error)
{
trackerEndpoint.message = QString::fromLocal8Bit(endpoint.last_error.message());
}
else
{
trackerEndpoint.message.clear();
}
}
#endif

if (numEndpoints > 0)
{
if (numUpdating > 0)
{
trackerEntry.status = TrackerEntry::Updating;
trackerEntry.status = TrackerEntryStatus::Updating;
}
else if (numWorking > 0)
{
trackerEntry.status = TrackerEntry::Working;
trackerEntry.status = TrackerEntryStatus::Working;
}
else if (numTrackerError > 0)
{
trackerEntry.status = TrackerEntry::TrackerError;
trackerEntry.status = TrackerEntryStatus::TrackerError;
}
else if (numUnreachable == numEndpoints)
{
trackerEntry.status = TrackerEntry::Unreachable;
trackerEntry.status = TrackerEntryStatus::Unreachable;
}
else if ((numUnreachable + numNotWorking) == numEndpoints)
{
trackerEntry.status = TrackerEntry::NotWorking;
trackerEntry.status = TrackerEntryStatus::NotWorking;
}
}

trackerEntry.numPeers = -1;
trackerEntry.numSeeds = -1;
trackerEntry.numLeeches = -1;
trackerEntry.numDownloaded = -1;
trackerEntry.nextAnnounceTime = QDateTime();
trackerEntry.minAnnounceTime = QDateTime();
trackerEntry.message.clear();

for (const TrackerEndpointEntry &endpointEntry : asConst(trackerEntry.endpointEntries))
{
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);

if (endpointEntry.status == trackerEntry.status)
{
if (!trackerEntry.nextAnnounceTime.isValid() || (trackerEntry.nextAnnounceTime > endpointEntry.nextAnnounceTime))
{
trackerEntry.nextAnnounceTime = endpointEntry.nextAnnounceTime;
trackerEntry.minAnnounceTime = endpointEntry.minAnnounceTime;
if ((endpointEntry.status != TrackerEntryStatus::Working)
|| !endpointEntry.message.isEmpty())
{
trackerEntry.message = endpointEntry.message;
}
}

if (endpointEntry.status == TrackerEntryStatus::Working)
{
if (trackerEntry.message.isEmpty())
trackerEntry.message = endpointEntry.message;
}
}
}
}
Expand Down Expand Up @@ -405,6 +382,11 @@ bool TorrentImpl::isValid() const
return m_nativeHandle.is_valid();
}

Session *TorrentImpl::session() const
{
return m_session;
}

InfoHash TorrentImpl::infoHash() const
{
return m_infoHash;
Expand Down Expand Up @@ -1667,7 +1649,7 @@ void TorrentImpl::fileSearchFinished(const Path &savePath, const PathList &fileN
endReceivedMetadataHandling(savePath, fileNames);
}

TrackerEntry TorrentImpl::updateTrackerEntry(const lt::announce_entry &announceEntry, const QHash<TrackerEntry::Endpoint, QMap<int, int>> &updateInfo)
TrackerEntry TorrentImpl::updateTrackerEntry(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)
Expand All @@ -1680,10 +1662,16 @@ TrackerEntry TorrentImpl::updateTrackerEntry(const lt::announce_entry &announceE
return {};

#ifdef QBT_USES_LIBTORRENT2
::updateTrackerEntry(*it, announceEntry, nativeHandle().info_hashes(), updateInfo);
QSet<int> btProtocols;
const auto &infoHashes = nativeHandle().info_hashes();
if (infoHashes.has(lt::protocol_version::V1))
btProtocols.insert(1);
if (infoHashes.has(lt::protocol_version::V2))
btProtocols.insert(2);
#else
::updateTrackerEntry(*it, announceEntry, updateInfo);
const QSet<int> btProtocols {1};
#endif
::updateTrackerEntry(*it, announceEntry, btProtocols, updateInfo);
return *it;
}

Expand Down
Loading

0 comments on commit 76bf22a

Please sign in to comment.