Browse Source

Merge pull request #18034 from glassez/fetch-async

Fetch data asynchronously
adaptive-webui-19844
Vladimir Golovnev 2 years ago committed by GitHub
parent
commit
84fabf14c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      src/base/bittorrent/peerinfo.cpp
  2. 7
      src/base/bittorrent/peerinfo.h
  3. 2
      src/base/bittorrent/sessionimpl.cpp
  4. 2
      src/base/bittorrent/sessionimpl.h
  5. 24
      src/base/bittorrent/torrent.h
  6. 267
      src/base/bittorrent/torrentimpl.cpp
  7. 16
      src/base/bittorrent/torrentimpl.h
  8. 20
      src/gui/properties/peerlistwidget.cpp
  9. 49
      src/gui/properties/propertieswidget.cpp
  10. 13
      src/gui/properties/trackerlistwidget.cpp

10
src/base/bittorrent/peerinfo.cpp

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2015-2022 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
@ -31,16 +31,15 @@ @@ -31,16 +31,15 @@
#include <QBitArray>
#include "base/bittorrent/ltqbitarray.h"
#include "base/bittorrent/torrent.h"
#include "base/net/geoipmanager.h"
#include "base/unicodestrings.h"
#include "peeraddress.h"
using namespace BitTorrent;
PeerInfo::PeerInfo(const Torrent *torrent, const lt::peer_info &nativeInfo)
PeerInfo::PeerInfo(const lt::peer_info &nativeInfo, const QBitArray &allPieces)
: m_nativeInfo(nativeInfo)
, m_relevance(calcRelevance(torrent))
, m_relevance(calcRelevance(allPieces))
{
determineFlags();
}
@ -246,9 +245,8 @@ QString PeerInfo::connectionType() const @@ -246,9 +245,8 @@ QString PeerInfo::connectionType() const
: u"Web"_qs;
}
qreal PeerInfo::calcRelevance(const Torrent *torrent) const
qreal PeerInfo::calcRelevance(const QBitArray &allPieces) const
{
const QBitArray allPieces = torrent->pieces();
const int localMissing = allPieces.count(false);
if (localMissing <= 0)
return 0;

7
src/base/bittorrent/peerinfo.h

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2015-2022 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
@ -36,7 +36,6 @@ class QBitArray; @@ -36,7 +36,6 @@ class QBitArray;
namespace BitTorrent
{
class Torrent;
struct PeerAddress;
class PeerInfo
@ -45,7 +44,7 @@ namespace BitTorrent @@ -45,7 +44,7 @@ namespace BitTorrent
public:
PeerInfo() = default;
PeerInfo(const Torrent *torrent, const lt::peer_info &nativeInfo);
PeerInfo(const lt::peer_info &nativeInfo, const QBitArray &allPieces);
bool fromDHT() const;
bool fromPeX() const;
@ -93,7 +92,7 @@ namespace BitTorrent @@ -93,7 +92,7 @@ namespace BitTorrent
int downloadingPieceIndex() const;
private:
qreal calcRelevance(const Torrent *torrent) const;
qreal calcRelevance(const QBitArray &allPieces) const;
void determineFlags();
lt::peer_info m_nativeInfo = {};

2
src/base/bittorrent/sessionimpl.cpp

@ -627,6 +627,8 @@ SessionImpl::~SessionImpl() @@ -627,6 +627,8 @@ SessionImpl::~SessionImpl()
// we delete lt::session
delete Net::PortForwarder::instance();
// We must stop "async worker" only after deletion
// of all the components that could potentially use it
m_asyncWorker->clear();
m_asyncWorker->waitForDone();

2
src/base/bittorrent/sessionimpl.h

@ -443,7 +443,7 @@ namespace BitTorrent @@ -443,7 +443,7 @@ namespace BitTorrent
template <typename Func>
void invoke(Func &&func)
{
QMetaObject::invokeMethod(this, std::forward<Func>(func));
QMetaObject::invokeMethod(this, std::forward<Func>(func), Qt::QueuedConnection);
}
void invokeAsync(std::function<void ()> func);

24
src/base/bittorrent/torrent.h

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2015-2022 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
@ -106,9 +106,10 @@ namespace BitTorrent @@ -106,9 +106,10 @@ namespace BitTorrent
uint qHash(TorrentState key, uint seed = 0);
#endif
class Torrent : public AbstractFileStorage
class Torrent : public QObject, public AbstractFileStorage
{
Q_GADGET
Q_OBJECT
Q_DISABLE_COPY_MOVE(Torrent)
public:
enum class StopCondition
@ -128,7 +129,7 @@ namespace BitTorrent @@ -128,7 +129,7 @@ namespace BitTorrent
static const qreal MAX_RATIO;
static const int MAX_SEEDING_TIME;
virtual ~Torrent() = default;
using QObject::QObject;
virtual InfoHash infoHash() const = 0;
virtual QString name() const = 0;
@ -309,7 +310,7 @@ namespace BitTorrent @@ -309,7 +310,7 @@ namespace BitTorrent
virtual void removeUrlSeeds(const QVector<QUrl> &urlSeeds) = 0;
virtual bool connectPeer(const PeerAddress &peerAddress) = 0;
virtual void clearPeers() = 0;
virtual bool setMetadata(const TorrentInfo &torrentInfo) = 0;
virtual void setMetadata(const TorrentInfo &torrentInfo) = 0;
virtual StopCondition stopCondition() const = 0;
virtual void setStopCondition(StopCondition stopCondition) = 0;
@ -318,6 +319,19 @@ namespace BitTorrent @@ -318,6 +319,19 @@ namespace BitTorrent
virtual nonstd::expected<QByteArray, QString> exportToBuffer() const = 0;
virtual nonstd::expected<void, QString> exportToFile(const Path &path) const = 0;
virtual void fetchPeerInfo(std::function<void (QVector<PeerInfo>)> resultHandler) const = 0;
virtual void fetchURLSeeds(std::function<void (QVector<QUrl>)> resultHandler) const = 0;
virtual void fetchFilesProgress(std::function<void (QVector<qreal>)> resultHandler) const = 0;
virtual void fetchPieceAvailability(std::function<void (QVector<int>)> resultHandler) const = 0;
virtual void fetchDownloadingPieces(std::function<void (QBitArray)> resultHandler) const = 0;
/**
* @brief fraction of file pieces that are available at least from one peer
*
* This is not the same as torrrent availability, it is just a fraction of pieces
* that can be downloaded right now. It varies between 0 to 1.
*/
virtual void fetchAvailableFileFractions(std::function<void (QVector<qreal>)> resultHandler) const = 0;
TorrentID id() const;
bool isResumed() const;
qlonglong remainingSize() const;

267
src/base/bittorrent/torrentimpl.cpp

@ -48,6 +48,7 @@ @@ -48,6 +48,7 @@
#include <QByteArray>
#include <QDebug>
#include <QFile>
#include <QPointer>
#include <QSet>
#include <QStringList>
#include <QUrl>
@ -236,7 +237,7 @@ namespace @@ -236,7 +237,7 @@ namespace
TorrentImpl::TorrentImpl(SessionImpl *session, lt::session *nativeSession
, const lt::torrent_handle &nativeHandle, const LoadTorrentParams &params)
: QObject(session)
: Torrent(session)
, m_session(session)
, m_nativeSession(nativeSession)
, m_nativeHandle(nativeHandle)
@ -620,50 +621,86 @@ QVector<QUrl> TorrentImpl::urlSeeds() const @@ -620,50 +621,86 @@ QVector<QUrl> TorrentImpl::urlSeeds() const
void TorrentImpl::addUrlSeeds(const QVector<QUrl> &urlSeeds)
{
const std::set<std::string> currentSeeds = m_nativeHandle.url_seeds();
m_session->invokeAsync([urlSeeds, session = m_session
, nativeHandle = m_nativeHandle
, thisTorrent = QPointer<TorrentImpl>(this)]
{
try
{
const std::set<std::string> nativeSeeds = nativeHandle.url_seeds();
QVector<QUrl> currentSeeds;
currentSeeds.reserve(static_cast<decltype(currentSeeds)::size_type>(nativeSeeds.size()));
for (const std::string &urlSeed : nativeSeeds)
currentSeeds.append(QString::fromStdString(urlSeed));
QVector<QUrl> addedUrlSeeds;
addedUrlSeeds.reserve(urlSeeds.size());
for (const QUrl &url : urlSeeds)
{
const std::string nativeUrl = url.toString().toStdString();
if (currentSeeds.find(nativeUrl) == currentSeeds.end())
if (!currentSeeds.contains(url))
{
m_nativeHandle.add_url_seed(nativeUrl);
addedUrlSeeds << url;
nativeHandle.add_url_seed(url.toString().toStdString());
addedUrlSeeds.append(url);
}
}
session->invoke([session, thisTorrent, addedUrlSeeds]
{
if (!thisTorrent)
return;
if (!addedUrlSeeds.isEmpty())
{
m_session->handleTorrentNeedSaveResumeData(this);
m_session->handleTorrentUrlSeedsAdded(this, addedUrlSeeds);
session->handleTorrentNeedSaveResumeData(thisTorrent);
session->handleTorrentUrlSeedsAdded(thisTorrent, addedUrlSeeds);
}
});
}
catch (const std::exception &) {}
});
}
void TorrentImpl::removeUrlSeeds(const QVector<QUrl> &urlSeeds)
{
const std::set<std::string> currentSeeds = m_nativeHandle.url_seeds();
m_session->invokeAsync([urlSeeds, session = m_session
, nativeHandle = m_nativeHandle
, thisTorrent = QPointer<TorrentImpl>(this)]
{
try
{
const std::set<std::string> nativeSeeds = nativeHandle.url_seeds();
QVector<QUrl> currentSeeds;
currentSeeds.reserve(static_cast<decltype(currentSeeds)::size_type>(nativeSeeds.size()));
for (const std::string &urlSeed : nativeSeeds)
currentSeeds.append(QString::fromStdString(urlSeed));
QVector<QUrl> removedUrlSeeds;
removedUrlSeeds.reserve(urlSeeds.size());
for (const QUrl &url : urlSeeds)
{
const std::string nativeUrl = url.toString().toStdString();
if (currentSeeds.find(nativeUrl) != currentSeeds.end())
if (currentSeeds.contains(url))
{
m_nativeHandle.remove_url_seed(nativeUrl);
removedUrlSeeds << url;
nativeHandle.remove_url_seed(url.toString().toStdString());
removedUrlSeeds.append(url);
}
}
session->invoke([session, thisTorrent, removedUrlSeeds]
{
if (!thisTorrent)
return;
if (!removedUrlSeeds.isEmpty())
{
m_session->handleTorrentNeedSaveResumeData(this);
m_session->handleTorrentUrlSeedsRemoved(this, removedUrlSeeds);
session->handleTorrentNeedSaveResumeData(thisTorrent);
session->handleTorrentUrlSeedsRemoved(thisTorrent, removedUrlSeeds);
}
});
}
catch (const std::exception &) {}
});
}
void TorrentImpl::clearPeers()
@ -1282,7 +1319,7 @@ QVector<PeerInfo> TorrentImpl::peers() const @@ -1282,7 +1319,7 @@ QVector<PeerInfo> TorrentImpl::peers() const
peers.reserve(static_cast<decltype(peers)::size_type>(nativePeers.size()));
for (const lt::peer_info &peer : nativePeers)
peers << PeerInfo(this, peer);
peers.append(PeerInfo(peer, pieces()));
return peers;
}
@ -2025,7 +2062,7 @@ void TorrentImpl::handleFileCompletedAlert(const lt::file_completed_alert *p) @@ -2025,7 +2062,7 @@ void TorrentImpl::handleFileCompletedAlert(const lt::file_completed_alert *p)
const int fileIndex = m_indexMap.value(p->index, -1);
Q_ASSERT(fileIndex >= 0);
m_completedFiles[fileIndex] = true;
m_completedFiles.setBit(fileIndex);
if (m_session->isAppendExtensionEnabled())
{
@ -2185,17 +2222,24 @@ lt::torrent_handle TorrentImpl::nativeHandle() const @@ -2185,17 +2222,24 @@ lt::torrent_handle TorrentImpl::nativeHandle() const
return m_nativeHandle;
}
bool TorrentImpl::setMetadata(const TorrentInfo &torrentInfo)
void TorrentImpl::setMetadata(const TorrentInfo &torrentInfo)
{
if (hasMetadata())
return false;
return;
m_session->invokeAsync([nativeHandle = m_nativeHandle, torrentInfo]
{
try
{
#ifdef QBT_USES_LIBTORRENT2
return m_nativeHandle.set_metadata(torrentInfo.nativeInfo()->info_section());
nativeHandle.set_metadata(torrentInfo.nativeInfo()->info_section());
#else
const std::shared_ptr<lt::torrent_info> nativeInfo = torrentInfo.nativeInfo();
return m_nativeHandle.set_metadata(lt::span<const char>(nativeInfo->metadata().get(), nativeInfo->metadata_size()));
nativeHandle.set_metadata(lt::span<const char>(nativeInfo->metadata().get(), nativeInfo->metadata_size()));
#endif
}
catch (const std::exception &) {}
});
}
Torrent::StopCondition TorrentImpl::stopCondition() const
@ -2415,6 +2459,171 @@ nonstd::expected<void, QString> TorrentImpl::exportToFile(const Path &path) cons @@ -2415,6 +2459,171 @@ nonstd::expected<void, QString> TorrentImpl::exportToFile(const Path &path) cons
return {};
}
void TorrentImpl::fetchPeerInfo(std::function<void (QVector<PeerInfo>)> resultHandler) const
{
invokeAsync([nativeHandle = m_nativeHandle, allPieces = pieces()]() -> QVector<PeerInfo>
{
try
{
std::vector<lt::peer_info> nativePeers;
nativeHandle.get_peer_info(nativePeers);
QVector<PeerInfo> peers;
peers.reserve(static_cast<decltype(peers)::size_type>(nativePeers.size()));
for (const lt::peer_info &peer : nativePeers)
peers.append(PeerInfo(peer, allPieces));
return peers;
}
catch (const std::exception &) {}
return {};
}
, std::move(resultHandler));
}
void TorrentImpl::fetchURLSeeds(std::function<void (QVector<QUrl>)> resultHandler) const
{
invokeAsync([nativeHandle = m_nativeHandle]() -> QVector<QUrl>
{
try
{
const std::set<std::string> currentSeeds = nativeHandle.url_seeds();
QVector<QUrl> urlSeeds;
urlSeeds.reserve(static_cast<decltype(urlSeeds)::size_type>(currentSeeds.size()));
for (const std::string &urlSeed : currentSeeds)
urlSeeds.append(QString::fromStdString(urlSeed));
return urlSeeds;
}
catch (const std::exception &) {}
return {};
}
, std::move(resultHandler));
}
void TorrentImpl::fetchFilesProgress(std::function<void (QVector<qreal>)> resultHandler) const
{
invokeAsync([nativeHandle = m_nativeHandle, torrentInfo = m_torrentInfo
, completedFiles = m_completedFiles]() -> QVector<qreal>
{
if (!torrentInfo.isValid())
return {};
const int filesCount = torrentInfo.filesCount();
if (completedFiles.count(true) == filesCount)
return QVector<qreal>(filesCount, 1);
try
{
#ifdef QBT_USES_LIBTORRENT2
const std::vector<int64_t> fp = nativeHandle.file_progress(lt::torrent_handle::piece_granularity);
#else
std::vector<int64_t> fp;
nativeHandle.file_progress(fp, lt::torrent_handle::piece_granularity);
#endif
const auto nativeIndexes = torrentInfo.nativeIndexes();
QVector<qreal> result;
result.reserve(filesCount);
for (int i = 0; i < filesCount; ++i)
{
const int64_t progress = fp[LT::toUnderlyingType(nativeIndexes[i])];
const qlonglong size = torrentInfo.fileSize(i);
if ((size <= 0) || (progress == size))
result.append(1);
else
result.append(progress / static_cast<qreal>(size));
}
return result;
}
catch (const std::exception &) {}
return {};
}
, std::move(resultHandler));
}
void TorrentImpl::fetchPieceAvailability(std::function<void (QVector<int>)> resultHandler) const
{
invokeAsync([nativeHandle = m_nativeHandle]() -> QVector<int>
{
try
{
std::vector<int> piecesAvailability;
nativeHandle.piece_availability(piecesAvailability);
return QVector<int>(piecesAvailability.cbegin(), piecesAvailability.cend());
}
catch (const std::exception &) {}
return {};
}
, std::move(resultHandler));
}
void TorrentImpl::fetchDownloadingPieces(std::function<void (QBitArray)> resultHandler) const
{
invokeAsync([nativeHandle = m_nativeHandle, torrentInfo = m_torrentInfo]() -> QBitArray
{
try
{
#ifdef QBT_USES_LIBTORRENT2
const std::vector<lt::partial_piece_info> queue = nativeHandle.get_download_queue();
#else
std::vector<lt::partial_piece_info> queue;
nativeHandle.get_download_queue(queue);
#endif
QBitArray result;
result.resize(torrentInfo.piecesCount());
for (const lt::partial_piece_info &info : queue)
result.setBit(LT::toUnderlyingType(info.piece_index));
return result;
}
catch (const std::exception &) {}
return {};
}
, std::move(resultHandler));
}
void TorrentImpl::fetchAvailableFileFractions(std::function<void (QVector<qreal>)> resultHandler) const
{
invokeAsync([nativeHandle = m_nativeHandle, torrentInfo = m_torrentInfo]() -> QVector<qreal>
{
if (!torrentInfo.isValid() || (torrentInfo.filesCount() <= 0))
return {};
try
{
std::vector<int> piecesAvailability;
nativeHandle.piece_availability(piecesAvailability);
const int filesCount = torrentInfo.filesCount();
// libtorrent returns empty array for seeding only torrents
if (piecesAvailability.empty())
return QVector<qreal>(filesCount, -1);
QVector<qreal> result;
result.reserve(filesCount);
for (int i = 0; i < filesCount; ++i)
{
const TorrentInfo::PieceRange filePieces = torrentInfo.filePieces(i);
int availablePieces = 0;
for (const int piece : filePieces)
availablePieces += (piecesAvailability[piece] > 0) ? 1 : 0;
const qreal availability = filePieces.isEmpty()
? 1 // the file has no pieces, so it is available by default
: static_cast<qreal>(availablePieces) / filePieces.size();
result.append(availability);
}
return result;
}
catch (const std::exception &) {}
return {};
}
, std::move(resultHandler));
}
void TorrentImpl::prioritizeFiles(const QVector<DownloadPriority> &priorities)
{
if (!hasMetadata()) return;
@ -2478,3 +2687,19 @@ QVector<qreal> TorrentImpl::availableFileFractions() const @@ -2478,3 +2687,19 @@ QVector<qreal> TorrentImpl::availableFileFractions() const
}
return res;
}
template <typename Func, typename Callback>
void TorrentImpl::invokeAsync(Func func, Callback resultHandler) const
{
m_session->invokeAsync([session = m_session
, func = std::move(func)
, resultHandler = std::move(resultHandler)
, thisTorrent = QPointer<const TorrentImpl>(this)]() mutable
{
session->invoke([result = func(), thisTorrent, resultHandler = std::move(resultHandler)]
{
if (thisTorrent)
resultHandler(result);
});
});
}

16
src/base/bittorrent/torrentimpl.h

@ -80,10 +80,10 @@ namespace BitTorrent @@ -80,10 +80,10 @@ namespace BitTorrent
lt::operation_t operation;
};
class TorrentImpl final : public QObject, public Torrent
class TorrentImpl final : public Torrent
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(TorrentImpl)
Q_DECLARE_TR_FUNCTIONS(BitTorrent::TorrentImpl)
public:
TorrentImpl(SessionImpl *session, lt::session *nativeSession
@ -227,7 +227,7 @@ namespace BitTorrent @@ -227,7 +227,7 @@ namespace BitTorrent
void removeUrlSeeds(const QVector<QUrl> &urlSeeds) override;
bool connectPeer(const PeerAddress &peerAddress) override;
void clearPeers() override;
bool setMetadata(const TorrentInfo &torrentInfo) override;
void setMetadata(const TorrentInfo &torrentInfo) override;
StopCondition stopCondition() const override;
void setStopCondition(StopCondition stopCondition) override;
@ -236,6 +236,13 @@ namespace BitTorrent @@ -236,6 +236,13 @@ namespace BitTorrent
nonstd::expected<QByteArray, QString> exportToBuffer() const override;
nonstd::expected<void, QString> exportToFile(const Path &path) const override;
void fetchPeerInfo(std::function<void (QVector<PeerInfo>)> resultHandler) const override;
void fetchURLSeeds(std::function<void (QVector<QUrl>)> resultHandler) const override;
void fetchFilesProgress(std::function<void (QVector<qreal>)> resultHandler) const override;
void fetchPieceAvailability(std::function<void (QVector<int>)> resultHandler) const override;
void fetchDownloadingPieces(std::function<void (QBitArray)> resultHandler) const override;
void fetchAvailableFileFractions(std::function<void (QVector<qreal>)> resultHandler) const override;
bool needSaveResumeData() const;
// Session interface
@ -292,6 +299,9 @@ namespace BitTorrent @@ -292,6 +299,9 @@ namespace BitTorrent
nonstd::expected<lt::entry, QString> exportTorrent() const;
template <typename Func, typename Callback>
void invokeAsync(Func func, Callback resultHandler) const;
SessionImpl *const m_session = nullptr;
lt::session *m_nativeSession = nullptr;
lt::torrent_handle m_nativeHandle;

20
src/gui/properties/peerlistwidget.cpp

@ -37,6 +37,7 @@ @@ -37,6 +37,7 @@
#include <QHostAddress>
#include <QMenu>
#include <QMessageBox>
#include <QPointer>
#include <QSet>
#include <QShortcut>
#include <QSortFilterProxyModel>
@ -392,16 +393,24 @@ void PeerListWidget::saveSettings() const @@ -392,16 +393,24 @@ void PeerListWidget::saveSettings() const
void PeerListWidget::loadPeers(const BitTorrent::Torrent *torrent)
{
if (!torrent) return;
if (!torrent)
return;
using TorrentPtr = QPointer<const BitTorrent::Torrent>;
torrent->fetchPeerInfo([this, torrent = TorrentPtr(torrent)](const QVector<BitTorrent::PeerInfo> &peers)
{
if (torrent != m_properties->getCurrentTorrent())
return;
const QVector<BitTorrent::PeerInfo> peers = torrent->peers();
QSet<PeerEndpoint> existingPeers;
existingPeers.reserve(m_peerItems.size());
for (auto i = m_peerItems.cbegin(); i != m_peerItems.cend(); ++i)
existingPeers << i.key();
existingPeers.insert(i.key());
for (const BitTorrent::PeerInfo &peer : peers)
{
if (peer.address().ip.isNull()) continue;
if (peer.address().ip.isNull())
continue;
bool isNewPeer = false;
updatePeer(torrent, peer, isNewPeer);
@ -424,6 +433,7 @@ void PeerListWidget::loadPeers(const BitTorrent::Torrent *torrent) @@ -424,6 +433,7 @@ void PeerListWidget::loadPeers(const BitTorrent::Torrent *torrent)
m_listModel->removeRow(item->row());
}
});
}
void PeerListWidget::updatePeer(const BitTorrent::Torrent *torrent, const BitTorrent::PeerInfo &peer, bool &isNewPeer)
@ -433,7 +443,7 @@ void PeerListWidget::updatePeer(const BitTorrent::Torrent *torrent, const BitTor @@ -433,7 +443,7 @@ void PeerListWidget::updatePeer(const BitTorrent::Torrent *torrent, const BitTor
const Qt::Alignment intDataTextAlignment = Qt::AlignRight | Qt::AlignVCenter;
const auto setModelData =
[this] (const int row, const int column, const QString &displayData
[this](const int row, const int column, const QString &displayData
, const QVariant &underlyingData, const Qt::Alignment textAlignmentData = {}
, const QString &toolTip = {})
{

49
src/gui/properties/propertieswidget.cpp

@ -34,6 +34,7 @@ @@ -34,6 +34,7 @@
#include <QHeaderView>
#include <QListWidgetItem>
#include <QMenu>
#include <QPointer>
#include <QSplitter>
#include <QShortcut>
#include <QStackedWidget>
@ -498,13 +499,20 @@ void PropertiesWidget::loadDynamicData() @@ -498,13 +499,20 @@ void PropertiesWidget::loadDynamicData()
if (m_torrent->hasMetadata())
{
using TorrentPtr = QPointer<BitTorrent::Torrent>;
m_ui->labelTotalPiecesVal->setText(tr("%1 x %2 (have %3)", "(torrent pieces) eg 152 x 4MB (have 25)").arg(m_torrent->piecesCount()).arg(Utils::Misc::friendlyUnit(m_torrent->pieceLength())).arg(m_torrent->piecesHave()));
if (!m_torrent->isSeed() && !m_torrent->isPaused() && !m_torrent->isQueued() && !m_torrent->isChecking())
{
// Pieces availability
showPiecesAvailability(true);
m_piecesAvailability->setAvailability(m_torrent->pieceAvailability());
m_torrent->fetchPieceAvailability([this, torrent = TorrentPtr(m_torrent)](const QVector<int> &pieceAvailability)
{
if (torrent == m_torrent)
m_piecesAvailability->setAvailability(pieceAvailability);
});
m_ui->labelAverageAvailabilityVal->setText(Utils::String::fromDouble(m_torrent->distributedCopies(), 3));
}
else
@ -515,7 +523,12 @@ void PropertiesWidget::loadDynamicData() @@ -515,7 +523,12 @@ void PropertiesWidget::loadDynamicData()
// Progress
qreal progress = m_torrent->progress() * 100.;
m_ui->labelProgressVal->setText(Utils::String::fromDouble(progress, 1) + u'%');
m_downloadedPieces->setProgress(m_torrent->pieces(), m_torrent->downloadingPieces());
m_torrent->fetchDownloadingPieces([this, torrent = TorrentPtr(m_torrent)](const QBitArray &downloadingPieces)
{
if (torrent == m_torrent)
m_downloadedPieces->setProgress(m_torrent->pieces(), downloadingPieces);
});
}
else
{
@ -538,6 +551,19 @@ void PropertiesWidget::loadDynamicData() @@ -538,6 +551,19 @@ void PropertiesWidget::loadDynamicData()
qDebug("Updating priorities in files tab");
m_ui->filesList->setUpdatesEnabled(false);
using TorrentPtr = QPointer<BitTorrent::Torrent>;
m_torrent->fetchFilesProgress([this, torrent = TorrentPtr(m_torrent)](const QVector<qreal> &filesProgress)
{
if (torrent == m_torrent)
m_propListModel->model()->updateFilesProgress(filesProgress);
});
m_torrent->fetchAvailableFileFractions([this, torrent = TorrentPtr(m_torrent)](const QVector<qreal> &availableFileFractions)
{
if (torrent == m_torrent)
m_propListModel->model()->updateFilesAvailability(availableFileFractions);
});
// Load torrent content if not yet done so
const bool isContentInitialized = m_propListModel->model()->hasIndex(0, 0);
if (!isContentInitialized)
@ -546,9 +572,6 @@ void PropertiesWidget::loadDynamicData() @@ -546,9 +572,6 @@ void PropertiesWidget::loadDynamicData()
m_propListModel->model()->setupModelData(*m_torrent);
// Load file priorities
m_propListModel->model()->updateFilesPriorities(m_torrent->filePriorities());
// Update file progress/availability
m_propListModel->model()->updateFilesProgress(m_torrent->filesProgress());
m_propListModel->model()->updateFilesAvailability(m_torrent->availableFileFractions());
// Expand single-item folders recursively.
// This will trigger sorting and filtering so do it after all relevant data is loaded.
@ -563,8 +586,6 @@ void PropertiesWidget::loadDynamicData() @@ -563,8 +586,6 @@ void PropertiesWidget::loadDynamicData()
{
// Torrent content was loaded already, only make some updates
m_propListModel->model()->updateFilesProgress(m_torrent->filesProgress());
m_propListModel->model()->updateFilesAvailability(m_torrent->availableFileFractions());
// XXX: We don't update file priorities regularly for performance
// reasons. This means that priorities will not be updated if
// set from the Web UI.
@ -583,15 +604,21 @@ void PropertiesWidget::loadUrlSeeds() @@ -583,15 +604,21 @@ void PropertiesWidget::loadUrlSeeds()
if (!m_torrent)
return;
using TorrentPtr = QPointer<BitTorrent::Torrent>;
m_torrent->fetchURLSeeds([this, torrent = TorrentPtr(m_torrent)](const QVector<QUrl> &urlSeeds)
{
if (torrent != m_torrent)
return;
m_ui->listWebSeeds->clear();
qDebug("Loading URL seeds");
const QVector<QUrl> hcSeeds = m_torrent->urlSeeds();
// Add url seeds
for (const QUrl &hcSeed : hcSeeds)
for (const QUrl &urlSeed : urlSeeds)
{
qDebug("Loading URL seed: %s", qUtf8Printable(hcSeed.toString()));
new QListWidgetItem(hcSeed.toString(), m_ui->listWebSeeds);
qDebug("Loading URL seed: %s", qUtf8Printable(urlSeed.toString()));
new QListWidgetItem(urlSeed.toString(), m_ui->listWebSeeds);
}
});
}
Path PropertiesWidget::getFullPath(const QModelIndex &index) const

13
src/gui/properties/trackerlistwidget.cpp

@ -36,6 +36,7 @@ @@ -36,6 +36,7 @@
#include <QHeaderView>
#include <QMenu>
#include <QMessageBox>
#include <QPointer>
#include <QShortcut>
#include <QStringList>
#include <QTreeWidgetItem>
@ -310,12 +311,19 @@ void TrackerListWidget::loadStickyItems(const BitTorrent::Torrent *torrent) @@ -310,12 +311,19 @@ void TrackerListWidget::loadStickyItems(const BitTorrent::Torrent *torrent)
m_LSDItem->setText(COL_MSG, privateMsg);
}
using TorrentPtr = QPointer<const BitTorrent::Torrent>;
torrent->fetchPeerInfo([this, torrent = TorrentPtr(torrent)](const QVector<BitTorrent::PeerInfo> &peers)
{
if (torrent != m_properties->getCurrentTorrent())
return;
// XXX: libtorrent should provide this info...
// Count peers from DHT, PeX, LSD
uint seedsDHT = 0, seedsPeX = 0, seedsLSD = 0, peersDHT = 0, peersPeX = 0, peersLSD = 0;
for (const BitTorrent::PeerInfo &peer : asConst(torrent->peers()))
for (const BitTorrent::PeerInfo &peer : peers)
{
if (peer.isConnecting()) continue;
if (peer.isConnecting())
continue;
if (peer.fromDHT())
{
@ -346,6 +354,7 @@ void TrackerListWidget::loadStickyItems(const BitTorrent::Torrent *torrent) @@ -346,6 +354,7 @@ void TrackerListWidget::loadStickyItems(const BitTorrent::Torrent *torrent)
m_PEXItem->setText(COL_LEECHES, QString::number(peersPeX));
m_LSDItem->setText(COL_SEEDS, QString::number(seedsLSD));
m_LSDItem->setText(COL_LEECHES, QString::number(peersLSD));
});
}
void TrackerListWidget::loadTrackers()

Loading…
Cancel
Save