Skip to content

Commit

Permalink
Temp
Browse files Browse the repository at this point in the history
  • Loading branch information
glassez committed Dec 25, 2024
1 parent 3fed1fd commit 5d372f2
Show file tree
Hide file tree
Showing 9 changed files with 148 additions and 79 deletions.
11 changes: 8 additions & 3 deletions src/base/bittorrent/bencoderesumedatastorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,8 +265,11 @@ BitTorrent::LoadResumeDataResult BitTorrent::BencodeResumeDataStorage::loadTorre
torrentParams.stopCondition = Utils::String::toEnum(
fromLTString(resumeDataRoot.dict_find_string_value("qBt-stopCondition")), Torrent::StopCondition::None);

torrentParams.storedTorrentFilePath = Profile::instance()->fromPortablePath(
Path(fromLTString(resumeDataRoot.dict_find_string_value("qBt-storedTorrentFilePath"))));
const QString storedTorrentInfo = fromLTString(resumeDataRoot.dict_find_string_value("qBt-storedTorrentInfo"));
if (storedTorrentInfo.startsWith(u"magnet:"))
torrentParams.storedTorrentInfo = storedTorrentInfo;
else
torrentParams.storedTorrentInfo = Profile::instance()->fromPortablePath(Path(storedTorrentInfo));

torrentParams.sslParameters =
{
Expand Down Expand Up @@ -432,7 +435,9 @@ void BitTorrent::BencodeResumeDataStorage::Worker::store(const TorrentID &id, co
data["qBt-contentLayout"] = Utils::String::fromEnum(resumeData.contentLayout).toStdString();
data["qBt-firstLastPiecePriority"] = resumeData.firstLastPiecePriority;
data["qBt-stopCondition"] = Utils::String::fromEnum(resumeData.stopCondition).toStdString();
data["qBt-storedTorrentFilePath"] = Profile::instance()->toPortablePath(resumeData.storedTorrentFilePath).data().toStdString();
data["qBt-storedTorrentInfo"] = std::holds_alternative<QString>(resumeData.storedTorrentInfo)
? std::get<QString>(resumeData.storedTorrentInfo).toStdString()
: Profile::instance()->toPortablePath(std::get<Path>(resumeData.storedTorrentInfo)).data().toStdString();

if (!resumeData.sslParameters.certificate.isNull())
data[KEY_SSL_CERTIFICATE] = resumeData.sslParameters.certificate.toPem().toStdString();
Expand Down
19 changes: 12 additions & 7 deletions src/base/bittorrent/dbresumedatastorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ namespace
const Column DB_COLUMN_OPERATING_MODE = makeColumn(u"operating_mode"_s);
const Column DB_COLUMN_STOPPED = makeColumn(u"stopped"_s);
const Column DB_COLUMN_STOP_CONDITION = makeColumn(u"stop_condition"_s);
const Column DB_COLUMN_STORED_TORRENT_FILE_PATH = makeColumn(u"torrent_file_copy_path"_s);
const Column DB_COLUMN_STORED_TORRENT_INFO = makeColumn(u"stored_torrent_info"_s);
const Column DB_COLUMN_SSL_CERTIFICATE = makeColumn(u"ssl_certificate"_s);
const Column DB_COLUMN_SSL_PRIVATE_KEY = makeColumn(u"ssl_private_key"_s);
const Column DB_COLUMN_SSL_DH_PARAMS = makeColumn(u"ssl_dh_params"_s);
Expand Down Expand Up @@ -244,8 +244,11 @@ namespace
resumeData.stopped = query.value(DB_COLUMN_STOPPED.name).toBool();
resumeData.stopCondition = Utils::String::toEnum(
query.value(DB_COLUMN_STOP_CONDITION.name).toString(), Torrent::StopCondition::None);
resumeData.storedTorrentFilePath = Profile::instance()->fromPortablePath(
Path(query.value(DB_COLUMN_STORED_TORRENT_FILE_PATH.name).toString()));
const QString storedTorrentInfo = query.value(DB_COLUMN_STORED_TORRENT_INFO.name).toString();
if (storedTorrentInfo.startsWith(u"magnet:"))
resumeData.storedTorrentInfo = storedTorrentInfo;
else
resumeData.storedTorrentInfo = Profile::instance()->fromPortablePath(Path(storedTorrentInfo));
resumeData.sslParameters =
{
.certificate = QSslCertificate(query.value(DB_COLUMN_SSL_CERTIFICATE.name).toByteArray()),
Expand Down Expand Up @@ -550,7 +553,7 @@ void BitTorrent::DBResumeDataStorage::createDB() const
makeColumnDefinition(DB_COLUMN_OPERATING_MODE, u"TEXT NOT NULL"_s),
makeColumnDefinition(DB_COLUMN_STOPPED, u"INTEGER NOT NULL"_s),
makeColumnDefinition(DB_COLUMN_STOP_CONDITION, u"TEXT NOT NULL DEFAULT `None`"_s),
makeColumnDefinition(DB_COLUMN_STORED_TORRENT_FILE_PATH, u"TEXT"_s),
makeColumnDefinition(DB_COLUMN_STORED_TORRENT_INFO, u"TEXT"_s),
makeColumnDefinition(DB_COLUMN_SSL_CERTIFICATE, u"TEXT"_s),
makeColumnDefinition(DB_COLUMN_SSL_PRIVATE_KEY, u"TEXT"_s),
makeColumnDefinition(DB_COLUMN_SSL_DH_PARAMS, u"TEXT"_s),
Expand Down Expand Up @@ -657,7 +660,7 @@ void BitTorrent::DBResumeDataStorage::updateDB(const int fromVersion) const
}

if (fromVersion <= 8)
addColumn(DB_TABLE_TORRENTS, DB_COLUMN_STORED_TORRENT_FILE_PATH, u"TEXT"_s);
addColumn(DB_TABLE_TORRENTS, DB_COLUMN_STORED_TORRENT_INFO, u"TEXT"_s);

const QString updateMetaVersionQuery = makeUpdateStatement(DB_TABLE_META, {DB_COLUMN_NAME, DB_COLUMN_VALUE});
if (!query.prepare(updateMetaVersionQuery))
Expand Down Expand Up @@ -843,7 +846,7 @@ namespace
DB_COLUMN_OPERATING_MODE,
DB_COLUMN_STOPPED,
DB_COLUMN_STOP_CONDITION,
DB_COLUMN_STORED_TORRENT_FILE_PATH,
DB_COLUMN_STORED_TORRENT_INFO,
DB_COLUMN_SSL_CERTIFICATE,
DB_COLUMN_SSL_PRIVATE_KEY,
DB_COLUMN_SSL_DH_PARAMS,
Expand Down Expand Up @@ -907,7 +910,9 @@ namespace
query.bindValue(DB_COLUMN_OPERATING_MODE.placeholder, Utils::String::fromEnum(m_resumeData.operatingMode));
query.bindValue(DB_COLUMN_STOPPED.placeholder, m_resumeData.stopped);
query.bindValue(DB_COLUMN_STOP_CONDITION.placeholder, Utils::String::fromEnum(m_resumeData.stopCondition));
query.bindValue(DB_COLUMN_STORED_TORRENT_FILE_PATH.placeholder, Profile::instance()->toPortablePath(m_resumeData.storedTorrentFilePath).data());
query.bindValue(DB_COLUMN_STORED_TORRENT_INFO.placeholder, std::holds_alternative<QString>(m_resumeData.storedTorrentInfo)
? std::get<QString>(m_resumeData.storedTorrentInfo)
: Profile::instance()->toPortablePath(std::get<Path>(m_resumeData.storedTorrentInfo)).data());
query.bindValue(DB_COLUMN_SSL_CERTIFICATE.placeholder, QString::fromLatin1(m_resumeData.sslParameters.certificate.toPem()));
query.bindValue(DB_COLUMN_SSL_PRIVATE_KEY.placeholder, QString::fromLatin1(m_resumeData.sslParameters.privateKey.toPem()));
query.bindValue(DB_COLUMN_SSL_DH_PARAMS.placeholder, QString::fromLatin1(m_resumeData.sslParameters.dhParams));
Expand Down
4 changes: 3 additions & 1 deletion src/base/bittorrent/loadtorrentparams.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@

#pragma once

#include <variant>

#include <libtorrent/add_torrent_params.hpp>

#include <QString>
Expand Down Expand Up @@ -57,7 +59,7 @@ namespace BitTorrent
bool hasFinishedStatus = false;
bool stopped = false;
Torrent::StopCondition stopCondition = Torrent::StopCondition::None;
Path storedTorrentFilePath;
std::variant<QString, Path> storedTorrentInfo;

bool addToQueueTop = false; // only for new torrents

Expand Down
137 changes: 87 additions & 50 deletions src/base/bittorrent/sessionimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3127,11 +3127,10 @@ nonstd::expected<Path, QString> SessionImpl::createTorrentFile(const Torrent *to
return nonstd::make_unexpected(tr("Unable to create folder. Path: \"%1\".").arg(folderPath.toString()));

const Path torrentFilePath = generateTorrentFilePath(folderPath, torrent->name());
const auto result = torrent->exportToFile(torrentFilePath);
if (result)
return torrentFilePath;
if (const auto result = torrent->exportToFile(torrentFilePath); !result)
return nonstd::make_unexpected(result.error());

return nonstd::make_unexpected(result.error());
return torrentFilePath;
}

nonstd::expected<Path, QString> SessionImpl::createTorrentFile(const TorrentDescriptor &torrentDescr, const Path &folderPath)
Expand Down Expand Up @@ -5066,6 +5065,45 @@ void SessionImpl::updateSeedingLimitTimer()
}
}

void SessionImpl::storeTorrentFile(TorrentImpl *torrent)
{
const Path storeDir = torrentFileStoreDirectory();
if (!isStoreTorrentFileEnabled() || storeDir.isEmpty())
return;

const std::variant<QString, Path> storedTorrentInfo = torrent->storedTorrentInfo();
if (!std::holds_alternative<QString>(storedTorrentInfo))
return;

const QString originalMagnetURI = std::get<QString>(storedTorrentInfo);
if (originalMagnetURI.isEmpty())
return;

const auto parseResult = TorrentDescriptor::parse(originalMagnetURI);
if (!parseResult)
{
LogMsg(tr("Failed to store .torrent file. Torrent: \"%1\". Destination: \"%2\". Reason: \"%3\".")
.arg(torrent->name(), storeDir.toString(), parseResult.error()), Log::WARNING);
return;
}

TorrentDescriptor torrentDescr = parseResult.value();
torrentDescr.setTorrentInfo(torrent->info());

if (const auto result = createTorrentFile(torrentDescr, storeDir))
{
const Path torrentFilePath = result.value();
torrent->setStoredTorrentInfo(torrentFilePath);
LogMsg(tr("Stored .torrent file. Torrent: \"%1\". Destination: \"%2\".")
.arg(torrent->name(), torrentFilePath.toString()));
}
else
{
LogMsg(tr("Failed to store .torrent file. Torrent: \"%1\". Destination: \"%2\". Reason: \"%3\".")
.arg(torrent->name(), result.value().toString(), result.error()), Log::WARNING);
}
}

void SessionImpl::handleTorrentShareLimitChanged(TorrentImpl *const)
{
updateSeedingLimitTimer();
Expand Down Expand Up @@ -5133,23 +5171,7 @@ void SessionImpl::handleTorrentUrlSeedsRemoved(TorrentImpl *const torrent, const

void SessionImpl::handleTorrentMetadataReceived(TorrentImpl *const torrent)
{
if (const Path storeDir = torrentFileStoreDirectory();
isStoreTorrentFileEnabled() && !storeDir.isEmpty())
{
if (const auto result = createTorrentFile(torrent, storeDir))
{
const Path torrentFilePath = result.value();
torrent->setStoredTorrentFilePath(torrentFilePath);
LogMsg(tr("Created .torrent file. Torrent: \"%1\". Destination: \"%2\".")
.arg(torrent->name(), torrentFilePath.toString()));
}
else
{
LogMsg(tr("Failed to create .torrent file. Torrent: \"%1\". Destination: \"%2\". Reason: \"%3\"")
.arg(torrent->name(), result.value().toString(), result.error()), Log::WARNING);
}
}

storeTorrentFile(torrent);
emit torrentMetadataReceived(torrent);
}

Expand Down Expand Up @@ -5320,28 +5342,12 @@ void SessionImpl::processPendingFinishedTorrents()
if (m_pendingFinishedTorrents.isEmpty())
return;

const Path storeDir = torrentFileStoreDirectory();
const bool needStoreTorrentFile = isStoreTorrentFileEnabled() && !storeDir.isEmpty();
for (TorrentImpl *torrent : asConst(m_pendingFinishedTorrents))
{
LogMsg(tr("Torrent download finished. Torrent: \"%1\"").arg(torrent->name()));
emit torrentFinished(torrent);

if (needStoreTorrentFile)
{
if (const auto result = createTorrentFile(torrent, storeDir))
{
const Path torrentFilePath = result.value();
torrent->setStoredTorrentFilePath(torrentFilePath);
LogMsg(tr("Created .torrent file. Torrent: \"%1\". Destination: \"%2\".")
.arg(torrent->name(), torrentFilePath.toString()));
}
else
{
LogMsg(tr("Failed to create .torrent file. Torrent: \"%1\". Destination: \"%2\". Reason: \"%3\"")
.arg(torrent->name(), result.value().toString(), result.error()), Log::WARNING);
}
}
storeTorrentFile(torrent);

processTorrentShareLimits(torrent);
}
Expand Down Expand Up @@ -5840,23 +5846,54 @@ TorrentImpl *SessionImpl::createTorrent(const lt::torrent_handle &nativeHandle,

torrent->requestResumeData(lt::torrent_handle::save_info_dict);

const TorrentDescriptor torrentSource = m_addingTorrents.take(torrent->id());
const Path copyDir = torrentFileStoreDirectory();

// The following is useless for torrents added without metadata
if (torrentSource.info().has_value() && isStoreTorrentFileEnabled() && !copyDir.isEmpty())
const TorrentDescriptor torrentDescr = m_addingTorrents.take(torrent->id());
if (const Path copyDir = torrentFileStoreDirectory();
isStoreTorrentFileEnabled() && !copyDir.isEmpty())
{
if (const auto result = createTorrentFile(torrentSource, copyDir))
if (torrentDescr.hasCompleteMetadata())
{
const Path torrentFilePath = result.value();
torrent->setStoredTorrentFilePath(torrentFilePath);
LogMsg(tr("Created copy of .torrent file. Torrent: \"%1\". Destination: \"%2\".")
.arg(torrent->name(), torrentFilePath.toString()));
const auto storeTorrent = [&torrentDescr, &copyDir]() -> nonstd::expected<Path, QString>
{
if (!copyDir.exists() && !Utils::Fs::mkpath(copyDir))
return nonstd::make_unexpected(tr("Unable to create folder. Path: \"%1\".").arg(copyDir.toString()));

const Path destFilePath = generateTorrentFilePath(copyDir, torrentDescr.name());

if (std::holds_alternative<Path>(torrentDescr.source()))
{
const Path sourceFilePath = std::get<Path>(torrentDescr.source());
if (!Utils::Fs::copyFile(sourceFilePath, destFilePath))
{
return nonstd::make_unexpected(tr("Unable to copy file. Source: \"%1\". Destination: \"%2\".")
.arg(sourceFilePath.toString(), destFilePath.toString()));
}
}
else
{
if (const auto saveResult = torrentDescr.saveToFile(destFilePath); !saveResult)
return nonstd::make_unexpected(saveResult.error());
}

return destFilePath;
};

if (const auto result = storeTorrent())
{
const Path torrentFilePath = result.value();
torrent->setStoredTorrentInfo(torrentFilePath);
LogMsg(tr("Stored .torrent file. Torrent: \"%1\". Destination: \"%2\".")
.arg(torrent->name(), torrentFilePath.toString()));
}
else
{
LogMsg(tr("Failed to store .torrent file. Torrent: \"%1\". Destination: \"%2\". Reason: \"%3\".")
.arg(torrent->name(), result.value().toString(), result.error()), Log::WARNING);
}
}
else
{
LogMsg(tr("Failed to copy .torrent file. Torrent: \"%1\". Destination: \"%2\". Reason: \"%3\"")
.arg(torrent->name(), result.value().toString(), result.error()), Log::WARNING);
// Store original Magnet URI until metadata is available.
torrent->setStoredTorrentInfo(std::get<QString>(torrentDescr.source()));
}
}
}
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 @@ -562,6 +562,7 @@ namespace BitTorrent

void updateSeedingLimitTimer();

void storeTorrentFile(TorrentImpl *torrent);
nonstd::expected<Path, QString> createTorrentFile(const Torrent *torrent, const Path &folderPath);
nonstd::expected<Path, QString> createTorrentFile(const TorrentDescriptor &torrentDescr, const Path &folderPath);

Expand Down
22 changes: 17 additions & 5 deletions src/base/bittorrent/torrentdescriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ nonstd::expected<BitTorrent::TorrentDescriptor, QString>
BitTorrent::TorrentDescriptor::load(const QByteArray &data) noexcept
try
{
return TorrentDescriptor(lt::load_torrent_buffer(lt::span<const char>(data.data(), data.size()), loadTorrentLimits()));
TorrentDescriptor torrentDescriptor {lt::load_torrent_buffer(lt::span<const char>(data.data(), data.size()), loadTorrentLimits())};
torrentDescriptor.m_hasCompleteMetadata = true;
return torrentDescriptor;
}
catch (const lt::system_error &err)
{
Expand All @@ -103,7 +105,8 @@ BitTorrent::TorrentDescriptor::loadFromFile(const Path &path) noexcept
try
{
TorrentDescriptor torrentDescriptor {lt::load_torrent_file(path.toString().toStdString(), loadTorrentLimits())};
torrentDescriptor.m_sourceFilePath = path;
torrentDescriptor.m_source = path;
torrentDescriptor.m_hasCompleteMetadata = true;
return torrentDescriptor;
}
catch (const lt::system_error &err)
Expand All @@ -121,7 +124,9 @@ try
else if (isV1Hash(str))
magnetURI = u"magnet:?xt=urn:btih:" + str;

return TorrentDescriptor(lt::parse_magnet_uri(magnetURI.toStdString()));
TorrentDescriptor torrentDescriptor {lt::parse_magnet_uri(magnetURI.toStdString())};
torrentDescriptor.m_source = magnetURI;
return torrentDescriptor;
}
catch (const lt::system_error &err)
{
Expand Down Expand Up @@ -190,9 +195,9 @@ const std::optional<BitTorrent::TorrentInfo> &BitTorrent::TorrentDescriptor::inf
return m_info;
}

Path BitTorrent::TorrentDescriptor::sourceFilePath() const
std::variant<QString, Path> BitTorrent::TorrentDescriptor::source() const
{
return m_sourceFilePath;
return m_source;
}

void BitTorrent::TorrentDescriptor::setTorrentInfo(TorrentInfo torrentInfo)
Expand All @@ -208,8 +213,10 @@ void BitTorrent::TorrentDescriptor::setTorrentInfo(TorrentInfo torrentInfo)
m_ltAddTorrentParams.ti = m_info->nativeInfo();
#ifdef QBT_USES_LIBTORRENT2
m_ltAddTorrentParams.info_hashes = m_ltAddTorrentParams.ti->info_hashes();
m_hasCompleteMetadata = !m_ltAddTorrentParams.info_hashes.has_v2();
#else
m_ltAddTorrentParams.info_hash = m_ltAddTorrentParams.ti->info_hash();
m_hasCompleteMetadata = true;
#endif
}
}
Expand All @@ -236,6 +243,11 @@ QList<QUrl> BitTorrent::TorrentDescriptor::urlSeeds() const
return urlSeeds;
}

bool BitTorrent::TorrentDescriptor::hasCompleteMetadata() const
{
return m_hasCompleteMetadata;
}

const libtorrent::add_torrent_params &BitTorrent::TorrentDescriptor::ltAddTorrentParams() const
{
return m_ltAddTorrentParams;
Expand Down
Loading

0 comments on commit 5d372f2

Please sign in to comment.