Improve tracker status handling

PR #16383.
This commit is contained in:
Vladimir Golovnev
2022-02-09 18:23:41 +03:00
committed by GitHub
parent dd1bd8ad10
commit 4a7f1116ac
7 changed files with 222 additions and 168 deletions

View File

@@ -291,6 +291,67 @@ namespace
return {};
}
#endif
#ifdef QBT_USES_LIBTORRENT2
TrackerEntryUpdateInfo getTrackerEntryUpdateInfo(const lt::announce_entry &nativeEntry, const lt::info_hash_t &hashes)
#else
TrackerEntryUpdateInfo getTrackerEntryUpdateInfo(const lt::announce_entry &nativeEntry)
#endif
{
TrackerEntryUpdateInfo result {};
int numUpdating = 0;
int numWorking = 0;
int numNotWorking = 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 auto protocolVersion : {lt::protocol_version::V1, lt::protocol_version::V2})
{
if (hashes.has(protocolVersion))
{
const lt::announce_infohash &infoHash = endpoint.info_hashes[protocolVersion];
if (!result.hasMessages)
result.hasMessages = !infoHash.message.empty();
if (infoHash.updating)
++numUpdating;
else if (infoHash.fails > 0)
++numNotWorking;
else if (nativeEntry.verified)
++numWorking;
}
}
}
#else
const auto numEndpoints = static_cast<qsizetype>(nativeEntry.endpoints.size());
for (const lt::announce_endpoint &endpoint : nativeEntry.endpoints)
{
if (!result.hasMessages)
result.hasMessages = !endpoint.message.empty();
if (endpoint.updating)
++numUpdating;
else if (endpoint.fails > 0)
++numNotWorking;
else if (nativeEntry.verified)
++numWorking;
}
#endif
if (numEndpoints > 0)
{
if (numUpdating > 0)
result.status = TrackerEntry::Updating;
else if (numWorking > 0)
result.status = TrackerEntry::Working;
else if (numNotWorking == numEndpoints)
result.status = TrackerEntry::NotWorking;
}
return result;
}
}
const int addTorrentParamsId = qRegisterMetaType<AddTorrentParams>();
@@ -4033,16 +4094,6 @@ void Session::handleTorrentResumeDataReady(TorrentImpl *const torrent, const Loa
m_resumeDataStorage->store(torrent->id(), data);
}
void Session::handleTorrentTrackerReply(TorrentImpl *const torrent, const QString &trackerUrl)
{
emit trackerSuccess(torrent, trackerUrl);
}
void Session::handleTorrentTrackerError(TorrentImpl *const torrent, const QString &trackerUrl)
{
emit trackerError(torrent, trackerUrl);
}
bool Session::addMoveTorrentStorageJob(TorrentImpl *torrent, const Path &newPath, const MoveStorageMode mode)
{
Q_ASSERT(torrent);
@@ -4233,11 +4284,6 @@ void Session::loadCategories()
}
}
void Session::handleTorrentTrackerWarning(TorrentImpl *const torrent, const QString &trackerUrl)
{
emit trackerWarning(torrent, trackerUrl);
}
bool Session::hasPerTorrentRatioLimit() const
{
return std::any_of(m_torrents.cbegin(), m_torrents.cend(), [](const TorrentImpl *torrent)
@@ -4562,6 +4608,8 @@ void Session::readAlerts()
const std::vector<lt::alert *> alerts = getPendingAlerts();
for (const lt::alert *a : alerts)
handleAlert(a);
processTrackerStatuses();
}
void Session::handleAlert(const lt::alert *a)
@@ -4581,9 +4629,6 @@ void Session::handleAlert(const lt::alert *a)
case lt::save_resume_data_failed_alert::alert_type:
case lt::torrent_paused_alert::alert_type:
case lt::torrent_resumed_alert::alert_type:
case lt::tracker_error_alert::alert_type:
case lt::tracker_reply_alert::alert_type:
case lt::tracker_warning_alert::alert_type:
case lt::fastresume_rejected_alert::alert_type:
case lt::torrent_checked_alert::alert_type:
case lt::metadata_received_alert::alert_type:
@@ -4596,6 +4641,11 @@ void Session::handleAlert(const lt::alert *a)
case lt::session_stats_alert::alert_type:
handleSessionStatsAlert(static_cast<const lt::session_stats_alert*>(a));
break;
case lt::tracker_error_alert::alert_type:
case lt::tracker_reply_alert::alert_type:
case lt::tracker_warning_alert::alert_type:
handleTrackerAlert(static_cast<const lt::tracker_alert *>(a));
break;
case lt::file_error_alert::alert_type:
handleFileErrorAlert(static_cast<const lt::file_error_alert*>(a));
break;
@@ -5133,3 +5183,50 @@ void Session::handleSocks5Alert(const lt::socks5_alert *p) const
, Log::WARNING);
}
}
void Session::handleTrackerAlert(const lt::tracker_alert *a)
{
TorrentImpl *torrent = m_torrents.value(a->handle.info_hash());
if (!torrent)
return;
const QByteArray trackerURL {a->tracker_url()};
m_updatedTrackerEntries[torrent].insert(trackerURL);
if (a->type() == lt::tracker_reply_alert::alert_type)
{
const int numPeers = static_cast<const lt::tracker_reply_alert *>(a)->num_peers;
torrent->updatePeerCount(trackerURL, a->local_endpoint, numPeers);
}
}
void Session::processTrackerStatuses()
{
QHash<Torrent *, QHash<QString, TrackerEntryUpdateInfo>> updateInfos;
for (auto it = m_updatedTrackerEntries.cbegin(); it != m_updatedTrackerEntries.cend(); ++it)
{
TorrentImpl *torrent = it.key();
const QSet<QByteArray> &updatedTrackers = it.value();
const std::vector<lt::announce_entry> trackerList = torrent->nativeHandle().trackers();
for (const lt::announce_entry &announceEntry : trackerList)
{
const auto trackerURL = QByteArray::fromRawData(announceEntry.url.c_str(), announceEntry.url.size());
if (!updatedTrackers.contains(trackerURL))
continue;
#ifdef QBT_USES_LIBTORRENT2
const TrackerEntryUpdateInfo updateInfo = getTrackerEntryUpdateInfo(announceEntry, torrent->nativeHandle().info_hashes());
#else
const TrackerEntryUpdateInfo updateInfo = getTrackerEntryUpdateInfo(announceEntry);
#endif
if ((updateInfo.status == TrackerEntry::Working) || (updateInfo.status == TrackerEntry::NotWorking))
updateInfos[torrent][QString::fromUtf8(trackerURL)] = updateInfo;
}
}
m_updatedTrackerEntries.clear();
if (!updateInfos.isEmpty())
emit trackerEntriesUpdated(updateInfos);
}

View File

@@ -203,6 +203,12 @@ namespace BitTorrent
} disk;
};
struct TrackerEntryUpdateInfo
{
TrackerEntry::Status status = TrackerEntry::NotContacted;
bool hasMessages = false;
};
class Session final : public QObject
{
Q_OBJECT
@@ -498,9 +504,6 @@ namespace BitTorrent
void handleTorrentUrlSeedsAdded(TorrentImpl *const torrent, const QVector<QUrl> &newUrlSeeds);
void handleTorrentUrlSeedsRemoved(TorrentImpl *const torrent, const QVector<QUrl> &urlSeeds);
void handleTorrentResumeDataReady(TorrentImpl *const torrent, const LoadTorrentParams &data);
void handleTorrentTrackerReply(TorrentImpl *const torrent, const QString &trackerUrl);
void handleTorrentTrackerWarning(TorrentImpl *const torrent, const QString &trackerUrl);
void handleTorrentTrackerError(TorrentImpl *const torrent, const QString &trackerUrl);
bool addMoveTorrentStorageJob(TorrentImpl *torrent, const Path &newPath, MoveStorageMode mode);
@@ -544,6 +547,7 @@ namespace BitTorrent
void trackersRemoved(Torrent *torrent, const QVector<TrackerEntry> &trackers);
void trackerSuccess(Torrent *torrent, const QString &tracker);
void trackerWarning(Torrent *torrent, const QString &tracker);
void trackerEntriesUpdated(const QHash<Torrent *, QHash<QString, TrackerEntryUpdateInfo>> &updateInfos);
private slots:
void configureDeferred();
@@ -606,6 +610,7 @@ namespace BitTorrent
#if defined(Q_OS_WIN)
void applyOSMemoryPriority() const;
#endif
void processTrackerStatuses();
bool loadTorrent(LoadTorrentParams params);
LoadTorrentParams initLoadTorrentParams(const AddTorrentParams &addTorrentParams);
@@ -636,6 +641,7 @@ namespace BitTorrent
void handleStorageMovedAlert(const lt::storage_moved_alert *p);
void handleStorageMovedFailedAlert(const lt::storage_moved_failed_alert *p);
void handleSocks5Alert(const lt::socks5_alert *p) const;
void handleTrackerAlert(const lt::tracker_alert *a);
void createTorrent(const lt::torrent_handle &nativeHandle);
@@ -793,6 +799,8 @@ namespace BitTorrent
QMap<QString, CategoryOptions> m_categories;
QSet<QString> m_tags;
QHash<TorrentImpl *, QSet<QByteArray>> m_updatedTrackerEntries;
// I/O errored torrents
QSet<TorrentID> m_recentErroredTorrents;
QTimer *m_recentErroredTorrentsTimer = nullptr;

View File

@@ -69,7 +69,7 @@ using namespace BitTorrent;
namespace
{
lt::announce_entry makeNativeAnnouncerEntry(const QString &url, const int tier)
lt::announce_entry makeNativeAnnounceEntry(const QString &url, const int tier)
{
lt::announce_entry entry {url.toStdString()};
entry.tier = tier;
@@ -536,7 +536,7 @@ void TorrentImpl::addTrackers(const QVector<TrackerEntry> &trackers)
{
if (!currentTrackers.contains(tracker))
{
m_nativeHandle.add_tracker(makeNativeAnnouncerEntry(tracker.url, tracker.tier));
m_nativeHandle.add_tracker(makeNativeAnnounceEntry(tracker.url, tracker.tier));
newTrackers << tracker;
}
}
@@ -560,7 +560,7 @@ void TorrentImpl::replaceTrackers(const QVector<TrackerEntry> &trackers)
for (const TrackerEntry &tracker : trackers)
{
nativeTrackers.emplace_back(makeNativeAnnouncerEntry(tracker.url, tracker.tier));
nativeTrackers.emplace_back(makeNativeAnnounceEntry(tracker.url, tracker.tier));
if (!currentTrackers.removeOne(tracker))
newTrackers << tracker;
@@ -1484,6 +1484,11 @@ void TorrentImpl::fileSearchFinished(const Path &savePath, const PathList &fileN
endReceivedMetadataHandling(savePath, fileNames);
}
void TorrentImpl::updatePeerCount(const QString &trackerUrl, const lt::tcp::endpoint &endpoint, const int count)
{
m_trackerPeerCounts[trackerUrl][endpoint] = count;
}
void TorrentImpl::endReceivedMetadataHandling(const Path &savePath, const PathList &fileNames)
{
Q_ASSERT(m_filePaths.isEmpty());
@@ -1665,46 +1670,6 @@ void TorrentImpl::handleMoveStorageJobFinished(const bool hasOutstandingJob)
}
}
void TorrentImpl::handleTrackerReplyAlert(const lt::tracker_reply_alert *p)
{
const QString trackerUrl = p->tracker_url();
m_trackerPeerCounts[trackerUrl][p->local_endpoint] = p->num_peers;
m_session->handleTorrentTrackerReply(this, trackerUrl);
}
void TorrentImpl::handleTrackerWarningAlert(const lt::tracker_warning_alert *p)
{
const QString trackerUrl = p->tracker_url();
m_session->handleTorrentTrackerWarning(this, trackerUrl);
}
void TorrentImpl::handleTrackerErrorAlert(const lt::tracker_error_alert *p)
{
// Starting with libtorrent 1.2.x each tracker has multiple local endpoints from which
// an announce is attempted. Some endpoints might succeed while others might fail.
// Emit the signal only if all endpoints have failed.
const std::vector<lt::announce_entry> trackerList = m_nativeHandle.trackers();
const auto iter = std::find_if(trackerList.cbegin(), trackerList.cend(), [p](const lt::announce_entry &entry)
{
return (entry.url == p->tracker_url());
});
if (iter == trackerList.cend())
return;
const QString trackerURL = QString::fromStdString(iter->url);
#ifdef QBT_USES_LIBTORRENT2
const TrackerEntry entry = fromNativeAnnounceEntry(*iter, m_nativeHandle.info_hashes(), m_trackerPeerCounts[trackerURL]);
#else
const TrackerEntry entry = fromNativeAnnounceEntry(*iter, m_trackerPeerCounts[trackerURL]);
#endif
if (entry.status == TrackerEntry::NotWorking)
m_session->handleTorrentTrackerError(this, trackerURL);
}
void TorrentImpl::handleTorrentCheckedAlert(const lt::torrent_checked_alert *p)
{
Q_UNUSED(p);
@@ -2014,15 +1979,6 @@ void TorrentImpl::handleAlert(const lt::alert *a)
case lt::torrent_resumed_alert::alert_type:
handleTorrentResumedAlert(static_cast<const lt::torrent_resumed_alert*>(a));
break;
case lt::tracker_error_alert::alert_type:
handleTrackerErrorAlert(static_cast<const lt::tracker_error_alert*>(a));
break;
case lt::tracker_reply_alert::alert_type:
handleTrackerReplyAlert(static_cast<const lt::tracker_reply_alert*>(a));
break;
case lt::tracker_warning_alert::alert_type:
handleTrackerWarningAlert(static_cast<const lt::tracker_warning_alert*>(a));
break;
case lt::metadata_received_alert::alert_type:
handleMetadataReceivedAlert(static_cast<const lt::metadata_received_alert*>(a));
break;

View File

@@ -239,6 +239,7 @@ namespace BitTorrent
void saveResumeData();
void handleMoveStorageJobFinished(bool hasOutstandingJob);
void fileSearchFinished(const Path &savePath, const PathList &fileNames);
void updatePeerCount(const QString &trackerUrl, const lt::tcp::endpoint &endpoint, int count);
private:
using EventTrigger = std::function<void ()>;
@@ -263,9 +264,6 @@ namespace BitTorrent
void handleTorrentFinishedAlert(const lt::torrent_finished_alert *p);
void handleTorrentPausedAlert(const lt::torrent_paused_alert *p);
void handleTorrentResumedAlert(const lt::torrent_resumed_alert *p);
void handleTrackerErrorAlert(const lt::tracker_error_alert *p);
void handleTrackerReplyAlert(const lt::tracker_reply_alert *p);
void handleTrackerWarningAlert(const lt::tracker_warning_alert *p);
bool isMoveInProgress() const;