mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2025-12-21 07:57:22 -06:00
Merge pull request #18034 from glassez/fetch-async
Fetch data asynchronously
This commit is contained in:
@@ -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 @@
|
||||
#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
|
||||
: 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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
class Torrent;
|
||||
struct PeerAddress;
|
||||
|
||||
class PeerInfo
|
||||
@@ -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
|
||||
int downloadingPieceIndex() const;
|
||||
|
||||
private:
|
||||
qreal calcRelevance(const Torrent *torrent) const;
|
||||
qreal calcRelevance(const QBitArray &allPieces) const;
|
||||
void determineFlags();
|
||||
|
||||
lt::peer_info m_nativeInfo = {};
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
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
|
||||
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
|
||||
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
|
||||
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;
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#include <QByteArray>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QPointer>
|
||||
#include <QSet>
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
@@ -236,7 +237,7 @@ namespace
|
||||
|
||||
TorrentImpl::TorrentImpl(SessionImpl *session, lt::session *nativeSession
|
||||
, const lt::torrent_handle &nativeHandle, const LoadTorrentParams ¶ms)
|
||||
: QObject(session)
|
||||
: Torrent(session)
|
||||
, m_session(session)
|
||||
, m_nativeSession(nativeSession)
|
||||
, m_nativeHandle(nativeHandle)
|
||||
@@ -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();
|
||||
|
||||
QVector<QUrl> addedUrlSeeds;
|
||||
addedUrlSeeds.reserve(urlSeeds.size());
|
||||
|
||||
for (const QUrl &url : urlSeeds)
|
||||
m_session->invokeAsync([urlSeeds, session = m_session
|
||||
, nativeHandle = m_nativeHandle
|
||||
, thisTorrent = QPointer<TorrentImpl>(this)]
|
||||
{
|
||||
const std::string nativeUrl = url.toString().toStdString();
|
||||
if (currentSeeds.find(nativeUrl) == currentSeeds.end())
|
||||
try
|
||||
{
|
||||
m_nativeHandle.add_url_seed(nativeUrl);
|
||||
addedUrlSeeds << url;
|
||||
}
|
||||
}
|
||||
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));
|
||||
|
||||
if (!addedUrlSeeds.isEmpty())
|
||||
{
|
||||
m_session->handleTorrentNeedSaveResumeData(this);
|
||||
m_session->handleTorrentUrlSeedsAdded(this, addedUrlSeeds);
|
||||
}
|
||||
QVector<QUrl> addedUrlSeeds;
|
||||
addedUrlSeeds.reserve(urlSeeds.size());
|
||||
|
||||
for (const QUrl &url : urlSeeds)
|
||||
{
|
||||
if (!currentSeeds.contains(url))
|
||||
{
|
||||
nativeHandle.add_url_seed(url.toString().toStdString());
|
||||
addedUrlSeeds.append(url);
|
||||
}
|
||||
}
|
||||
|
||||
session->invoke([session, thisTorrent, addedUrlSeeds]
|
||||
{
|
||||
if (!thisTorrent)
|
||||
return;
|
||||
|
||||
if (!addedUrlSeeds.isEmpty())
|
||||
{
|
||||
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();
|
||||
|
||||
QVector<QUrl> removedUrlSeeds;
|
||||
removedUrlSeeds.reserve(urlSeeds.size());
|
||||
|
||||
for (const QUrl &url : urlSeeds)
|
||||
m_session->invokeAsync([urlSeeds, session = m_session
|
||||
, nativeHandle = m_nativeHandle
|
||||
, thisTorrent = QPointer<TorrentImpl>(this)]
|
||||
{
|
||||
const std::string nativeUrl = url.toString().toStdString();
|
||||
if (currentSeeds.find(nativeUrl) != currentSeeds.end())
|
||||
try
|
||||
{
|
||||
m_nativeHandle.remove_url_seed(nativeUrl);
|
||||
removedUrlSeeds << url;
|
||||
}
|
||||
}
|
||||
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));
|
||||
|
||||
if (!removedUrlSeeds.isEmpty())
|
||||
{
|
||||
m_session->handleTorrentNeedSaveResumeData(this);
|
||||
m_session->handleTorrentUrlSeedsRemoved(this, removedUrlSeeds);
|
||||
}
|
||||
QVector<QUrl> removedUrlSeeds;
|
||||
removedUrlSeeds.reserve(urlSeeds.size());
|
||||
|
||||
for (const QUrl &url : urlSeeds)
|
||||
{
|
||||
if (currentSeeds.contains(url))
|
||||
{
|
||||
nativeHandle.remove_url_seed(url.toString().toStdString());
|
||||
removedUrlSeeds.append(url);
|
||||
}
|
||||
}
|
||||
|
||||
session->invoke([session, thisTorrent, removedUrlSeeds]
|
||||
{
|
||||
if (!thisTorrent)
|
||||
return;
|
||||
|
||||
if (!removedUrlSeeds.isEmpty())
|
||||
{
|
||||
session->handleTorrentNeedSaveResumeData(thisTorrent);
|
||||
session->handleTorrentUrlSeedsRemoved(thisTorrent, removedUrlSeeds);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (const std::exception &) {}
|
||||
});
|
||||
}
|
||||
|
||||
void TorrentImpl::clearPeers()
|
||||
@@ -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)
|
||||
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
|
||||
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()));
|
||||
const std::shared_ptr<lt::torrent_info> nativeInfo = torrentInfo.nativeInfo();
|
||||
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
|
||||
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
|
||||
}
|
||||
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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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
|
||||
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
|
||||
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
|
||||
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user