diff --git a/src/base/CMakeLists.txt b/src/base/CMakeLists.txt index 3120422d6..4c00d5048 100644 --- a/src/base/CMakeLists.txt +++ b/src/base/CMakeLists.txt @@ -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 diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index 300fd4eb8..dfcf3b6b7 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -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 &updatedTrackerEntries); + void trackerEntryStatusesUpdated(Torrent *torrent, const QHash &updatedTrackers); }; } diff --git a/src/base/bittorrent/sessionimpl.cpp b/src/base/bittorrent/sessionimpl.cpp index 7550c996a..cce3ef973 100644 --- a/src/base/bittorrent/sessionimpl.cpp +++ b/src/base/bittorrent/sessionimpl.cpp @@ -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 updatedTrackerEntries; - updatedTrackerEntries.reserve(trackerEntries.size()); - for (const auto &trackerEntry : trackerEntries) - updatedTrackerEntries.emplace(trackerEntry.url, trackerEntry); - emit trackerEntriesUpdated(torrent, updatedTrackerEntries); + const QVector trackers = torrent->trackers(); + QHash 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 &updateInfo = m_updatedTrackerEntries[torrent->nativeHandle()][std::string(a->tracker_url())][a->local_endpoint]; + QMap &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>> updatedTrackers) +void SessionImpl::updateTrackerEntryStatuses(lt::torrent_handle torrentHandle, QHash>> updatedTrackers) { invokeAsync([this, torrentHandle = std::move(torrentHandle), updatedTrackers = std::move(updatedTrackers)]() mutable { @@ -6154,8 +6154,8 @@ void SessionImpl::updateTrackerEntries(lt::torrent_handle torrentHandle, QHashisStopped()) return; - QHash updatedTrackerEntries; - updatedTrackerEntries.reserve(updatedTrackers.size()); + QHash 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, QHashupdateTrackerEntry(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 &) diff --git a/src/base/bittorrent/sessionimpl.h b/src/base/bittorrent/sessionimpl.h index 9b503ed4d..e6e17aa29 100644 --- a/src/base/bittorrent/sessionimpl.h +++ b/src/base/bittorrent/sessionimpl.h @@ -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>> updatedTrackers); + void updateTrackerEntryStatuses(lt::torrent_handle torrentHandle, QHash>> 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>>> m_updatedTrackerEntries; + QHash>>> m_updatedTrackerStatuses; // I/O errored torrents QSet m_recentErroredTorrents; diff --git a/src/base/bittorrent/torrent.h b/src/base/bittorrent/torrent.h index 14d2ab7bf..e3435d37e 100644 --- a/src/base/bittorrent/torrent.h +++ b/src/base/bittorrent/torrent.h @@ -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 trackers() const = 0; + virtual QVector trackers() const = 0; virtual QVector urlSeeds() const = 0; virtual QString error() const = 0; virtual qlonglong totalDownload() const = 0; diff --git a/src/base/bittorrent/torrentimpl.cpp b/src/base/bittorrent/torrentimpl.cpp index 2a688f9a5..d37ff9df3 100644 --- a/src/base/bittorrent/torrentimpl.cpp +++ b/src/base/bittorrent/torrentimpl.cpp @@ -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 &btProtocols, const QHash> &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, TrackerEndpointEntry>::iterator &iter) + trackerEntryStatus.endpoints.removeIf([&nativeEntry](const QHash, 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 &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(m_ltAddTorrentParams.userdata); - m_trackerEntries.reserve(static_cast(extensionData->trackers.size())); + m_trackerEntryStatuses.reserve(static_cast(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(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 TorrentImpl::trackers() const +QVector TorrentImpl::trackers() const { - return m_trackerEntries; + return m_trackerEntryStatuses; } void TorrentImpl::addTrackers(QVector trackers) { - trackers.removeIf([](const TrackerEntry &entry) { return entry.url.isEmpty(); }); + trackers.removeIf([](const TrackerEntry &trackerEntry) { return trackerEntry.url.isEmpty(); }); - const auto newTrackers = QSet(trackers.cbegin(), trackers.cend()) - - QSet(m_trackerEntries.cbegin(), m_trackerEntries.cend()); - if (newTrackers.isEmpty()) + QSet 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(trackers.cbegin(), trackers.cend()) - currentTrackerSet; + if (newTrackerSet.isEmpty()) return; - trackers = QVector(newTrackers.cbegin(), newTrackers.cend()); - for (const TrackerEntry &tracker : trackers) + trackers = QVector(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 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 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(trackers.cbegin(), trackers.cend()); trackers = QVector(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 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> &updateInfo) +TrackerEntryStatus TorrentImpl::updateTrackerEntryStatus(const lt::announce_entry &announceEntry, const QHash> &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 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 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 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(); } diff --git a/src/base/bittorrent/torrentimpl.h b/src/base/bittorrent/torrentimpl.h index 8b0d4450d..003a67e25 100644 --- a/src/base/bittorrent/torrentimpl.h +++ b/src/base/bittorrent/torrentimpl.h @@ -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 trackers() const override; + QVector trackers() const override; QVector 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> &updateInfo); - void resetTrackerEntries(); + TrackerEntryStatus updateTrackerEntryStatus(const lt::announce_entry &announceEntry, const QHash> &updateInfo); + void resetTrackerEntryStatuses(); private: using EventTrigger = std::function; @@ -349,7 +349,7 @@ namespace BitTorrent MaintenanceJob m_maintenanceJob = MaintenanceJob::None; - QVector m_trackerEntries; + QVector m_trackerEntryStatuses; QVector m_urlSeeds; FileErrorInfo m_lastFileError; diff --git a/src/base/bittorrent/torrentinfo.cpp b/src/base/bittorrent/torrentinfo.cpp index 4a0cd050c..eecd9d33a 100644 --- a/src/base/bittorrent/torrentinfo.cpp +++ b/src/base/bittorrent/torrentinfo.cpp @@ -279,7 +279,7 @@ QVector TorrentInfo::trackers() const QVector ret; ret.reserve(static_cast(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; } diff --git a/src/base/bittorrent/trackerentry.cpp b/src/base/bittorrent/trackerentry.cpp index f81e9c29e..1f323d253 100644 --- a/src/base/bittorrent/trackerentry.cpp +++ b/src/base/bittorrent/trackerentry.cpp @@ -1,5 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2024 Mike Tzou (Chocobo1) * Copyright (C) 2015-2023 Vladimir Golovnev * * This program is free software; you can redistribute it and/or @@ -28,7 +29,9 @@ #include "trackerentry.h" +#include #include +#include QList BitTorrent::parseTrackerEntries(const QStringView str) { diff --git a/src/base/bittorrent/trackerentry.h b/src/base/bittorrent/trackerentry.h index 33fce42f5..cd3cf5c63 100644 --- a/src/base/bittorrent/trackerentry.h +++ b/src/base/bittorrent/trackerentry.h @@ -1,5 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2024 Mike Tzou (Chocobo1) * Copyright (C) 2015-2023 Vladimir Golovnev * * This program is free software; you can redistribute it and/or @@ -29,56 +30,16 @@ #pragma once #include -#include -#include #include -#include + +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, TrackerEndpointEntry> endpointEntries {}; }; QList parseTrackerEntries(QStringView str); diff --git a/src/base/bittorrent/trackerentrystatus.cpp b/src/base/bittorrent/trackerentrystatus.cpp new file mode 100644 index 000000000..35acd09d3 --- /dev/null +++ b/src/base/bittorrent/trackerentrystatus.cpp @@ -0,0 +1,54 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2015-2023 Vladimir Golovnev + * + * 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); +} diff --git a/src/base/bittorrent/trackerentrystatus.h b/src/base/bittorrent/trackerentrystatus.h new file mode 100644 index 000000000..1f271d41a --- /dev/null +++ b/src/base/bittorrent/trackerentrystatus.h @@ -0,0 +1,89 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2015-2023 Vladimir Golovnev + * + * 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 +#include +#include + +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, TrackerEndpointStatus> endpoints {}; + + void clear(); + }; + + bool operator==(const TrackerEntryStatus &left, const TrackerEntryStatus &right); + std::size_t qHash(const TrackerEntryStatus &key, std::size_t seed = 0); +} diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index 4040682f8..2893220f7 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -1386,7 +1386,7 @@ void MainWindow::showFiltersSidebar(const bool show) connect(BitTorrent::Session::instance(), &BitTorrent::Session::trackersAdded, m_transferListFiltersWidget, &TransferListFiltersWidget::addTrackers); connect(BitTorrent::Session::instance(), &BitTorrent::Session::trackersRemoved, m_transferListFiltersWidget, &TransferListFiltersWidget::removeTrackers); connect(BitTorrent::Session::instance(), &BitTorrent::Session::trackersChanged, m_transferListFiltersWidget, &TransferListFiltersWidget::refreshTrackers); - connect(BitTorrent::Session::instance(), &BitTorrent::Session::trackerEntriesUpdated, m_transferListFiltersWidget, &TransferListFiltersWidget::trackerEntriesUpdated); + connect(BitTorrent::Session::instance(), &BitTorrent::Session::trackerEntryStatusesUpdated, m_transferListFiltersWidget, &TransferListFiltersWidget::trackerEntryStatusesUpdated); m_splitter->insertWidget(0, m_transferListFiltersWidget); m_splitter->setCollapsible(0, true); diff --git a/src/gui/trackerlist/trackerlistmodel.cpp b/src/gui/trackerlist/trackerlistmodel.cpp index 4b4c6e42b..92fb8acb3 100644 --- a/src/gui/trackerlist/trackerlistmodel.cpp +++ b/src/gui/trackerlist/trackerlistmodel.cpp @@ -48,6 +48,7 @@ #include "base/bittorrent/peerinfo.h" #include "base/bittorrent/session.h" #include "base/bittorrent/torrent.h" +#include "base/bittorrent/trackerentry.h" #include "base/global.h" #include "base/utils/misc.h" @@ -68,24 +69,24 @@ namespace return (val > -1) ? QString::number(val) : TrackerListModel::tr("N/A"); } - QString toString(const BitTorrent::TrackerEntryStatus status) + QString toString(const BitTorrent::TrackerEndpointState state) { - switch (status) + switch (state) { - case BitTorrent::TrackerEntryStatus::Working: + case BitTorrent::TrackerEndpointState::Working: return TrackerListModel::tr(STR_WORKING); - case BitTorrent::TrackerEntryStatus::Updating: + case BitTorrent::TrackerEndpointState::Updating: return TrackerListModel::tr("Updating..."); - case BitTorrent::TrackerEntryStatus::NotWorking: + case BitTorrent::TrackerEndpointState::NotWorking: return TrackerListModel::tr("Not working"); - case BitTorrent::TrackerEntryStatus::TrackerError: + case BitTorrent::TrackerEndpointState::TrackerError: return TrackerListModel::tr("Tracker error"); - case BitTorrent::TrackerEntryStatus::Unreachable: + case BitTorrent::TrackerEndpointState::Unreachable: return TrackerListModel::tr("Unreachable"); - case BitTorrent::TrackerEntryStatus::NotContacted: + case BitTorrent::TrackerEndpointState::NotContacted: return TrackerListModel::tr("Not contacted yet"); } - return TrackerListModel::tr("Invalid status!"); + return TrackerListModel::tr("Invalid state!"); } QString statusDHT(const BitTorrent::Torrent *torrent) @@ -132,7 +133,7 @@ struct TrackerListModel::Item final QString name {}; int tier = -1; int btVersion = -1; - BitTorrent::TrackerEntryStatus status = BitTorrent::TrackerEntryStatus::NotContacted; + BitTorrent::TrackerEndpointState status = BitTorrent::TrackerEndpointState::NotContacted; QString message {}; int numPeers = -1; @@ -159,11 +160,11 @@ struct TrackerListModel::Item final >> childItems {}; Item(QStringView name, QStringView message); - explicit Item(const BitTorrent::TrackerEntry &trackerEntry); - Item(const std::shared_ptr &parentItem, const BitTorrent::TrackerEndpointEntry &endpointEntry); + explicit Item(const BitTorrent::TrackerEntryStatus &trackerEntryStatus); + Item(const std::shared_ptr &parentItem, const BitTorrent::TrackerEndpointStatus &endpointStatus); - void fillFrom(const BitTorrent::TrackerEntry &trackerEntry); - void fillFrom(const BitTorrent::TrackerEndpointEntry &endpointEntry); + void fillFrom(const BitTorrent::TrackerEntryStatus &trackerEntryStatus); + void fillFrom(const BitTorrent::TrackerEndpointStatus &endpointStatus); }; class TrackerListModel::Items final : public multi_index_container< @@ -180,53 +181,53 @@ TrackerListModel::Item::Item(const QStringView name, const QStringView message) { } -TrackerListModel::Item::Item(const BitTorrent::TrackerEntry &trackerEntry) - : name {trackerEntry.url} +TrackerListModel::Item::Item(const BitTorrent::TrackerEntryStatus &trackerEntryStatus) + : name {trackerEntryStatus.url} { - fillFrom(trackerEntry); + fillFrom(trackerEntryStatus); } -TrackerListModel::Item::Item(const std::shared_ptr &parentItem, const BitTorrent::TrackerEndpointEntry &endpointEntry) - : name {endpointEntry.name} - , btVersion {endpointEntry.btVersion} +TrackerListModel::Item::Item(const std::shared_ptr &parentItem, const BitTorrent::TrackerEndpointStatus &endpointStatus) + : name {endpointStatus.name} + , btVersion {endpointStatus.btVersion} , parentItem {parentItem} { - fillFrom(endpointEntry); + fillFrom(endpointStatus); } -void TrackerListModel::Item::fillFrom(const BitTorrent::TrackerEntry &trackerEntry) +void TrackerListModel::Item::fillFrom(const BitTorrent::TrackerEntryStatus &trackerEntryStatus) { Q_ASSERT(parentItem.expired()); - Q_ASSERT(trackerEntry.url == name); + Q_ASSERT(trackerEntryStatus.url == name); - tier = trackerEntry.tier; - status = trackerEntry.status; - message = trackerEntry.message; - numPeers = trackerEntry.numPeers; - numSeeds = trackerEntry.numSeeds; - numLeeches = trackerEntry.numLeeches; - numDownloaded = trackerEntry.numDownloaded; - nextAnnounceTime = trackerEntry.nextAnnounceTime; - minAnnounceTime = trackerEntry.minAnnounceTime; + tier = trackerEntryStatus.tier; + status = trackerEntryStatus.state; + message = trackerEntryStatus.message; + numPeers = trackerEntryStatus.numPeers; + numSeeds = trackerEntryStatus.numSeeds; + numLeeches = trackerEntryStatus.numLeeches; + numDownloaded = trackerEntryStatus.numDownloaded; + nextAnnounceTime = trackerEntryStatus.nextAnnounceTime; + minAnnounceTime = trackerEntryStatus.minAnnounceTime; secsToNextAnnounce = 0; secsToMinAnnounce = 0; announceTimestamp = QDateTime(); } -void TrackerListModel::Item::fillFrom(const BitTorrent::TrackerEndpointEntry &endpointEntry) +void TrackerListModel::Item::fillFrom(const BitTorrent::TrackerEndpointStatus &endpointStatus) { Q_ASSERT(!parentItem.expired()); - Q_ASSERT(endpointEntry.name == name); - Q_ASSERT(endpointEntry.btVersion == btVersion); + Q_ASSERT(endpointStatus.name == name); + Q_ASSERT(endpointStatus.btVersion == btVersion); - status = endpointEntry.status; - message = endpointEntry.message; - numPeers = endpointEntry.numPeers; - numSeeds = endpointEntry.numSeeds; - numLeeches = endpointEntry.numLeeches; - numDownloaded = endpointEntry.numDownloaded; - nextAnnounceTime = endpointEntry.nextAnnounceTime; - minAnnounceTime = endpointEntry.minAnnounceTime; + status = endpointStatus.state; + message = endpointStatus.message; + numPeers = endpointStatus.numPeers; + numSeeds = endpointStatus.numSeeds; + numLeeches = endpointStatus.numLeeches; + numDownloaded = endpointStatus.numDownloaded; + nextAnnounceTime = endpointStatus.nextAnnounceTime; + minAnnounceTime = endpointStatus.minAnnounceTime; secsToNextAnnounce = 0; secsToMinAnnounce = 0; announceTimestamp = QDateTime(); @@ -261,8 +262,8 @@ TrackerListModel::TrackerListModel(BitTorrent::Session *btSession, QObject *pare if (torrent == m_torrent) onTrackersChanged(); }); - connect(m_btSession, &BitTorrent::Session::trackerEntriesUpdated, this - , [this](BitTorrent::Torrent *torrent, const QHash &updatedTrackers) + connect(m_btSession, &BitTorrent::Session::trackerEntryStatusesUpdated, this + , [this](BitTorrent::Torrent *torrent, const QHash &updatedTrackers) { if (torrent == m_torrent) onTrackersUpdated(updatedTrackers); @@ -296,8 +297,8 @@ void TrackerListModel::populate() { Q_ASSERT(m_torrent); - const QList trackerEntries = m_torrent->trackers(); - m_items->reserve(trackerEntries.size() + STICKY_ROW_COUNT); + const QList trackers = m_torrent->trackers(); + m_items->reserve(trackers.size() + STICKY_ROW_COUNT); const QString &privateTorrentMessage = m_torrent->isPrivate() ? tr(STR_PRIVATE_MSG) : u""_s; m_items->emplace_back(std::make_shared(u"** [DHT] **", privateTorrentMessage)); @@ -365,46 +366,44 @@ void TrackerListModel::populate() emit dataChanged(index(ROW_DHT, COL_SEEDS), index(ROW_LSD, COL_LEECHES)); }); - for (const BitTorrent::TrackerEntry &trackerEntry : trackerEntries) - addTrackerItem(trackerEntry); + for (const BitTorrent::TrackerEntryStatus &status : trackers) + addTrackerItem(status); m_announceTimestamp = QDateTime::currentDateTime(); m_announceRefreshTimer->start(ANNOUNCE_TIME_REFRESH_INTERVAL); } -std::shared_ptr TrackerListModel::createTrackerItem(const BitTorrent::TrackerEntry &trackerEntry) +std::shared_ptr TrackerListModel::createTrackerItem(const BitTorrent::TrackerEntryStatus &trackerEntryStatus) { - auto item = std::make_shared(trackerEntry); - for (const auto &[id, endpointEntry] : trackerEntry.endpointEntries.asKeyValueRange()) - { - item->childItems.emplace_back(std::make_shared(item, endpointEntry)); - } + const auto item = std::make_shared(trackerEntryStatus); + for (const auto &[id, endpointStatus] : trackerEntryStatus.endpoints.asKeyValueRange()) + item->childItems.emplace_back(std::make_shared(item, endpointStatus)); return item; } -void TrackerListModel::addTrackerItem(const BitTorrent::TrackerEntry &trackerEntry) +void TrackerListModel::addTrackerItem(const BitTorrent::TrackerEntryStatus &trackerEntryStatus) { - [[maybe_unused]] const auto &[iter, res] = m_items->emplace_back(createTrackerItem(trackerEntry)); + [[maybe_unused]] const auto &[iter, res] = m_items->emplace_back(createTrackerItem(trackerEntryStatus)); Q_ASSERT(res); } -void TrackerListModel::updateTrackerItem(const std::shared_ptr &item, const BitTorrent::TrackerEntry &trackerEntry) +void TrackerListModel::updateTrackerItem(const std::shared_ptr &item, const BitTorrent::TrackerEntryStatus &trackerEntryStatus) { QSet> endpointItemIDs; QList> newEndpointItems; - for (const auto &[id, endpointEntry] : trackerEntry.endpointEntries.asKeyValueRange()) + for (const auto &[id, endpointStatus] : trackerEntryStatus.endpoints.asKeyValueRange()) { endpointItemIDs.insert(id); auto &itemsByID = item->childItems.get(); if (const auto &iter = itemsByID.find(std::make_tuple(id.first, id.second)); iter != itemsByID.end()) { - (*iter)->fillFrom(endpointEntry); + (*iter)->fillFrom(endpointStatus); } else { - newEndpointItems.emplace_back(std::make_shared(item, endpointEntry)); + newEndpointItems.emplace_back(std::make_shared(item, endpointStatus)); } } @@ -429,7 +428,7 @@ void TrackerListModel::updateTrackerItem(const std::shared_ptr &item, cons } } - const auto numRows = rowCount(trackerIndex); + const int numRows = rowCount(trackerIndex); emit dataChanged(index(0, 0, trackerIndex), index((numRows - 1), (columnCount(trackerIndex) - 1), trackerIndex)); if (!newEndpointItems.isEmpty()) @@ -440,7 +439,7 @@ void TrackerListModel::updateTrackerItem(const std::shared_ptr &item, cons endInsertRows(); } - item->fillFrom(trackerEntry); + item->fillFrom(trackerEntryStatus); emit dataChanged(trackerIndex, index(trackerRow, (columnCount() - 1))); } @@ -697,10 +696,10 @@ QModelIndex TrackerListModel::parent(const QModelIndex &index) const void TrackerListModel::onTrackersAdded(const QList &newTrackers) { - const auto row = rowCount(); + const int row = rowCount(); beginInsertRows({}, row, (row + newTrackers.size() - 1)); - for (const BitTorrent::TrackerEntry &trackerEntry : newTrackers) - addTrackerItem(trackerEntry); + for (const BitTorrent::TrackerEntry &entry : newTrackers) + addTrackerItem({entry.url, entry.tier}); endInsertRows(); } @@ -727,18 +726,18 @@ void TrackerListModel::onTrackersChanged() trackerItemIDs.insert(m_items->at(i)->name); QList> newTrackerItems; - for (const BitTorrent::TrackerEntry &trackerEntry : m_torrent->trackers()) + for (const BitTorrent::TrackerEntryStatus &trackerEntryStatus : m_torrent->trackers()) { - trackerItemIDs.insert(trackerEntry.url); + trackerItemIDs.insert(trackerEntryStatus.url); auto &itemsByName = m_items->get(); - if (const auto &iter = itemsByName.find(trackerEntry.url); iter != itemsByName.end()) + if (const auto &iter = itemsByName.find(trackerEntryStatus.url); iter != itemsByName.end()) { - updateTrackerItem(*iter, trackerEntry); + updateTrackerItem(*iter, trackerEntryStatus); } else { - newTrackerItems.emplace_back(createTrackerItem(trackerEntry)); + newTrackerItems.emplace_back(createTrackerItem(trackerEntryStatus)); } } @@ -760,7 +759,7 @@ void TrackerListModel::onTrackersChanged() if (!newTrackerItems.isEmpty()) { - const auto numRows = rowCount(); + const int numRows = rowCount(); beginInsertRows({}, numRows, (numRows + newTrackerItems.size() - 1)); for (const auto &newTrackerItem : asConst(newTrackerItems)) m_items->get<0>().push_back(newTrackerItem); @@ -768,14 +767,14 @@ void TrackerListModel::onTrackersChanged() } } -void TrackerListModel::onTrackersUpdated(const QHash &updatedTrackers) +void TrackerListModel::onTrackersUpdated(const QHash &updatedTrackers) { - for (const auto &[url, entry] : updatedTrackers.asKeyValueRange()) + for (const auto &[url, tracker] : updatedTrackers.asKeyValueRange()) { auto &itemsByName = m_items->get(); - if (const auto &iter = itemsByName.find(entry.url); iter != itemsByName.end()) [[likely]] + if (const auto &iter = itemsByName.find(tracker.url); iter != itemsByName.end()) [[likely]] { - updateTrackerItem(*iter, entry); + updateTrackerItem(*iter, tracker); } } } diff --git a/src/gui/trackerlist/trackerlistmodel.h b/src/gui/trackerlist/trackerlistmodel.h index 2065a4eb2..9a633bf8e 100644 --- a/src/gui/trackerlist/trackerlistmodel.h +++ b/src/gui/trackerlist/trackerlistmodel.h @@ -35,7 +35,7 @@ #include #include -#include "base/bittorrent/trackerentry.h" +#include "base/bittorrent/trackerentrystatus.h" class QTimer; @@ -43,6 +43,7 @@ namespace BitTorrent { class Session; class Torrent; + struct TrackerEntry; } class TrackerListModel final : public QAbstractItemModel @@ -99,14 +100,14 @@ private: struct Item; void populate(); - std::shared_ptr createTrackerItem(const BitTorrent::TrackerEntry &trackerEntry); - void addTrackerItem(const BitTorrent::TrackerEntry &trackerEntry); - void updateTrackerItem(const std::shared_ptr &item, const BitTorrent::TrackerEntry &trackerEntry); + std::shared_ptr createTrackerItem(const BitTorrent::TrackerEntryStatus &trackerEntryStatus); + void addTrackerItem(const BitTorrent::TrackerEntryStatus &trackerEntryStatus); + void updateTrackerItem(const std::shared_ptr &item, const BitTorrent::TrackerEntryStatus &trackerEntryStatus); void refreshAnnounceTimes(); void onTrackersAdded(const QList &newTrackers); void onTrackersRemoved(const QStringList &deletedTrackers); void onTrackersChanged(); - void onTrackersUpdated(const QHash &updatedTrackers); + void onTrackersUpdated(const QHash &updatedTrackers); BitTorrent::Session *m_btSession = nullptr; BitTorrent::Torrent *m_torrent = nullptr; diff --git a/src/gui/trackerlist/trackerlistwidget.cpp b/src/gui/trackerlist/trackerlistwidget.cpp index 1e43bd92e..be34e261a 100644 --- a/src/gui/trackerlist/trackerlistwidget.cpp +++ b/src/gui/trackerlist/trackerlistwidget.cpp @@ -47,7 +47,7 @@ #include "base/bittorrent/session.h" #include "base/bittorrent/torrent.h" -#include "base/bittorrent/trackerentry.h" +#include "base/bittorrent/trackerentrystatus.h" #include "base/global.h" #include "base/preferences.h" #include "gui/autoexpandabledialog.h" @@ -142,52 +142,68 @@ QModelIndexList TrackerListWidget::getSelectedTrackerRows() const void TrackerListWidget::decreaseSelectedTrackerTiers() { - const auto &trackerIndexes = getSelectedTrackerRows(); + const QModelIndexList trackerIndexes = getSelectedTrackerRows(); if (trackerIndexes.isEmpty()) return; QSet trackerURLs; + trackerURLs.reserve(trackerIndexes.size()); for (const QModelIndex &index : trackerIndexes) - { trackerURLs.insert(index.siblingAtColumn(TrackerListModel::COL_URL).data().toString()); - } - QList trackers = m_model->torrent()->trackers(); - for (BitTorrent::TrackerEntry &trackerEntry : trackers) + const QList trackers = m_model->torrent()->trackers(); + QList adjustedTrackers; + adjustedTrackers.reserve(trackers.size()); + + for (const BitTorrent::TrackerEntryStatus &status : trackers) { - if (trackerURLs.contains(trackerEntry.url)) + BitTorrent::TrackerEntry entry { - if (trackerEntry.tier > 0) - --trackerEntry.tier; + .url = status.url, + .tier = status.tier + }; + if (trackerURLs.contains(entry.url)) + { + if (entry.tier > 0) + --entry.tier; } + adjustedTrackers.append(entry); } - m_model->torrent()->replaceTrackers(trackers); + m_model->torrent()->replaceTrackers(adjustedTrackers); } void TrackerListWidget::increaseSelectedTrackerTiers() { - const auto &trackerIndexes = getSelectedTrackerRows(); + const QModelIndexList trackerIndexes = getSelectedTrackerRows(); if (trackerIndexes.isEmpty()) return; QSet trackerURLs; + trackerURLs.reserve(trackerIndexes.size()); for (const QModelIndex &index : trackerIndexes) - { trackerURLs.insert(index.siblingAtColumn(TrackerListModel::COL_URL).data().toString()); - } - QList trackers = m_model->torrent()->trackers(); - for (BitTorrent::TrackerEntry &trackerEntry : trackers) + const QList trackers = m_model->torrent()->trackers(); + QList adjustedTrackers; + adjustedTrackers.reserve(trackers.size()); + + for (const BitTorrent::TrackerEntryStatus &status : trackers) { - if (trackerURLs.contains(trackerEntry.url)) + BitTorrent::TrackerEntry entry { - if (trackerEntry.tier < std::numeric_limits::max()) - ++trackerEntry.tier; + .url = status.url, + .tier = status.tier + }; + if (trackerURLs.contains(entry.url)) + { + if (entry.tier < std::numeric_limits::max()) + ++entry.tier; } + adjustedTrackers.append(entry); } - m_model->torrent()->replaceTrackers(trackers); + m_model->torrent()->replaceTrackers(adjustedTrackers); } void TrackerListWidget::openAddTrackersDialog() @@ -205,7 +221,7 @@ void TrackerListWidget::copyTrackerUrl() if (!torrent()) return; - const auto &selectedTrackerIndexes = getSelectedTrackerRows(); + const QModelIndexList selectedTrackerIndexes = getSelectedTrackerRows(); if (selectedTrackerIndexes.isEmpty()) return; @@ -226,7 +242,7 @@ void TrackerListWidget::deleteSelectedTrackers() if (!torrent()) return; - const auto &selectedTrackerIndexes = getSelectedTrackerRows(); + const QModelIndexList selectedTrackerIndexes = getSelectedTrackerRows(); if (selectedTrackerIndexes.isEmpty()) return; @@ -245,7 +261,7 @@ void TrackerListWidget::editSelectedTracker() if (!torrent()) return; - const auto &selectedTrackerIndexes = getSelectedTrackerRows(); + const QModelIndexList selectedTrackerIndexes = getSelectedTrackerRows(); if (selectedTrackerIndexes.isEmpty()) return; @@ -268,24 +284,36 @@ void TrackerListWidget::editSelectedTracker() if (newTrackerURL == trackerURL) return; - QList trackers = torrent()->trackers(); + const QList trackers = torrent()->trackers(); + QList entries; + entries.reserve(trackers.size()); + bool match = false; - for (BitTorrent::TrackerEntry &entry : trackers) + for (const BitTorrent::TrackerEntryStatus &status : trackers) { - if (newTrackerURL == QUrl(entry.url)) + const QUrl url {status.url}; + + if (newTrackerURL == url) { QMessageBox::warning(this, tr("Tracker editing failed"), tr("The tracker URL already exists.")); return; } - if (!match && (trackerURL == QUrl(entry.url))) + BitTorrent::TrackerEntry entry + { + .url = status.url, + .tier = status.tier + }; + + if (!match && (trackerURL == url)) { match = true; entry.url = newTrackerURL.toString(); } + entries.append(entry); } - torrent()->replaceTrackers(trackers); + torrent()->replaceTrackers(entries); } void TrackerListWidget::reannounceSelected() @@ -315,14 +343,12 @@ void TrackerListWidget::reannounceSelected() trackerURLs.insert(index.siblingAtColumn(TrackerListModel::COL_URL).data().toString()); } - const QList &trackers = m_model->torrent()->trackers(); + const QList &trackers = m_model->torrent()->trackers(); for (qsizetype i = 0; i < trackers.size(); ++i) { - const BitTorrent::TrackerEntry &trackerEntry = trackers.at(i); - if (trackerURLs.contains(trackerEntry.url)) - { + const BitTorrent::TrackerEntryStatus &status = trackers.at(i); + if (trackerURLs.contains(status.url)) torrent()->forceReannounce(i); - } } } diff --git a/src/gui/transferlistfilters/trackersfilterwidget.cpp b/src/gui/transferlistfilters/trackersfilterwidget.cpp index 289f502a4..a166c7da7 100644 --- a/src/gui/transferlistfilters/trackersfilterwidget.cpp +++ b/src/gui/transferlistfilters/trackersfilterwidget.cpp @@ -38,6 +38,8 @@ #include "base/algorithm.h" #include "base/bittorrent/session.h" +#include "base/bittorrent/trackerentry.h" +#include "base/bittorrent/trackerentrystatus.h" #include "base/global.h" #include "base/net/downloadmanager.h" #include "base/preferences.h" @@ -202,16 +204,15 @@ void TrackersFilterWidget::refreshTrackers(const BitTorrent::Torrent *torrent) return false; }); - const QVector trackerEntries = torrent->trackers(); - const bool isTrackerless = trackerEntries.isEmpty(); - if (isTrackerless) + const QVector trackers = torrent->trackers(); + if (trackers.isEmpty()) { addItems(NULL_HOST, {torrentID}); } else { - for (const BitTorrent::TrackerEntry &trackerEntry : trackerEntries) - addItems(trackerEntry.url, {torrentID}); + for (const BitTorrent::TrackerEntryStatus &status : trackers) + addItems(status.url, {torrentID}); } item(OTHERERROR_ROW)->setText(formatItemText(OTHERERROR_ROW, m_errors.size())); @@ -380,8 +381,8 @@ void TrackersFilterWidget::setDownloadTrackerFavicon(bool value) } } -void TrackersFilterWidget::handleTrackerEntriesUpdated(const BitTorrent::Torrent *torrent - , const QHash &updatedTrackerEntries) +void TrackersFilterWidget::handleTrackerStatusesUpdated(const BitTorrent::Torrent *torrent + , const QHash &updatedTrackers) { const BitTorrent::TorrentID id = torrent->id(); @@ -389,51 +390,51 @@ void TrackersFilterWidget::handleTrackerEntriesUpdated(const BitTorrent::Torrent auto trackerErrorHashesIt = m_trackerErrors.find(id); auto warningHashesIt = m_warnings.find(id); - for (const BitTorrent::TrackerEntry &trackerEntry : updatedTrackerEntries) + for (const BitTorrent::TrackerEntryStatus &trackerEntryStatus : updatedTrackers) { - if (trackerEntry.status == BitTorrent::TrackerEntryStatus::Working) + if (trackerEntryStatus.state == BitTorrent::TrackerEndpointState::Working) { if (errorHashesIt != m_errors.end()) { - errorHashesIt->remove(trackerEntry.url); + errorHashesIt->remove(trackerEntryStatus.url); } if (trackerErrorHashesIt != m_trackerErrors.end()) { - trackerErrorHashesIt->remove(trackerEntry.url); + trackerErrorHashesIt->remove(trackerEntryStatus.url); } - const bool hasNoWarningMessages = std::all_of(trackerEntry.endpointEntries.cbegin(), trackerEntry.endpointEntries.cend() - , [](const BitTorrent::TrackerEndpointEntry &endpointEntry) + const bool hasNoWarningMessages = std::all_of(trackerEntryStatus.endpoints.cbegin(), trackerEntryStatus.endpoints.cend() + , [](const BitTorrent::TrackerEndpointStatus &endpointEntry) { - return endpointEntry.message.isEmpty() || (endpointEntry.status != BitTorrent::TrackerEntryStatus::Working); + return endpointEntry.message.isEmpty() || (endpointEntry.state != BitTorrent::TrackerEndpointState::Working); }); if (hasNoWarningMessages) { if (warningHashesIt != m_warnings.end()) { - warningHashesIt->remove(trackerEntry.url); + warningHashesIt->remove(trackerEntryStatus.url); } } else { if (warningHashesIt == m_warnings.end()) warningHashesIt = m_warnings.insert(id, {}); - warningHashesIt->insert(trackerEntry.url); + warningHashesIt->insert(trackerEntryStatus.url); } } - else if ((trackerEntry.status == BitTorrent::TrackerEntryStatus::NotWorking) - || (trackerEntry.status == BitTorrent::TrackerEntryStatus::Unreachable)) + else if ((trackerEntryStatus.state == BitTorrent::TrackerEndpointState::NotWorking) + || (trackerEntryStatus.state == BitTorrent::TrackerEndpointState::Unreachable)) { if (errorHashesIt == m_errors.end()) errorHashesIt = m_errors.insert(id, {}); - errorHashesIt->insert(trackerEntry.url); + errorHashesIt->insert(trackerEntryStatus.url); } - else if (trackerEntry.status == BitTorrent::TrackerEntryStatus::TrackerError) + else if (trackerEntryStatus.state == BitTorrent::TrackerEndpointState::TrackerError) { if (trackerErrorHashesIt == m_trackerErrors.end()) trackerErrorHashesIt = m_trackerErrors.insert(id, {}); - trackerErrorHashesIt->insert(trackerEntry.url); + trackerErrorHashesIt->insert(trackerEntryStatus.url); } } @@ -481,10 +482,10 @@ void TrackersFilterWidget::removeTracker(const QString &tracker) continue; QStringList trackersToRemove; - for (const BitTorrent::TrackerEntry &trackerEntry : asConst(torrent->trackers())) + for (const BitTorrent::TrackerEntryStatus &trackerEntryStatus : asConst(torrent->trackers())) { - if ((trackerEntry.url == tracker) || (QUrl(trackerEntry.url).host() == tracker)) - trackersToRemove.append(trackerEntry.url); + if ((trackerEntryStatus.url == tracker) || (QUrl(trackerEntryStatus.url).host() == tracker)) + trackersToRemove.append(trackerEntryStatus.url); } torrent->removeTrackers({trackersToRemove}); @@ -592,8 +593,8 @@ void TrackersFilterWidget::handleTorrentsLoaded(const QVectorid(); - const QVector trackers = torrent->trackers(); - for (const BitTorrent::TrackerEntry &tracker : trackers) + const QVector trackers = torrent->trackers(); + for (const BitTorrent::TrackerEntryStatus &tracker : trackers) torrentsPerTracker[tracker.url].append(torrentID); // Check for trackerless torrent @@ -613,8 +614,8 @@ void TrackersFilterWidget::handleTorrentsLoaded(const QVectorid(); - const QVector trackers = torrent->trackers(); - for (const BitTorrent::TrackerEntry &tracker : trackers) + const QVector trackers = torrent->trackers(); + for (const BitTorrent::TrackerEntryStatus &tracker : trackers) removeItem(tracker.url, torrentID); // Check for trackerless torrent diff --git a/src/gui/transferlistfilters/trackersfilterwidget.h b/src/gui/transferlistfilters/trackersfilterwidget.h index fe740b2c1..a61aada59 100644 --- a/src/gui/transferlistfilters/trackersfilterwidget.h +++ b/src/gui/transferlistfilters/trackersfilterwidget.h @@ -32,12 +32,17 @@ #include #include -#include "base/bittorrent/trackerentry.h" #include "base/path.h" #include "basefilterwidget.h" class TransferListWidget; +namespace BitTorrent +{ + struct TrackerEntry; + struct TrackerEntryStatus; +} + namespace Net { struct DownloadResult; @@ -55,8 +60,8 @@ public: void addTrackers(const BitTorrent::Torrent *torrent, const QVector &trackers); void removeTrackers(const BitTorrent::Torrent *torrent, const QStringList &trackers); void refreshTrackers(const BitTorrent::Torrent *torrent); - void handleTrackerEntriesUpdated(const BitTorrent::Torrent *torrent - , const QHash &updatedTrackerEntries); + void handleTrackerStatusesUpdated(const BitTorrent::Torrent *torrent + , const QHash &updatedTrackers); void setDownloadTrackerFavicon(bool value); private slots: diff --git a/src/gui/transferlistfilterswidget.cpp b/src/gui/transferlistfilterswidget.cpp index de9be9447..feb93d1a6 100644 --- a/src/gui/transferlistfilterswidget.cpp +++ b/src/gui/transferlistfilterswidget.cpp @@ -42,6 +42,7 @@ #include "base/algorithm.h" #include "base/bittorrent/session.h" #include "base/bittorrent/torrent.h" +#include "base/bittorrent/trackerentrystatus.h" #include "base/global.h" #include "base/logger.h" #include "base/net/downloadmanager.h" @@ -191,10 +192,10 @@ void TransferListFiltersWidget::refreshTrackers(const BitTorrent::Torrent *torre m_trackersFilterWidget->refreshTrackers(torrent); } -void TransferListFiltersWidget::trackerEntriesUpdated(const BitTorrent::Torrent *torrent - , const QHash &updatedTrackerEntries) +void TransferListFiltersWidget::trackerEntryStatusesUpdated(const BitTorrent::Torrent *torrent + , const QHash &updatedTrackers) { - m_trackersFilterWidget->handleTrackerEntriesUpdated(torrent, updatedTrackerEntries); + m_trackersFilterWidget->handleTrackerStatusesUpdated(torrent, updatedTrackers); } void TransferListFiltersWidget::onCategoryFilterStateChanged(bool enabled) diff --git a/src/gui/transferlistfilterswidget.h b/src/gui/transferlistfilterswidget.h index 456701c6b..dc652e48e 100644 --- a/src/gui/transferlistfilterswidget.h +++ b/src/gui/transferlistfilterswidget.h @@ -30,10 +30,8 @@ #pragma once #include -#include #include -#include "base/bittorrent/torrent.h" #include "base/bittorrent/trackerentry.h" class CategoryFilterWidget; @@ -42,6 +40,12 @@ class TagFilterWidget; class TrackersFilterWidget; class TransferListWidget; +namespace BitTorrent +{ + class Torrent; + struct TrackerEntryStatus; +} + class TransferListFiltersWidget final : public QWidget { Q_OBJECT @@ -55,8 +59,8 @@ public slots: void addTrackers(const BitTorrent::Torrent *torrent, const QVector &trackers); void removeTrackers(const BitTorrent::Torrent *torrent, const QStringList &trackers); void refreshTrackers(const BitTorrent::Torrent *torrent); - void trackerEntriesUpdated(const BitTorrent::Torrent *torrent - , const QHash &updatedTrackerEntries); + void trackerEntryStatusesUpdated(const BitTorrent::Torrent *torrent + , const QHash &updatedTrackers); private slots: void onCategoryFilterStateChanged(bool enabled); diff --git a/src/gui/transferlistwidget.cpp b/src/gui/transferlistwidget.cpp index c97445907..2540cea03 100644 --- a/src/gui/transferlistwidget.cpp +++ b/src/gui/transferlistwidget.cpp @@ -45,7 +45,7 @@ #include "base/bittorrent/session.h" #include "base/bittorrent/torrent.h" -#include "base/bittorrent/trackerentry.h" +#include "base/bittorrent/trackerentrystatus.h" #include "base/global.h" #include "base/logger.h" #include "base/path.h" @@ -783,14 +783,14 @@ void TransferListWidget::editTorrentTrackers() if (!torrents.empty()) { - commonTrackers = torrents[0]->trackers(); + for (const BitTorrent::TrackerEntryStatus &status : asConst(torrents[0]->trackers())) + commonTrackers.append({.url = status.url, .tier = status.tier}); for (const BitTorrent::Torrent *torrent : torrents) { QSet trackerSet; - - for (const BitTorrent::TrackerEntry &entry : asConst(torrent->trackers())) - trackerSet.insert(entry); + for (const BitTorrent::TrackerEntryStatus &status : asConst(torrent->trackers())) + trackerSet.insert({.url = status.url, .tier = status.tier}); commonTrackers.erase(std::remove_if(commonTrackers.begin(), commonTrackers.end() , [&trackerSet](const BitTorrent::TrackerEntry &entry) { return !trackerSet.contains(entry); }) diff --git a/src/webui/api/serialize/serialize_torrent.cpp b/src/webui/api/serialize/serialize_torrent.cpp index cd94a022f..28c821d72 100644 --- a/src/webui/api/serialize/serialize_torrent.cpp +++ b/src/webui/api/serialize/serialize_torrent.cpp @@ -33,7 +33,7 @@ #include "base/bittorrent/infohash.h" #include "base/bittorrent/torrent.h" -#include "base/bittorrent/trackerentry.h" +#include "base/bittorrent/trackerentrystatus.h" #include "base/path.h" #include "base/tagset.h" #include "base/utils/datetime.h" diff --git a/src/webui/api/synccontroller.cpp b/src/webui/api/synccontroller.cpp index 648cb99ea..99330ed59 100644 --- a/src/webui/api/synccontroller.cpp +++ b/src/webui/api/synccontroller.cpp @@ -43,7 +43,7 @@ #include "base/bittorrent/sessionstatus.h" #include "base/bittorrent/torrent.h" #include "base/bittorrent/torrentinfo.h" -#include "base/bittorrent/trackerentry.h" +#include "base/bittorrent/trackerentrystatus.h" #include "base/global.h" #include "base/net/geoipmanager.h" #include "base/preferences.h" @@ -523,8 +523,8 @@ void SyncController::makeMaindataSnapshot() QVariantMap serializedTorrent = serialize(*torrent); serializedTorrent.remove(KEY_TORRENT_ID); - for (const BitTorrent::TrackerEntry &tracker : asConst(torrent->trackers())) - m_knownTrackers[tracker.url].insert(torrentID); + for (const BitTorrent::TrackerEntryStatus &status : asConst(torrent->trackers())) + m_knownTrackers[status.url].insert(torrentID); m_maindataSnapshot.torrents[torrentID.toString()] = serializedTorrent; } @@ -834,11 +834,11 @@ void SyncController::onTorrentAdded(BitTorrent::Torrent *torrent) m_removedTorrents.remove(torrentID); m_updatedTorrents.insert(torrentID); - for (const BitTorrent::TrackerEntry &trackerEntry : asConst(torrent->trackers())) + for (const BitTorrent::TrackerEntryStatus &status : asConst(torrent->trackers())) { - m_knownTrackers[trackerEntry.url].insert(torrentID); - m_updatedTrackers.insert(trackerEntry.url); - m_removedTrackers.remove(trackerEntry.url); + m_knownTrackers[status.url].insert(torrentID); + m_updatedTrackers.insert(status.url); + m_removedTrackers.remove(status.url); } } @@ -849,9 +849,9 @@ void SyncController::onTorrentAboutToBeRemoved(BitTorrent::Torrent *torrent) m_updatedTorrents.remove(torrentID); m_removedTorrents.insert(torrentID); - for (const BitTorrent::TrackerEntry &trackerEntry : asConst(torrent->trackers())) + for (const BitTorrent::TrackerEntryStatus &status : asConst(torrent->trackers())) { - auto iter = m_knownTrackers.find(trackerEntry.url); + auto iter = m_knownTrackers.find(status.url); Q_ASSERT(iter != m_knownTrackers.end()); if (iter == m_knownTrackers.end()) [[unlikely]] continue; @@ -861,12 +861,12 @@ void SyncController::onTorrentAboutToBeRemoved(BitTorrent::Torrent *torrent) if (torrentIDs.isEmpty()) { m_knownTrackers.erase(iter); - m_updatedTrackers.remove(trackerEntry.url); - m_removedTrackers.insert(trackerEntry.url); + m_updatedTrackers.remove(status.url); + m_removedTrackers.insert(status.url); } else { - m_updatedTrackers.insert(trackerEntry.url); + m_updatedTrackers.insert(status.url); } } } @@ -922,11 +922,12 @@ void SyncController::onTorrentTrackersChanged(BitTorrent::Torrent *torrent) { using namespace BitTorrent; - const QVector currentTrackerEntries = torrent->trackers(); + const QVector trackers = torrent->trackers(); + QSet currentTrackers; - currentTrackers.reserve(currentTrackerEntries.size()); - for (const TrackerEntry ¤tTrackerEntry : currentTrackerEntries) - currentTrackers.insert(currentTrackerEntry.url); + currentTrackers.reserve(trackers.size()); + for (const TrackerEntryStatus &status : trackers) + currentTrackers.insert(status.url); const TorrentID torrentID = torrent->id(); Algorithm::removeIf(m_knownTrackers diff --git a/src/webui/api/torrentscontroller.cpp b/src/webui/api/torrentscontroller.cpp index fb0768d85..76e0a07d7 100644 --- a/src/webui/api/torrentscontroller.cpp +++ b/src/webui/api/torrentscontroller.cpp @@ -49,6 +49,7 @@ #include "base/bittorrent/torrent.h" #include "base/bittorrent/torrentdescriptor.h" #include "base/bittorrent/trackerentry.h" +#include "base/bittorrent/trackerentrystatus.h" #include "base/interfaces/iapplication.h" #include "base/global.h" #include "base/logger.h" @@ -194,7 +195,7 @@ namespace } } - const int working = static_cast(BitTorrent::TrackerEntryStatus::Working); + const int working = static_cast(BitTorrent::TrackerEndpointState::Working); const int disabled = 0; const QString privateMsg {QCoreApplication::translate("TrackerListWidget", "This torrent is private")}; @@ -500,16 +501,16 @@ void TorrentsController::trackersAction() QJsonArray trackerList = getStickyTrackers(torrent); - for (const BitTorrent::TrackerEntry &tracker : asConst(torrent->trackers())) + for (const BitTorrent::TrackerEntryStatus &tracker : asConst(torrent->trackers())) { - const bool isNotWorking = (tracker.status == BitTorrent::TrackerEntryStatus::NotWorking) - || (tracker.status == BitTorrent::TrackerEntryStatus::TrackerError) - || (tracker.status == BitTorrent::TrackerEntryStatus::Unreachable); + const bool isNotWorking = (tracker.state == BitTorrent::TrackerEndpointState::NotWorking) + || (tracker.state == BitTorrent::TrackerEndpointState::TrackerError) + || (tracker.state == BitTorrent::TrackerEndpointState::Unreachable); trackerList << QJsonObject { {KEY_TRACKER_URL, tracker.url}, {KEY_TRACKER_TIER, tracker.tier}, - {KEY_TRACKER_STATUS, static_cast((isNotWorking ? BitTorrent::TrackerEntryStatus::NotWorking : tracker.status))}, + {KEY_TRACKER_STATUS, static_cast((isNotWorking ? BitTorrent::TrackerEndpointState::NotWorking : tracker.state))}, {KEY_TRACKER_MSG, tracker.message}, {KEY_TRACKER_PEERS_COUNT, tracker.numPeers}, {KEY_TRACKER_SEEDS_COUNT, tracker.numSeeds}, @@ -800,7 +801,7 @@ void TorrentsController::addTrackersAction() if (!torrent) throw APIError(APIErrorType::NotFound); - const QVector entries = BitTorrent::parseTrackerEntries(params()[u"urls"_s]); + const QList entries = BitTorrent::parseTrackerEntries(params()[u"urls"_s]); torrent->addTrackers(entries); } @@ -823,23 +824,35 @@ void TorrentsController::editTrackerAction() if (!newTrackerUrl.isValid()) throw APIError(APIErrorType::BadParams, u"New tracker URL is invalid"_s); - QVector trackers = torrent->trackers(); + const QList currentTrackers = torrent->trackers(); + QList entries; + entries.reserve(currentTrackers.size()); + bool match = false; - for (BitTorrent::TrackerEntry &tracker : trackers) + for (const BitTorrent::TrackerEntryStatus &tracker : currentTrackers) { const QUrl trackerUrl {tracker.url}; + if (trackerUrl == newTrackerUrl) throw APIError(APIErrorType::Conflict, u"New tracker URL already exists"_s); + + BitTorrent::TrackerEntry entry + { + .url = tracker.url, + .tier = tracker.tier + }; + if (trackerUrl == origTrackerUrl) { match = true; - tracker.url = newTrackerUrl.toString(); + entry.url = newTrackerUrl.toString(); } + entries.append(entry); } if (!match) throw APIError(APIErrorType::Conflict, u"Tracker not found"_s); - torrent->replaceTrackers(trackers); + torrent->replaceTrackers(entries); if (!torrent->isStopped()) torrent->forceReannounce();