From c4dbe8483269e3740bb708d08a73639f0668c10b Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Sat, 29 Jun 2019 16:15:41 +0800 Subject: [PATCH 1/3] Use newer libtorrent API --- src/base/bittorrent/session.cpp | 184 ++++++++++++++++++-------------- 1 file changed, 103 insertions(+), 81 deletions(-) diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index b68a94eb4..7bcc23ae8 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -65,6 +65,10 @@ #include #include +#if (LIBTORRENT_VERSION_NUM >= 10200) +#include +#endif + #include "base/algorithm.h" #include "base/exceptions.h" #include "base/global.h" @@ -1843,17 +1847,15 @@ bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magne params.savePath = normalizeSavePath(params.savePath, ""); if (!params.category.isEmpty()) { - if (!m_categories.contains(params.category) && !addCategory(params.category)) { - qWarning() << "Couldn't create category" << params.category; + if (!m_categories.contains(params.category) && !addCategory(params.category)) params.category = ""; - } } + const bool fromMagnetUri = magnetUri.isValid(); // If empty then Automatic mode, otherwise Manual mode QString savePath = params.savePath.isEmpty() ? categorySavePath(params.category) : params.savePath; lt::add_torrent_params p; InfoHash hash; - const bool fromMagnetUri = magnetUri.isValid(); if (fromMagnetUri) { hash = magnetUri.hash(); @@ -1887,8 +1889,58 @@ bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magne p = magnetUri.addTorrentParams(); } - else if (torrentInfo.isValid()) { - if (!params.restored) { + else { + if (!torrentInfo.isValid()) { + // We can have an invalid torrentInfo when there isn't a matching + // .torrent file to the .fastresume we loaded. Possibly from a + // failed upgrade. + return false; + } + + hash = torrentInfo.hash(); + } + + // We should not add the torrent if it is already + // processed or is pending to add to session + if (m_addingTorrents.contains(hash) || m_loadedMetadata.contains(hash)) + return false; + + TorrentHandle *const torrent = m_torrents.value(hash); + if (torrent) { // a duplicate torrent is added + if (torrent->isPrivate() || (!fromMagnetUri && torrentInfo.isPrivate())) + return false; + + // merge trackers and web seeds + torrent->addTrackers(fromMagnetUri ? magnetUri.trackers() : torrentInfo.trackers()); + torrent->addUrlSeeds(fromMagnetUri ? magnetUri.urlSeeds() : torrentInfo.urlSeeds()); + return true; + } + + // Record if .fastresume is complete, that is whether it contains + // the required fields to resume a torrent. + bool hasCompleteFastresume = false; + + if (!fromMagnetUri) { + if (params.restored) { // load from existing fastresume +#if (LIBTORRENT_VERSION_NUM < 10200) + p.resume_data = std::vector {fastresumeData.constData() + , (fastresumeData.constData() + fastresumeData.size())}; + p.flags |= lt::add_torrent_params::flag_use_resume_save_path; + + // Still setup the default parameters and let libtorrent handle + // the parameter merging + hasCompleteFastresume = false; +#else + lt::error_code ec; + p = lt::read_resume_data(fastresumeData, ec); + + // libtorrent will always apply `file_priorities` to torrents, + // if the field is present then the fastresume is considered to + // be correctly generated and should be complete. + hasCompleteFastresume = !p.file_priorities.empty(); +#endif + } + else { // new torrent if (!params.hasRootFolder) torrentInfo.stripRootFolder(); @@ -1906,108 +1958,78 @@ bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magne if (!contentName.isEmpty() && (contentName != torrentInfo.name())) params.name = contentName; } + + Q_ASSERT(p.file_priorities.empty()); + std::transform(params.filePriorities.cbegin(), params.filePriorities.cend() + , std::back_inserter(p.file_priorities), [](const DownloadPriority priority) + { +#if (LIBTORRENT_VERSION_NUM < 10200) + return static_cast(priority); +#else + return static_cast( + static_cast(priority)); +#endif + }); } p.ti = torrentInfo.nativeInfo(); - hash = torrentInfo.hash(); - } - else { - // We can have an invalid torrentInfo when there isn't a matching - // .torrent file to the .fastresume we loaded. Possibly from a - // failed upgrade. - return false; - } - - // We should not add torrent if it already - // processed or adding to session - if (m_addingTorrents.contains(hash) || m_loadedMetadata.contains(hash)) return false; - - TorrentHandle *const torrent = m_torrents.value(hash); - if (torrent) { - if (torrent->isPrivate() || (!fromMagnetUri && torrentInfo.isPrivate())) - return false; - torrent->addTrackers(fromMagnetUri ? magnetUri.trackers() : torrentInfo.trackers()); - torrent->addUrlSeeds(fromMagnetUri ? magnetUri.urlSeeds() : torrentInfo.urlSeeds()); - return true; } - qDebug("Adding torrent..."); - qDebug(" -> Hash: %s", qUtf8Printable(hash)); - - // Preallocation mode - if (isPreallocationEnabled()) - p.storage_mode = lt::storage_mode_allocate; - else - p.storage_mode = lt::storage_mode_sparse; - + if (!hasCompleteFastresume) { + // Common #if (LIBTORRENT_VERSION_NUM < 10200) - p.flags |= lt::add_torrent_params::flag_paused; // Start in pause - p.flags &= ~lt::add_torrent_params::flag_auto_managed; // Because it is added in paused state - p.flags &= ~lt::add_torrent_params::flag_duplicate_is_error; // Already checked + p.flags |= lt::add_torrent_params::flag_paused; // Start in pause + p.flags &= ~lt::add_torrent_params::flag_auto_managed; // Because it is added in paused state + p.flags &= ~lt::add_torrent_params::flag_duplicate_is_error; // Already checked #else - p.flags |= lt::torrent_flags::paused; // Start in pause - p.flags &= ~lt::torrent_flags::auto_managed; // Because it is added in paused state - p.flags &= ~lt::torrent_flags::duplicate_is_error; // Already checked + p.flags |= lt::torrent_flags::paused; // Start in pause + p.flags &= ~lt::torrent_flags::auto_managed; // Because it is added in paused state + p.flags &= ~lt::torrent_flags::duplicate_is_error; // Already checked #endif - // Seeding mode - // Skip checking and directly start seeding (new in libtorrent v0.15) - if (params.skipChecking) { -#if (LIBTORRENT_VERSION_NUM < 10200) - p.flags |= lt::add_torrent_params::flag_seed_mode; -#else - p.flags |= lt::torrent_flags::seed_mode; -#endif - } - else { + // Limits + p.max_connections = maxConnectionsPerTorrent(); + p.max_uploads = maxUploadsPerTorrent(); + p.save_path = Utils::Fs::toNativePath(savePath).toStdString(); + p.upload_limit = params.uploadLimit; + p.download_limit = params.downloadLimit; + + // Preallocation mode + p.storage_mode = isPreallocationEnabled() + ? lt::storage_mode_allocate : lt::storage_mode_sparse; + + // Seeding mode + // Skip checking and directly start seeding + if (params.skipChecking) { #if (LIBTORRENT_VERSION_NUM < 10200) - p.flags &= ~lt::add_torrent_params::flag_seed_mode; + p.flags |= lt::add_torrent_params::flag_seed_mode; #else - p.flags &= ~lt::torrent_flags::seed_mode; + p.flags |= lt::torrent_flags::seed_mode; #endif - } - - if (!fromMagnetUri) { - if (params.restored) { - // Set torrent fast resume data - p.resume_data = std::vector {fastresumeData.constData(), fastresumeData.constData() + fastresumeData.size()}; - p.flags |= lt::add_torrent_params::flag_use_resume_save_path; } else { - Q_ASSERT(p.file_priorities.empty()); - std::transform(params.filePriorities.cbegin(), params.filePriorities.cend() - , std::back_inserter(p.file_priorities), [](DownloadPriority priority) - { #if (LIBTORRENT_VERSION_NUM < 10200) - return static_cast(priority); + p.flags &= ~lt::add_torrent_params::flag_seed_mode; #else - return static_cast( - static_cast(priority)); + p.flags &= ~lt::torrent_flags::seed_mode; #endif - }); } - } - if (params.restored && !params.paused) { - // Make sure the torrent will restored in "paused" state - // Then we will start it if needed + if (params.restored && !params.paused) { + // Make sure the torrent will restored in "paused" state + // Then we will start it if needed #if (LIBTORRENT_VERSION_NUM < 10200) - p.flags |= lt::add_torrent_params::flag_stop_when_ready; + p.flags |= lt::add_torrent_params::flag_stop_when_ready; #else - p.flags |= lt::torrent_flags::stop_when_ready; + p.flags |= lt::torrent_flags::stop_when_ready; #endif + } } - // Limits - p.max_connections = maxConnectionsPerTorrent(); - p.max_uploads = maxUploadsPerTorrent(); - p.save_path = Utils::Fs::toNativePath(savePath).toStdString(); - p.upload_limit = params.uploadLimit; - p.download_limit = params.downloadLimit; - m_addingTorrents.insert(hash, params); // Adding torrent to BitTorrent session m_nativeSession->async_add_torrent(p); + return true; } From 664cfe7d6954d9b541f9b89bcf09e59a713fbdca Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Sat, 29 Jun 2019 19:56:36 +0800 Subject: [PATCH 2/3] Fix torrent properties not saved for paused torrents --- src/base/bittorrent/torrenthandle.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/base/bittorrent/torrenthandle.cpp b/src/base/bittorrent/torrenthandle.cpp index f65b3b0c7..c97e2ce7d 100644 --- a/src/base/bittorrent/torrenthandle.cpp +++ b/src/base/bittorrent/torrenthandle.cpp @@ -1365,6 +1365,8 @@ void TorrentHandle::setSequentialDownload(const bool enable) m_nativeStatus.flags &= ~lt::torrent_flags::sequential_download; // prevent return cached value } #endif + + saveResumeData(); } void TorrentHandle::toggleSequentialDownload() @@ -1418,6 +1420,8 @@ void TorrentHandle::setFirstLastPiecePriorityImpl(const bool enabled, const QVec LogMsg(tr("Download first and last piece first: %1, torrent: '%2'") .arg((enabled ? tr("On") : tr("Off")), name())); + + saveResumeData(); } void TorrentHandle::toggleFirstLastPiecePriority() From b9094ff8a52687f72e7a70d0e53e696a94efe24a Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Sun, 30 Jun 2019 20:39:49 +0800 Subject: [PATCH 3/3] Use proper log message when there are no error --- src/base/bittorrent/session.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index 7bcc23ae8..4da1db24d 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -4042,9 +4042,14 @@ void Session::handleTorrentDeleteFailedAlert(const lt::torrent_delete_failed_ale // so we remove the directory ourselves Utils::Fs::smartRemoveEmptyFolderTree(tmpRemovingTorrentData.savePathToRemove); - LogMsg(tr("'%1' was removed from the transfer list but the files couldn't be deleted. Error: %2", "'xxx.avi' was removed...") - .arg(tmpRemovingTorrentData.name, QString::fromLocal8Bit(p->error.message().c_str())) - , Log::CRITICAL); + if (p->error) { + LogMsg(tr("'%1' was removed from the transfer list but the files couldn't be deleted. Error: %2", "'xxx.avi' was removed...") + .arg(tmpRemovingTorrentData.name, QString::fromStdString(p->error.message())) + , Log::WARNING); + } + else { + LogMsg(tr("'%1' was removed from the transfer list.", "'xxx.avi' was removed...").arg(tmpRemovingTorrentData.name)); + } } void Session::handleMetadataReceivedAlert(const lt::metadata_received_alert *p)