mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2026-01-01 13:18:06 -06:00
@@ -46,6 +46,7 @@ add_library(qbt_base STATIC
|
||||
bittorrent/torrentinfo.h
|
||||
bittorrent/tracker.h
|
||||
bittorrent/trackerentry.h
|
||||
bittorrent/trackerentrystatus.h
|
||||
concepts/explicitlyconvertibleto.h
|
||||
concepts/stringable.h
|
||||
digest32.h
|
||||
@@ -151,6 +152,7 @@ add_library(qbt_base STATIC
|
||||
bittorrent/torrentinfo.cpp
|
||||
bittorrent/tracker.cpp
|
||||
bittorrent/trackerentry.cpp
|
||||
bittorrent/trackerentrystatus.cpp
|
||||
exceptions.cpp
|
||||
http/connection.cpp
|
||||
http/httperror.cpp
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "categoryoptions.h"
|
||||
#include "sharelimitaction.h"
|
||||
#include "trackerentry.h"
|
||||
#include "trackerentrystatus.h"
|
||||
|
||||
class QString;
|
||||
|
||||
@@ -490,6 +491,6 @@ namespace BitTorrent
|
||||
void trackersRemoved(Torrent *torrent, const QStringList &trackers);
|
||||
void trackerSuccess(Torrent *torrent, const QString &tracker);
|
||||
void trackerWarning(Torrent *torrent, const QString &tracker);
|
||||
void trackerEntriesUpdated(Torrent *torrent, const QHash<QString, TrackerEntry> &updatedTrackerEntries);
|
||||
void trackerEntryStatusesUpdated(Torrent *torrent, const QHash<QString, TrackerEntryStatus> &updatedTrackers);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -102,6 +102,7 @@
|
||||
#include "torrentdescriptor.h"
|
||||
#include "torrentimpl.h"
|
||||
#include "tracker.h"
|
||||
#include "trackerentry.h"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
using namespace BitTorrent;
|
||||
@@ -2214,7 +2215,7 @@ void SessionImpl::populateAdditionalTrackers()
|
||||
{
|
||||
tracker = tracker.trimmed();
|
||||
if (!tracker.isEmpty())
|
||||
m_additionalTrackerList.append({tracker.toString()});
|
||||
m_additionalTrackerList.append({.url = tracker.toString(), .tier = 0});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4898,14 +4899,15 @@ void SessionImpl::handleTorrentMetadataReceived(TorrentImpl *const torrent)
|
||||
|
||||
void SessionImpl::handleTorrentStopped(TorrentImpl *const torrent)
|
||||
{
|
||||
torrent->resetTrackerEntries();
|
||||
torrent->resetTrackerEntryStatuses();
|
||||
|
||||
const auto &trackerEntries = torrent->trackers();
|
||||
QHash<QString, TrackerEntry> updatedTrackerEntries;
|
||||
updatedTrackerEntries.reserve(trackerEntries.size());
|
||||
for (const auto &trackerEntry : trackerEntries)
|
||||
updatedTrackerEntries.emplace(trackerEntry.url, trackerEntry);
|
||||
emit trackerEntriesUpdated(torrent, updatedTrackerEntries);
|
||||
const QVector<TrackerEntryStatus> trackers = torrent->trackers();
|
||||
QHash<QString, TrackerEntryStatus> updatedTrackers;
|
||||
updatedTrackers.reserve(trackers.size());
|
||||
|
||||
for (const TrackerEntryStatus &status : trackers)
|
||||
updatedTrackers.emplace(status.url, status);
|
||||
emit trackerEntryStatusesUpdated(torrent, updatedTrackers);
|
||||
|
||||
LogMsg(tr("Torrent stopped. Torrent: \"%1\"").arg(torrent->name()));
|
||||
emit torrentStopped(torrent);
|
||||
@@ -6041,7 +6043,7 @@ void SessionImpl::handleTrackerAlert(const lt::tracker_alert *a)
|
||||
if (!torrent)
|
||||
return;
|
||||
|
||||
QMap<int, int> &updateInfo = m_updatedTrackerEntries[torrent->nativeHandle()][std::string(a->tracker_url())][a->local_endpoint];
|
||||
QMap<int, int> &updateInfo = m_updatedTrackerStatuses[torrent->nativeHandle()][std::string(a->tracker_url())][a->local_endpoint];
|
||||
|
||||
if (a->type() == lt::tracker_reply_alert::alert_type)
|
||||
{
|
||||
@@ -6105,15 +6107,13 @@ void SessionImpl::handleTorrentConflictAlert(const lt::torrent_conflict_alert *a
|
||||
|
||||
void SessionImpl::processTrackerStatuses()
|
||||
{
|
||||
if (m_updatedTrackerEntries.isEmpty())
|
||||
if (m_updatedTrackerStatuses.isEmpty())
|
||||
return;
|
||||
|
||||
for (auto it = m_updatedTrackerEntries.cbegin(); it != m_updatedTrackerEntries.cend(); ++it)
|
||||
{
|
||||
updateTrackerEntries(it.key(), it.value());
|
||||
}
|
||||
for (auto it = m_updatedTrackerStatuses.cbegin(); it != m_updatedTrackerStatuses.cend(); ++it)
|
||||
updateTrackerEntryStatuses(it.key(), it.value());
|
||||
|
||||
m_updatedTrackerEntries.clear();
|
||||
m_updatedTrackerStatuses.clear();
|
||||
}
|
||||
|
||||
void SessionImpl::saveStatistics() const
|
||||
@@ -6140,7 +6140,7 @@ void SessionImpl::loadStatistics()
|
||||
m_previouslyUploaded = value[u"AlltimeUL"_s].toLongLong();
|
||||
}
|
||||
|
||||
void SessionImpl::updateTrackerEntries(lt::torrent_handle torrentHandle, QHash<std::string, QHash<lt::tcp::endpoint, QMap<int, int>>> updatedTrackers)
|
||||
void SessionImpl::updateTrackerEntryStatuses(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
|
||||
{
|
||||
@@ -6154,8 +6154,8 @@ void SessionImpl::updateTrackerEntries(lt::torrent_handle torrentHandle, QHash<s
|
||||
if (!torrent || torrent->isStopped())
|
||||
return;
|
||||
|
||||
QHash<QString, TrackerEntry> updatedTrackerEntries;
|
||||
updatedTrackerEntries.reserve(updatedTrackers.size());
|
||||
QHash<QString, TrackerEntryStatus> trackers;
|
||||
trackers.reserve(updatedTrackers.size());
|
||||
for (const lt::announce_entry &announceEntry : nativeTrackers)
|
||||
{
|
||||
const auto updatedTrackersIter = updatedTrackers.find(announceEntry.url);
|
||||
@@ -6163,12 +6163,12 @@ void SessionImpl::updateTrackerEntries(lt::torrent_handle torrentHandle, QHash<s
|
||||
continue;
|
||||
|
||||
const auto &updateInfo = updatedTrackersIter.value();
|
||||
TrackerEntry trackerEntry = torrent->updateTrackerEntry(announceEntry, updateInfo);
|
||||
const QString url = trackerEntry.url;
|
||||
updatedTrackerEntries.emplace(url, std::move(trackerEntry));
|
||||
TrackerEntryStatus status = torrent->updateTrackerEntryStatus(announceEntry, updateInfo);
|
||||
const QString url = status.url;
|
||||
trackers.emplace(url, std::move(status));
|
||||
}
|
||||
|
||||
emit trackerEntriesUpdated(torrent, updatedTrackerEntries);
|
||||
emit trackerEntryStatusesUpdated(torrent, trackers);
|
||||
});
|
||||
}
|
||||
catch (const std::exception &)
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
#include "session.h"
|
||||
#include "sessionstatus.h"
|
||||
#include "torrentinfo.h"
|
||||
#include "trackerentry.h"
|
||||
#include "trackerentrystatus.h"
|
||||
|
||||
class QString;
|
||||
class QThread;
|
||||
@@ -69,16 +69,18 @@ class NativeSessionExtension;
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
enum class MoveStorageMode;
|
||||
enum class MoveStorageContext;
|
||||
|
||||
class InfoHash;
|
||||
class ResumeDataStorage;
|
||||
class Torrent;
|
||||
class TorrentDescriptor;
|
||||
class TorrentImpl;
|
||||
class Tracker;
|
||||
struct LoadTorrentParams;
|
||||
|
||||
enum class MoveStorageMode;
|
||||
enum class MoveStorageContext;
|
||||
struct LoadTorrentParams;
|
||||
struct TrackerEntry;
|
||||
|
||||
struct SessionMetricIndices
|
||||
{
|
||||
@@ -587,7 +589,7 @@ namespace BitTorrent
|
||||
void saveStatistics() const;
|
||||
void loadStatistics();
|
||||
|
||||
void updateTrackerEntries(lt::torrent_handle torrentHandle, QHash<std::string, QHash<lt::tcp::endpoint, QMap<int, int>>> updatedTrackers);
|
||||
void updateTrackerEntryStatuses(lt::torrent_handle torrentHandle, QHash<std::string, QHash<lt::tcp::endpoint, QMap<int, int>>> updatedTrackers);
|
||||
|
||||
// BitTorrent
|
||||
lt::session *m_nativeSession = nullptr;
|
||||
@@ -766,7 +768,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<lt::tcp::endpoint, QMap<int, int>>>> m_updatedTrackerEntries;
|
||||
QHash<lt::torrent_handle, QHash<std::string, QHash<lt::tcp::endpoint, QMap<int, int>>>> m_updatedTrackerStatuses;
|
||||
|
||||
// I/O errored torrents
|
||||
QSet<TorrentID> m_recentErroredTorrents;
|
||||
|
||||
@@ -48,14 +48,17 @@ class QUrl;
|
||||
namespace BitTorrent
|
||||
{
|
||||
enum class DownloadPriority;
|
||||
|
||||
class InfoHash;
|
||||
class PeerInfo;
|
||||
class Session;
|
||||
class TorrentID;
|
||||
class TorrentInfo;
|
||||
|
||||
struct PeerAddress;
|
||||
struct SSLParameters;
|
||||
struct TrackerEntry;
|
||||
struct TrackerEntryStatus;
|
||||
|
||||
// Using `Q_ENUM_NS()` without a wrapper namespace in our case is not advised
|
||||
// since `Q_NAMESPACE` cannot be used when the same namespace resides at different files.
|
||||
@@ -245,7 +248,7 @@ namespace BitTorrent
|
||||
virtual bool hasMissingFiles() const = 0;
|
||||
virtual bool hasError() const = 0;
|
||||
virtual int queuePosition() const = 0;
|
||||
virtual QVector<TrackerEntry> trackers() const = 0;
|
||||
virtual QVector<TrackerEntryStatus> trackers() const = 0;
|
||||
virtual QVector<QUrl> urlSeeds() const = 0;
|
||||
virtual QString error() const = 0;
|
||||
virtual qlonglong totalDownload() const = 0;
|
||||
|
||||
@@ -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 <AnnounceInfo = 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();
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
#include "torrent.h"
|
||||
#include "torrentcontentlayout.h"
|
||||
#include "torrentinfo.h"
|
||||
#include "trackerentry.h"
|
||||
#include "trackerentrystatus.h"
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
@@ -175,7 +175,7 @@ namespace BitTorrent
|
||||
bool hasMissingFiles() const override;
|
||||
bool hasError() const override;
|
||||
int queuePosition() const override;
|
||||
QVector<TrackerEntry> trackers() const override;
|
||||
QVector<TrackerEntryStatus> trackers() const override;
|
||||
QVector<QUrl> urlSeeds() const override;
|
||||
QString error() const override;
|
||||
qlonglong totalDownload() const override;
|
||||
@@ -275,8 +275,8 @@ namespace BitTorrent
|
||||
void deferredRequestResumeData();
|
||||
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 QHash<lt::tcp::endpoint, QMap<int, int>> &updateInfo);
|
||||
void resetTrackerEntries();
|
||||
TrackerEntryStatus updateTrackerEntryStatus(const lt::announce_entry &announceEntry, const QHash<lt::tcp::endpoint, QMap<int, int>> &updateInfo);
|
||||
void resetTrackerEntryStatuses();
|
||||
|
||||
private:
|
||||
using EventTrigger = std::function<void ()>;
|
||||
@@ -349,7 +349,7 @@ namespace BitTorrent
|
||||
|
||||
MaintenanceJob m_maintenanceJob = MaintenanceJob::None;
|
||||
|
||||
QVector<TrackerEntry> m_trackerEntries;
|
||||
QVector<TrackerEntryStatus> m_trackerEntryStatuses;
|
||||
QVector<QUrl> m_urlSeeds;
|
||||
FileErrorInfo m_lastFileError;
|
||||
|
||||
|
||||
@@ -279,7 +279,7 @@ QVector<TrackerEntry> TorrentInfo::trackers() const
|
||||
QVector<TrackerEntry> ret;
|
||||
ret.reserve(static_cast<decltype(ret)::size_type>(trackers.size()));
|
||||
for (const lt::announce_entry &tracker : trackers)
|
||||
ret.append({QString::fromStdString(tracker.url), tracker.tier});
|
||||
ret.append({.url = QString::fromStdString(tracker.url), .tier = tracker.tier});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2024 Mike Tzou (Chocobo1)
|
||||
* Copyright (C) 2015-2023 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -28,7 +29,9 @@
|
||||
|
||||
#include "trackerentry.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
#include <QStringView>
|
||||
|
||||
QList<BitTorrent::TrackerEntry> BitTorrent::parseTrackerEntries(const QStringView str)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2024 Mike Tzou (Chocobo1)
|
||||
* Copyright (C) 2015-2023 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -29,56 +30,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <QtContainerFwd>
|
||||
#include <QDateTime>
|
||||
#include <QHash>
|
||||
#include <QString>
|
||||
#include <QStringView>
|
||||
|
||||
class QStringView;
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
enum class TrackerEntryStatus
|
||||
{
|
||||
NotContacted = 1,
|
||||
Working = 2,
|
||||
Updating = 3,
|
||||
NotWorking = 4,
|
||||
TrackerError = 5,
|
||||
Unreachable = 6
|
||||
};
|
||||
struct TrackerEndpointEntry
|
||||
{
|
||||
QString name {};
|
||||
int btVersion = 1;
|
||||
|
||||
TrackerEntryStatus status = TrackerEntryStatus::NotContacted;
|
||||
QString message {};
|
||||
|
||||
int numPeers = -1;
|
||||
int numSeeds = -1;
|
||||
int numLeeches = -1;
|
||||
int numDownloaded = -1;
|
||||
|
||||
QDateTime nextAnnounceTime {};
|
||||
QDateTime minAnnounceTime {};
|
||||
};
|
||||
|
||||
struct TrackerEntry
|
||||
{
|
||||
QString url {};
|
||||
int tier = 0;
|
||||
|
||||
TrackerEntryStatus status = TrackerEntryStatus::NotContacted;
|
||||
QString message {};
|
||||
|
||||
int numPeers = -1;
|
||||
int numSeeds = -1;
|
||||
int numLeeches = -1;
|
||||
int numDownloaded = -1;
|
||||
|
||||
QDateTime nextAnnounceTime {};
|
||||
QDateTime minAnnounceTime {};
|
||||
|
||||
QHash<std::pair<QString, int>, TrackerEndpointEntry> endpointEntries {};
|
||||
};
|
||||
|
||||
QList<TrackerEntry> parseTrackerEntries(QStringView str);
|
||||
|
||||
54
src/base/bittorrent/trackerentrystatus.cpp
Normal file
54
src/base/bittorrent/trackerentrystatus.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015-2023 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
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#include "trackerentrystatus.h"
|
||||
|
||||
void BitTorrent::TrackerEntryStatus::clear()
|
||||
{
|
||||
url.clear();
|
||||
tier = 0;
|
||||
state = TrackerEndpointState::NotContacted;
|
||||
message.clear();
|
||||
numPeers = -1;
|
||||
numSeeds = -1;
|
||||
numLeeches = -1;
|
||||
numDownloaded = -1;
|
||||
nextAnnounceTime = {};
|
||||
minAnnounceTime = {};
|
||||
endpoints.clear();
|
||||
}
|
||||
|
||||
bool BitTorrent::operator==(const TrackerEntryStatus &left, const TrackerEntryStatus &right)
|
||||
{
|
||||
return (left.url == right.url);
|
||||
}
|
||||
|
||||
std::size_t BitTorrent::qHash(const TrackerEntryStatus &key, const std::size_t seed)
|
||||
{
|
||||
return ::qHash(key.url, seed);
|
||||
}
|
||||
89
src/base/bittorrent/trackerentrystatus.h
Normal file
89
src/base/bittorrent/trackerentrystatus.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015-2023 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
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QHash>
|
||||
#include <QString>
|
||||
|
||||
class QStringView;
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
enum class TrackerEndpointState
|
||||
{
|
||||
NotContacted = 1,
|
||||
Working = 2,
|
||||
Updating = 3,
|
||||
NotWorking = 4,
|
||||
TrackerError = 5,
|
||||
Unreachable = 6
|
||||
};
|
||||
|
||||
struct TrackerEndpointStatus
|
||||
{
|
||||
QString name {};
|
||||
int btVersion = 1;
|
||||
|
||||
TrackerEndpointState state = TrackerEndpointState::NotContacted;
|
||||
QString message {};
|
||||
|
||||
int numPeers = -1;
|
||||
int numSeeds = -1;
|
||||
int numLeeches = -1;
|
||||
int numDownloaded = -1;
|
||||
|
||||
QDateTime nextAnnounceTime {};
|
||||
QDateTime minAnnounceTime {};
|
||||
};
|
||||
|
||||
struct TrackerEntryStatus
|
||||
{
|
||||
QString url {};
|
||||
int tier = 0;
|
||||
|
||||
TrackerEndpointState state = TrackerEndpointState::NotContacted;
|
||||
QString message {};
|
||||
|
||||
int numPeers = -1;
|
||||
int numSeeds = -1;
|
||||
int numLeeches = -1;
|
||||
int numDownloaded = -1;
|
||||
|
||||
QDateTime nextAnnounceTime {};
|
||||
QDateTime minAnnounceTime {};
|
||||
|
||||
QHash<std::pair<QString, int>, TrackerEndpointStatus> endpoints {};
|
||||
|
||||
void clear();
|
||||
};
|
||||
|
||||
bool operator==(const TrackerEntryStatus &left, const TrackerEntryStatus &right);
|
||||
std::size_t qHash(const TrackerEntryStatus &key, std::size_t seed = 0);
|
||||
}
|
||||
Reference in New Issue
Block a user