Improve tracker entries handling

This commit is contained in:
Vladimir Golovnev (Glassez)
2021-03-01 16:06:08 +03:00
committed by sledgehammer999
parent 726455ac3e
commit b2c7d8211f
17 changed files with 194 additions and 215 deletions

View File

@@ -78,7 +78,7 @@ MagnetUri::MagnetUri(const QString &source)
m_trackers.reserve(m_addTorrentParams.trackers.size());
for (const std::string &tracker : m_addTorrentParams.trackers)
m_trackers.append(lt::announce_entry {tracker});
m_trackers.append({QString::fromStdString(tracker)});
m_urlSeeds.reserve(m_addTorrentParams.url_seeds.size());
for (const std::string &urlSeed : m_addTorrentParams.url_seeds)

View File

@@ -1606,7 +1606,7 @@ void Session::populateAdditionalTrackers()
{
tracker = tracker.trimmed();
if (!tracker.isEmpty())
m_additionalTrackerList << tracker.toString();
m_additionalTrackerList.append({tracker.toString()});
}
}
@@ -3825,7 +3825,7 @@ void Session::handleTorrentTrackersAdded(TorrentImpl *const torrent, const QVect
torrent->saveResumeData();
for (const TrackerEntry &newTracker : newTrackers)
LogMsg(tr("Tracker '%1' was added to torrent '%2'").arg(newTracker.url(), torrent->name()));
LogMsg(tr("Tracker '%1' was added to torrent '%2'").arg(newTracker.url, torrent->name()));
emit trackersAdded(torrent, newTrackers);
if (torrent->trackers().size() == newTrackers.size())
emit trackerlessStateChanged(torrent, false);
@@ -3837,7 +3837,7 @@ void Session::handleTorrentTrackersRemoved(TorrentImpl *const torrent, const QVe
torrent->saveResumeData();
for (const TrackerEntry &deletedTracker : deletedTrackers)
LogMsg(tr("Tracker '%1' was deleted from torrent '%2'").arg(deletedTracker.url(), torrent->name()));
LogMsg(tr("Tracker '%1' was deleted from torrent '%2'").arg(deletedTracker.url, torrent->name()));
emit trackersRemoved(torrent, deletedTrackers);
if (torrent->trackers().empty())
emit trackerlessStateChanged(torrent, true);

View File

@@ -99,8 +99,8 @@ namespace BitTorrent
class Torrent;
class TorrentImpl;
class Tracker;
class TrackerEntry;
struct LoadTorrentParams;
struct TrackerEntry;
enum class MoveStorageMode;

View File

@@ -45,8 +45,8 @@ namespace BitTorrent
class InfoHash;
class PeerInfo;
class TorrentInfo;
class TrackerEntry;
struct PeerAddress;
struct TrackerEntry;
enum class TorrentOperatingMode
{

View File

@@ -47,6 +47,10 @@
#include <libtorrent/version.hpp>
#include <libtorrent/write_resume_data.hpp>
#if (LIBTORRENT_VERSION_NUM >= 20000)
#include <libtorrent/info_hash.hpp>
#endif
#include <QBitArray>
#include <QDebug>
#include <QDir>
@@ -96,6 +100,114 @@ namespace
entryList.emplace_back(setValue.toStdString());
return entryList;
}
lt::announce_entry makeNativeAnnouncerEntry(const QString &url, const int tier)
{
lt::announce_entry entry {url.toStdString()};
entry.tier = tier;
return entry;
}
#if (LIBTORRENT_VERSION_NUM >= 20000)
TrackerEntry fromNativeAnnouncerEntry(const lt::announce_entry &nativeEntry, const lt::info_hash_t &hashes)
#else
TrackerEntry fromNativeAnnouncerEntry(const lt::announce_entry &nativeEntry)
#endif
{
TrackerEntry trackerEntry {QString::fromStdString(nativeEntry.url), nativeEntry.tier};
int numUpdating = 0;
int numWorking = 0;
int numNotContacted = 0;
#if (LIBTORRENT_VERSION_NUM >= 20000)
const int numEndpoints = nativeEntry.endpoints.size() * ((hashes.has_v1() && hashes.has_v2()) ? 2 : 1);
trackerEntry.endpoints.reserve(numEndpoints);
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];
TrackerEntry::EndpointStats trackerEndpoint;
trackerEndpoint.protocolVersion = (protocolVersion == lt::protocol_version::V1) ? 1 : 2;
trackerEndpoint.numSeeds = infoHash.scrape_complete;
trackerEndpoint.numLeeches = infoHash.scrape_incomplete;
trackerEndpoint.numDownloaded = infoHash.scrape_downloaded;
if (infoHash.updating)
{
trackerEndpoint.status = TrackerEntry::Updating;
++numUpdating;
}
else if (infoHash.fails > 0)
{
trackerEndpoint.status = TrackerEntry::NotWorking;
}
else if (nativeEntry.verified)
{
trackerEndpoint.status = TrackerEntry::Working;
++numWorking;
}
else
{
trackerEndpoint.status = TrackerEntry::NotContacted;
++numNotContacted;
}
trackerEntry.endpoints.append(trackerEndpoint);
trackerEntry.numSeeds = std::max(trackerEntry.numSeeds, infoHash.scrape_complete);
trackerEntry.numLeeches = std::max(trackerEntry.numLeeches, infoHash.scrape_incomplete);
trackerEntry.numDownloaded = std::max(trackerEntry.numDownloaded, infoHash.scrape_downloaded);
}
}
}
#else
trackerEntry.endpoints.reserve(nativeEntry.endpoints.size());
for (const lt::announce_endpoint &endpoint : nativeEntry.endpoints)
{
TrackerEntry::EndpointStats trackerEndpoint;
trackerEndpoint.numSeeds = endpoint.scrape_complete;
trackerEndpoint.numLeeches = endpoint.scrape_incomplete;
trackerEndpoint.numDownloaded = endpoint.scrape_downloaded;
if (endpoint.updating)
{
trackerEndpoint.status = TrackerEntry::Updating;
++numUpdating;
}
else if (endpoint.fails > 0)
{
trackerEndpoint.status = TrackerEntry::NotWorking;
}
else if (nativeEntry.verified)
{
trackerEndpoint.status = TrackerEntry::Working;
++numWorking;
}
else
{
trackerEndpoint.status = TrackerEntry::NotContacted;
++numNotContacted;
}
trackerEntry.endpoints.append(trackerEndpoint);
trackerEntry.numSeeds = std::max(trackerEntry.numSeeds, endpoint.scrape_complete);
trackerEntry.numLeeches = std::max(trackerEntry.numLeeches, endpoint.scrape_incomplete);
trackerEntry.numDownloaded = std::max(trackerEntry.numDownloaded, endpoint.scrape_downloaded);
}
#endif
if (numUpdating > 0)
trackerEntry.status = TrackerEntry::Updating;
else if (numWorking > 0)
trackerEntry.status = TrackerEntry::Working;
else if (numNotContacted > 0)
trackerEntry.status = TrackerEntry::NotContacted;
else
trackerEntry.status = TrackerEntry::NotWorking;
return trackerEntry;
}
}
// TorrentImpl
@@ -311,7 +423,11 @@ QVector<TrackerEntry> TorrentImpl::trackers() const
entries.reserve(nativeTrackers.size());
for (const lt::announce_entry &tracker : nativeTrackers)
entries << tracker;
#if (LIBTORRENT_VERSION_NUM >= 20000)
entries << fromNativeAnnouncerEntry(tracker, m_nativeHandle.info_hashes());
#else
entries << fromNativeAnnouncerEntry(tracker);
#endif
return entries;
}
@@ -325,7 +441,7 @@ void TorrentImpl::addTrackers(const QVector<TrackerEntry> &trackers)
{
QSet<TrackerEntry> currentTrackers;
for (const lt::announce_entry &entry : m_nativeHandle.trackers())
currentTrackers << entry;
currentTrackers.insert({QString::fromStdString(entry.url), entry.tier});
QVector<TrackerEntry> newTrackers;
newTrackers.reserve(trackers.size());
@@ -334,7 +450,7 @@ void TorrentImpl::addTrackers(const QVector<TrackerEntry> &trackers)
{
if (!currentTrackers.contains(tracker))
{
m_nativeHandle.add_tracker(tracker.nativeEntry());
m_nativeHandle.add_tracker(makeNativeAnnouncerEntry(tracker.url, tracker.tier));
newTrackers << tracker;
}
}
@@ -355,7 +471,7 @@ void TorrentImpl::replaceTrackers(const QVector<TrackerEntry> &trackers)
for (const TrackerEntry &tracker : trackers)
{
nativeTrackers.emplace_back(tracker.nativeEntry());
nativeTrackers.emplace_back(makeNativeAnnouncerEntry(tracker.url, tracker.tier));
if (!currentTrackers.removeOne(tracker))
newTrackers << tracker;
@@ -1496,9 +1612,9 @@ void TorrentImpl::handleTrackerErrorAlert(const lt::tracker_error_alert *p)
const QVector<TrackerEntry> trackerList = trackers();
const auto iter = std::find_if(trackerList.cbegin(), trackerList.cend(), [&trackerUrl](const TrackerEntry &entry)
{
return (entry.url() == trackerUrl);
return (entry.url == trackerUrl);
});
if ((iter != trackerList.cend()) && (iter->status() == TrackerEntry::NotWorking))
if ((iter != trackerList.cend()) && (iter->status == TrackerEntry::NotWorking))
m_session->handleTorrentTrackerError(this, trackerUrl);
}

View File

@@ -302,7 +302,7 @@ QVector<TrackerEntry> TorrentInfo::trackers() const
ret.reserve(trackers.size());
for (const lt::announce_entry &tracker : trackers)
ret.append(tracker);
ret.append({QString::fromStdString(tracker.url)});
return ret;
}

View File

@@ -45,7 +45,7 @@ class QUrl;
namespace BitTorrent
{
class InfoHash;
class TrackerEntry;
struct TrackerEntry;
class TorrentInfo final : public AbstractFileStorage
{

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2015, 2021 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -28,139 +28,15 @@
#include "trackerentry.h"
#include <algorithm>
#include <libtorrent/version.hpp>
#include <QString>
#include <QUrl>
using namespace BitTorrent;
TrackerEntry::TrackerEntry(const QString &url)
: m_nativeEntry(url.toStdString())
{
}
TrackerEntry::TrackerEntry(const lt::announce_entry &nativeEntry)
: m_nativeEntry(nativeEntry)
{
}
QString TrackerEntry::url() const
{
return QString::fromStdString(nativeEntry().url);
}
int TrackerEntry::tier() const
{
return nativeEntry().tier;
}
TrackerEntry::Status TrackerEntry::status() const
{
const auto &endpoints = nativeEntry().endpoints;
const bool allFailed = !endpoints.empty() && std::all_of(endpoints.begin(), endpoints.end()
, [](const lt::announce_endpoint &endpoint)
{
#if (LIBTORRENT_VERSION_NUM >= 20000)
return std::all_of(endpoint.info_hashes.begin(), endpoint.info_hashes.end()
, [](const lt::announce_infohash &infohash)
{
return (infohash.fails > 0);
});
#else
return (endpoint.fails > 0);
#endif
});
if (allFailed)
return NotWorking;
const bool isUpdating = std::any_of(endpoints.begin(), endpoints.end()
, [](const lt::announce_endpoint &endpoint)
{
#if (LIBTORRENT_VERSION_NUM >= 20000)
return std::any_of(endpoint.info_hashes.begin(), endpoint.info_hashes.end()
, [](const lt::announce_infohash &infohash)
{
return infohash.updating;
});
#else
return endpoint.updating;
#endif
});
if (isUpdating)
return Updating;
if (!nativeEntry().verified)
return NotContacted;
return Working;
}
void TrackerEntry::setTier(const int value)
{
m_nativeEntry.tier = value;
}
int TrackerEntry::numSeeds() const
{
int value = -1;
for (const lt::announce_endpoint &endpoint : nativeEntry().endpoints)
{
#if (LIBTORRENT_VERSION_NUM >= 20000)
for (const lt::announce_infohash &infoHash : endpoint.info_hashes)
value = std::max(value, infoHash.scrape_complete);
#else
value = std::max(value, endpoint.scrape_complete);
#endif
}
return value;
}
int TrackerEntry::numLeeches() const
{
int value = -1;
for (const lt::announce_endpoint &endpoint : nativeEntry().endpoints)
{
#if (LIBTORRENT_VERSION_NUM >= 20000)
for (const lt::announce_infohash &infoHash : endpoint.info_hashes)
value = std::max(value, infoHash.scrape_incomplete);
#else
value = std::max(value, endpoint.scrape_incomplete);
#endif
}
return value;
}
int TrackerEntry::numDownloaded() const
{
int value = -1;
for (const lt::announce_endpoint &endpoint : nativeEntry().endpoints)
{
#if (LIBTORRENT_VERSION_NUM >= 20000)
for (const lt::announce_infohash &infoHash : endpoint.info_hashes)
value = std::max(value, infoHash.scrape_downloaded);
#else
value = std::max(value, endpoint.scrape_downloaded);
#endif
}
return value;
}
const lt::announce_entry &TrackerEntry::nativeEntry() const
{
return m_nativeEntry;
}
bool BitTorrent::operator==(const TrackerEntry &left, const TrackerEntry &right)
{
return ((left.tier() == right.tier())
&& QUrl(left.url()) == QUrl(right.url()));
return ((left.tier == right.tier)
&& QUrl(left.url) == QUrl(right.url));
}
uint BitTorrent::qHash(const TrackerEntry &key, const uint seed)
{
return (::qHash(key.url(), seed) ^ ::qHash(key.tier()));
return (::qHash(key.url, seed) ^ ::qHash(key.tier));
}

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2015, 2021 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -28,17 +28,14 @@
#pragma once
#include <libtorrent/announce_entry.hpp>
#include <QtGlobal>
class QString;
#include <QString>
#include <QVector>
namespace BitTorrent
{
class TrackerEntry
struct TrackerEntry
{
public:
enum Status
{
NotContacted = 1,
@@ -47,26 +44,26 @@ namespace BitTorrent
NotWorking = 4
};
TrackerEntry() = default;
TrackerEntry(const QString &url);
TrackerEntry(const lt::announce_entry &nativeEntry);
TrackerEntry(const TrackerEntry &other) = default;
TrackerEntry &operator=(const TrackerEntry &other) = default;
struct EndpointStats
{
int protocolVersion = 1;
QString url() const;
Status status() const;
Status status = NotContacted;
int numSeeds = -1;
int numLeeches = -1;
int numDownloaded = -1;
};
int tier() const;
void setTier(int value);
QString url;
int tier = 0;
int numSeeds() const;
int numLeeches() const;
int numDownloaded() const;
QVector<EndpointStats> endpoints {};
const lt::announce_entry &nativeEntry() const;
private:
lt::announce_entry m_nativeEntry;
// Deprecated fields
Status status = NotContacted;
int numSeeds = -1;
int numLeeches = -1;
int numDownloaded = -1;
};
bool operator==(const TrackerEntry &left, const TrackerEntry &right);