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 8b2d8f3 commit 8bc3458
Show file tree
Hide file tree
Showing 7 changed files with 510 additions and 273 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 @@ -5698,7 +5702,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
244 changes: 244 additions & 0 deletions src/base/bittorrent/torrentbackend.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
/*
* 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 "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);

// TODO: Handle status update!
// m_nativeStatus = extensionData->status;

if (queuePos >= lt::queue_position_t {})
m_ltTorrentHandle.queue_position_set(queuePos);
}
81 changes: 81 additions & 0 deletions src/base/bittorrent/torrentbackend.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* 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.
*/

#pragma once

#include <libtorrent/fwd.hpp>
#include <libtorrent/torrent_handle.hpp>

#include <QList>
#include <QObject>
#include <QUrl>

#include "torrent.h"
// TODO: Move TorrentOperatingMode to separate header!

namespace BitTorrent
{
struct PeerAddress;
struct SSLParameters;
struct TrackerEntry;

class TorrentBackend final : public QObject
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(TorrentBackend)

public:
TorrentBackend(lt::session *ltSession, lt::torrent_handle ltTorrentHandle, QObject *parent = nullptr);

void start(TorrentOperatingMode mode);
void stop();
void forceReannounce(int index);
void forceDHTAnnounce();
void addTrackers(const QList<TrackerEntry> &trackers);
void replaceTrackers(const QList<TrackerEntry> &trackers);
void addUrlSeeds(const QList<QUrl> &urlSeeds);
void removeUrlSeeds(const QList<QUrl> &urlSeeds);
void connectPeer(const PeerAddress &peerAddress);
void clearPeers();
void setSequentialDownload(bool enable);
void setSuperSeeding(bool enable);
void setDHTDisabled(bool enable);
void setPEXDisabled(bool disable);
void setLSDDisabled(bool disable);
void setSSLParameters(const SSLParameters &sslParameters);
void setDownloadLimit(int limit);
void setUploadLimit(int limit);
void flushCache();
void requestResumeData(lt::resume_data_flags_t flags);
void reload(const lt::add_torrent_params &ltAddTorrentParams, bool isStopped, TorrentOperatingMode operatingMode);

private:
lt::session *m_ltSession;
lt::torrent_handle m_ltTorrentHandle;
};
}
Loading

0 comments on commit 8bc3458

Please sign in to comment.