Skip to content

Commit

Permalink
Improve interaction with backend
Browse files Browse the repository at this point in the history
  • Loading branch information
glassez committed Oct 1, 2024
1 parent b5b34c9 commit 550c0f2
Show file tree
Hide file tree
Showing 7 changed files with 548 additions and 279 deletions.
2 changes: 2 additions & 0 deletions src/base/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ add_library(qbt_base STATIC
bittorrent/speedmonitor.h
bittorrent/sslparameters.h
bittorrent/torrent.h
bittorrent/torrentbackend.h
bittorrent/torrentcontenthandler.h
bittorrent/torrentcontentlayout.h
bittorrent/torrentcontentremoveoption.h
Expand Down Expand Up @@ -146,6 +147,7 @@ add_library(qbt_base STATIC
bittorrent/speedmonitor.cpp
bittorrent/sslparameters.cpp
bittorrent/torrent.cpp
bittorrent/torrentbackend.cpp
bittorrent/torrentcontenthandler.cpp
bittorrent/torrentcontentremover.cpp
bittorrent/torrentcreationmanager.cpp
Expand Down
12 changes: 11 additions & 1 deletion src/base/bittorrent/sessionimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
#include "nativesessionextension.h"
#include "portforwarderimpl.h"
#include "resumedatastorage.h"
#include "torrentbackend.h"
#include "torrentcontentremover.h"
#include "torrentdescriptor.h"
#include "torrentimpl.h"
Expand Down Expand Up @@ -530,6 +531,7 @@ SessionImpl::SessionImpl(QObject *parent)
, m_startPaused {BITTORRENT_SESSION_KEY(u"StartPaused"_s)}
, m_seedingLimitTimer {new QTimer(this)}
, m_resumeDataTimer {new QTimer(this)}
, m_backendThread {new QThread}
, m_ioThread {new QThread}
, m_asyncWorker {new QThreadPool(this)}
, m_recentErroredTorrentsTimer {new QTimer(this)}
Expand Down Expand Up @@ -590,6 +592,8 @@ SessionImpl::SessionImpl(QObject *parent)
, &Net::ProxyConfigurationManager::proxyConfigurationChanged
, this, &SessionImpl::configureDeferred);

m_backendThread->start();

m_fileSearcher = new FileSearcher;
m_fileSearcher->moveToThread(m_ioThread.get());
connect(m_ioThread.get(), &QThread::finished, m_fileSearcher, &QObject::deleteLater);
Expand Down Expand Up @@ -5706,7 +5710,13 @@ void SessionImpl::dispatchTorrentAlert(const lt::torrent_alert *alert)

TorrentImpl *SessionImpl::createTorrent(const lt::torrent_handle &nativeHandle, const LoadTorrentParams &params)
{
auto *const torrent = new TorrentImpl(this, m_nativeSession, nativeHandle, params);
auto *const torrentBackend = new TorrentBackend(m_nativeSession, nativeHandle);
torrentBackend->moveToThread(m_backendThread.get());
connect(m_backendThread.get(), &QThread::finished, torrentBackend, &QObject::deleteLater);

auto *const torrent = new TorrentImpl(this, torrentBackend, m_nativeSession, nativeHandle, params);
connect(torrent, &QObject::destroyed, torrentBackend, &QObject::deleteLater);

m_torrents.insert(torrent->id(), torrent);
if (const InfoHash infoHash = torrent->infoHash(); infoHash.isHybrid())
m_hybridTorrentsByAltID.insert(TorrentID::fromSHA1Hash(infoHash.v1()), torrent);
Expand Down
1 change: 1 addition & 0 deletions src/base/bittorrent/sessionimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,7 @@ namespace BitTorrent
// Tracker
QPointer<Tracker> m_tracker;

Utils::Thread::UniquePtr m_backendThread;
Utils::Thread::UniquePtr m_ioThread;
QThreadPool *m_asyncWorker = nullptr;
ResumeDataStorage *m_resumeDataStorage = nullptr;
Expand Down
268 changes: 268 additions & 0 deletions src/base/bittorrent/torrentbackend.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2024 Vladimir Golovnev <[email protected]>
*
* 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 "torrentbackend.h"

#include <libtorrent/announce_entry.hpp>
#include <libtorrent/session.hpp>
#include <libtorrent/torrent_status.hpp>

#include <QPromise>

#include "extensiondata.h"
#include "peeraddress.h"
#include "sslparameters.h"
#include "trackerentry.h"

#ifndef QBT_USES_LIBTORRENT2
#include "customstorage.h"
#endif

namespace
{
lt::announce_entry makeLTAnnounceEntry(const QString &url, const int tier)
{
lt::announce_entry entry {url.toStdString()};
entry.tier = tier;
return entry;
}
}

BitTorrent::TorrentBackend::TorrentBackend(lt::session *ltSession, lt::torrent_handle ltTorrentHandle, QObject *parent)
: QObject(parent)
, m_ltSession {ltSession}
, m_ltTorrentHandle {std::move(ltTorrentHandle)}
{
}

void BitTorrent::TorrentBackend::start(const TorrentOperatingMode mode)
{
m_ltTorrentHandle.clear_error();
m_ltTorrentHandle.unset_flags(lt::torrent_flags::upload_mode);

if (mode == TorrentOperatingMode::Forced)
{
m_ltTorrentHandle.unset_flags(lt::torrent_flags::auto_managed);
m_ltTorrentHandle.resume();
}
else
{
m_ltTorrentHandle.set_flags(lt::torrent_flags::auto_managed);
}
}

void BitTorrent::TorrentBackend::stop()
{
m_ltTorrentHandle.unset_flags(lt::torrent_flags::auto_managed);
m_ltTorrentHandle.pause();
}

void BitTorrent::TorrentBackend::forceReannounce(const int index)
{
m_ltTorrentHandle.force_reannounce(0, index);
}

void BitTorrent::TorrentBackend::forceDHTAnnounce()
{
m_ltTorrentHandle.force_dht_announce();
}

void BitTorrent::TorrentBackend::addTrackers(const QList<TrackerEntry> &trackers)
{
for (const TrackerEntry &tracker : trackers)
m_ltTorrentHandle.add_tracker(makeLTAnnounceEntry(tracker.url, tracker.tier));
}

void BitTorrent::TorrentBackend::replaceTrackers(const QList<TrackerEntry> &trackers)
{
std::vector<lt::announce_entry> ltAnnounceEntries;
ltAnnounceEntries.reserve(trackers.size());
for (const TrackerEntry &tracker : trackers)
ltAnnounceEntries.emplace_back(makeLTAnnounceEntry(tracker.url, tracker.tier));
m_ltTorrentHandle.replace_trackers(ltAnnounceEntries);
}

void BitTorrent::TorrentBackend::addUrlSeeds(const QList<QUrl> &urlSeeds)
{
for (const QUrl &url : urlSeeds)
m_ltTorrentHandle.add_url_seed(url.toString().toStdString());
}

void BitTorrent::TorrentBackend::removeUrlSeeds(const QList<QUrl> &urlSeeds)
{
for (const QUrl &url : urlSeeds)
m_ltTorrentHandle.remove_url_seed(url.toString().toStdString());
}

void BitTorrent::TorrentBackend::connectPeer(const PeerAddress &peerAddress)
{
try
{
lt::error_code ec;
const lt::address addr = lt::make_address(peerAddress.ip.toString().toStdString(), ec);
if (ec)
throw lt::system_error(ec);

m_ltTorrentHandle.connect_peer({addr, peerAddress.port});
}
catch (const lt::system_error &)
{
}
}

void BitTorrent::TorrentBackend::clearPeers()
{
m_ltTorrentHandle.clear_peers();
}

void BitTorrent::TorrentBackend::setSequentialDownload(const bool enable)
{
if (enable)
m_ltTorrentHandle.set_flags(lt::torrent_flags::sequential_download);
else
m_ltTorrentHandle.unset_flags(lt::torrent_flags::sequential_download);
}

void BitTorrent::TorrentBackend::setSuperSeeding(const bool enable)
{
if (enable)
m_ltTorrentHandle.set_flags(lt::torrent_flags::super_seeding);
else
m_ltTorrentHandle.unset_flags(lt::torrent_flags::super_seeding);
}

void BitTorrent::TorrentBackend::setDHTDisabled(const bool disable)
{
if (disable)
m_ltTorrentHandle.set_flags(lt::torrent_flags::disable_dht);
else
m_ltTorrentHandle.unset_flags(lt::torrent_flags::disable_dht);
}

void BitTorrent::TorrentBackend::setPEXDisabled(const bool disable)
{
if (disable)
m_ltTorrentHandle.set_flags(lt::torrent_flags::disable_pex);
else
m_ltTorrentHandle.unset_flags(lt::torrent_flags::disable_pex);
}

void BitTorrent::TorrentBackend::setLSDDisabled(const bool disable)
{
if (disable)
m_ltTorrentHandle.set_flags(lt::torrent_flags::disable_lsd);
else
m_ltTorrentHandle.unset_flags(lt::torrent_flags::disable_lsd);
}

void BitTorrent::TorrentBackend::setSSLParameters(const SSLParameters &sslParameters)
{
m_ltTorrentHandle.set_ssl_certificate_buffer(sslParameters.certificate.toPem().toStdString()
, sslParameters.privateKey.toPem().toStdString(), sslParameters.dhParams.toStdString());
}

void BitTorrent::TorrentBackend::setDownloadLimit(const int limit)
{
m_ltTorrentHandle.set_download_limit(limit);
}

void BitTorrent::TorrentBackend::setUploadLimit(const int limit)
{
m_ltTorrentHandle.set_upload_limit(limit);
}

void BitTorrent::TorrentBackend::flushCache()
{
m_ltTorrentHandle.flush_cache();
}

void BitTorrent::TorrentBackend::requestResumeData(const lt::resume_data_flags_t flags)
{
m_ltTorrentHandle.save_resume_data(flags);
}

void BitTorrent::TorrentBackend::reload(const lt::add_torrent_params &ltAddTorrentParams
, const bool isStopped, const TorrentOperatingMode operatingMode)
{
const auto queuePos = m_ltTorrentHandle.queue_position();

m_ltSession->remove_torrent(m_ltTorrentHandle, lt::session::delete_partfile);

lt::add_torrent_params p = ltAddTorrentParams;
p.flags |= lt::torrent_flags::update_subscribe
| lt::torrent_flags::override_trackers
| lt::torrent_flags::override_web_seeds;

if (isStopped)
{
p.flags |= lt::torrent_flags::paused;
p.flags &= ~lt::torrent_flags::auto_managed;
}
else if (operatingMode == TorrentOperatingMode::AutoManaged)
{
p.flags |= (lt::torrent_flags::auto_managed | lt::torrent_flags::paused);
}
else
{
p.flags &= ~(lt::torrent_flags::auto_managed | lt::torrent_flags::paused);
}

auto *const extensionData = new ExtensionData;
p.userdata = LTClientData(extensionData);
#ifndef QBT_USES_LIBTORRENT2
p.storage = customStorageConstructor;
#endif
m_ltTorrentHandle = m_ltSession->add_torrent(p);

if (queuePos >= lt::queue_position_t {})
m_ltTorrentHandle.queue_position_set(queuePos);

lt::torrent_status torrentStatus = extensionData->status;
torrentStatus.queue_position = queuePos;

emit reloaded(torrentStatus);
}

// QFuture<QList<BitTorrent::PeerInfo>> BitTorrent::TorrentBackend::peers()
// {
// QPromise<QList<BitTorrent::PeerInfo>> promise;
// QFuture<QList<BitTorrent::PeerInfo>> future = promise.future();
// promise.start();

// std::vector<lt::peer_info> nativePeers;
// m_ltTorrentHandle.get_peer_info(nativePeers);

// QList<PeerInfo> peers;
// peers.reserve(static_cast<decltype(peers)::size_type>(nativePeers.size()));

// for (const lt::peer_info &peer : nativePeers)
// peers.append(PeerInfo(peer, pieces()));

// promise.addResult(peers);
// return future;
// }
Loading

0 comments on commit 550c0f2

Please sign in to comment.