From b65a714d177cf353697be3b483ba2e0bc5852f92 Mon Sep 17 00:00:00 2001 From: "Vladimir Golovnev (Glassez)" Date: Sat, 20 Mar 2021 14:50:01 +0300 Subject: [PATCH 1/3] Save resume data when torrent has done checking --- src/base/bittorrent/torrentimpl.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/base/bittorrent/torrentimpl.cpp b/src/base/bittorrent/torrentimpl.cpp index 9b30f6c6d..066e0fa74 100644 --- a/src/base/bittorrent/torrentimpl.cpp +++ b/src/base/bittorrent/torrentimpl.cpp @@ -1676,6 +1676,9 @@ void TorrentImpl::handleTorrentCheckedAlert(const lt::torrent_checked_alert *p) return; } + if (m_nativeHandle.need_save_resume_data()) + m_session->handleTorrentNeedSaveResumeData(this); + if (m_fastresumeDataRejected && !m_hasMissingFiles) m_fastresumeDataRejected = false; From 5d889e4a8f0e44c12c30177e6a60e39625152874 Mon Sep 17 00:00:00 2001 From: "Vladimir Golovnev (Glassez)" Date: Sat, 20 Mar 2021 15:15:28 +0300 Subject: [PATCH 2/3] Drop deprecated code --- src/base/bittorrent/session.cpp | 46 +---------------------------- src/base/bittorrent/torrentimpl.cpp | 17 ----------- src/base/bittorrent/torrentimpl.h | 1 - 3 files changed, 1 insertion(+), 63 deletions(-) diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index 683daa5f1..d4c1b4fe3 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -4253,51 +4253,7 @@ bool Session::loadTorrentResumeData(const QByteArray &data, const TorrentInfo &m const bool hasMetadata = (p.ti && p.ti->is_valid()); if (!hasMetadata && !root.dict_find("info-hash")) - { - // TODO: The following code is deprecated. Remove after several releases in 4.3.x. - // === BEGIN DEPRECATED CODE === // - // Try to load from legacy data used in older versions for torrents w/o metadata - const lt::bdecode_node magnetURINode = root.dict_find("qBt-magnetUri"); - if (magnetURINode.type() == lt::bdecode_node::string_t) - { - lt::parse_magnet_uri(magnetURINode.string_value(), p, ec); - - if (isTempPathEnabled()) - { - p.save_path = Utils::Fs::toNativePath(tempPath()).toStdString(); - } - else - { - // If empty then Automatic mode, otherwise Manual mode - const QString savePath = torrentParams.savePath.isEmpty() ? categorySavePath(torrentParams.category) : torrentParams.savePath; - p.save_path = Utils::Fs::toNativePath(savePath).toStdString(); - } - - // Preallocation mode - p.storage_mode = (isPreallocationEnabled() ? lt::storage_mode_allocate : lt::storage_mode_sparse); - - const lt::bdecode_node addedTimeNode = root.dict_find("qBt-addedTime"); - if (addedTimeNode.type() == lt::bdecode_node::int_t) - p.added_time = addedTimeNode.int_value(); - - const lt::bdecode_node sequentialNode = root.dict_find("qBt-sequential"); - if (sequentialNode.type() == lt::bdecode_node::int_t) - { - if (static_cast(sequentialNode.int_value())) - p.flags |= lt::torrent_flags::sequential_download; - else - p.flags &= ~lt::torrent_flags::sequential_download; - } - - if (torrentParams.name.isEmpty() && !p.name.empty()) - torrentParams.name = QString::fromStdString(p.name); - } - // === END DEPRECATED CODE === // - else - { - return false; - } - } + return false; return true; } diff --git a/src/base/bittorrent/torrentimpl.cpp b/src/base/bittorrent/torrentimpl.cpp index 066e0fa74..cae29edb8 100644 --- a/src/base/bittorrent/torrentimpl.cpp +++ b/src/base/bittorrent/torrentimpl.cpp @@ -1797,23 +1797,6 @@ void TorrentImpl::handleSaveResumeDataAlert(const lt::save_resume_data_alert *p) auto resumeDataPtr = std::make_shared(lt::write_resume_data(m_ltAddTorrentParams)); lt::entry &resumeData = *resumeDataPtr; - // TODO: The following code is deprecated. Remove after several releases in 4.3.x. - // === BEGIN DEPRECATED CODE === // - const bool useDummyResumeData = !hasMetadata(); - if (useDummyResumeData) - { - updateStatus(); - - resumeData["qBt-magnetUri"] = createMagnetURI().toStdString(); - // sequentialDownload needs to be stored in the - // resume data if there is no metadata, otherwise they won't be - // restored if qBittorrent quits before the metadata are retrieved: - resumeData["qBt-sequential"] = isSequentialDownload(); - - resumeData["qBt-addedTime"] = addedTime().toSecsSinceEpoch(); - } - // === END DEPRECATED CODE === // - resumeData["qBt-savePath"] = m_useAutoTMM ? "" : Profile::instance()->toPortablePath(m_savePath).toStdString(); resumeData["qBt-ratioLimit"] = static_cast(m_ratioLimit * 1000); resumeData["qBt-seedingTimeLimit"] = m_seedingTimeLimit; diff --git a/src/base/bittorrent/torrentimpl.h b/src/base/bittorrent/torrentimpl.h index 16a935066..9aef754dd 100644 --- a/src/base/bittorrent/torrentimpl.h +++ b/src/base/bittorrent/torrentimpl.h @@ -68,7 +68,6 @@ namespace BitTorrent bool forced = false; bool paused = false; - qreal ratioLimit = Torrent::USE_GLOBAL_RATIO; int seedingTimeLimit = Torrent::USE_GLOBAL_SEEDING_TIME; From 764aabc4592d7de7d65b0199406fa1f4b9946314 Mon Sep 17 00:00:00 2001 From: "Vladimir Golovnev (Glassez)" Date: Sat, 20 Mar 2021 15:46:49 +0300 Subject: [PATCH 3/3] Wrap "resume data" in LoadTorrentParams --- src/base/bittorrent/session.cpp | 53 +++++++++++++++++++++++- src/base/bittorrent/session.h | 2 +- src/base/bittorrent/torrentimpl.cpp | 64 +++++++---------------------- 3 files changed, 67 insertions(+), 52 deletions(-) diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index d4c1b4fe3..cebfca167 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +56,7 @@ #include #include #include +#include #include #include @@ -303,6 +305,17 @@ namespace }; } + using ListType = lt::entry::list_type; + + ListType setToEntryList(const QSet &input) + { + ListType entryList; + entryList.reserve(input.size()); + for (const QString &setValue : input) + entryList.emplace_back(setValue.toStdString()); + return entryList; + } + #ifdef Q_OS_WIN QString convertIfaceNameToGuid(const QString &name) { @@ -3926,16 +3939,52 @@ void Session::handleTorrentFinished(TorrentImpl *const torrent) emit allTorrentsFinished(); } -void Session::handleTorrentResumeDataReady(TorrentImpl *const torrent, const std::shared_ptr &data) +void Session::handleTorrentResumeDataReady(TorrentImpl *const torrent, const LoadTorrentParams &data) { --m_numResumeData; + // We need to adjust native libtorrent resume data + lt::add_torrent_params p = data.ltAddTorrentParams; + p.save_path = Profile::instance()->toPortablePath(QString::fromStdString(p.save_path)).toStdString(); + if (data.paused) + { + p.flags |= lt::torrent_flags::paused; + p.flags &= ~lt::torrent_flags::auto_managed; + } + else + { + // Torrent can be actually "running" but temporarily "paused" to perform some + // service jobs behind the scenes so we need to restore it as "running" + if (!data.forced) + { + p.flags |= lt::torrent_flags::auto_managed; + } + else + { + p.flags &= ~lt::torrent_flags::paused; + p.flags &= ~lt::torrent_flags::auto_managed; + } + } + // Separated thread is used for the blocking IO which results in slow processing of many torrents. // Copying lt::entry objects around isn't cheap. + auto resumeDataPtr = std::make_shared(lt::write_resume_data(p)); + lt::entry &resumeData = *resumeDataPtr; + + resumeData["qBt-savePath"] = Profile::instance()->toPortablePath(data.savePath).toStdString(); + resumeData["qBt-ratioLimit"] = static_cast(data.ratioLimit * 1000); + resumeData["qBt-seedingTimeLimit"] = data.seedingTimeLimit; + resumeData["qBt-category"] = data.category.toStdString(); + resumeData["qBt-tags"] = setToEntryList(data.tags); + resumeData["qBt-name"] = data.name.toStdString(); + resumeData["qBt-seedStatus"] = data.hasSeedStatus; + resumeData["qBt-contentLayout"] = Utils::String::fromEnum(data.contentLayout).toStdString(); + resumeData["qBt-firstLastPiecePriority"] = data.firstLastPiecePriority; + const QString filename = QString::fromLatin1("%1.fastresume").arg(torrent->id().toString()); QMetaObject::invokeMethod(m_resumeDataSavingManager - , [this, filename, data]() { m_resumeDataSavingManager->save(filename, data); }); + , [this, filename, resumeDataPtr]() { m_resumeDataSavingManager->save(filename, resumeDataPtr); }); } void Session::handleTorrentTrackerReply(TorrentImpl *const torrent, const QString &trackerUrl) diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index c8752d645..c6bd8c813 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -484,7 +484,7 @@ namespace BitTorrent void handleTorrentTrackersChanged(TorrentImpl *const torrent); void handleTorrentUrlSeedsAdded(TorrentImpl *const torrent, const QVector &newUrlSeeds); void handleTorrentUrlSeedsRemoved(TorrentImpl *const torrent, const QVector &urlSeeds); - void handleTorrentResumeDataReady(TorrentImpl *const torrent, const std::shared_ptr &data); + void handleTorrentResumeDataReady(TorrentImpl *const torrent, const LoadTorrentParams &data); void handleTorrentTrackerReply(TorrentImpl *const torrent, const QString &trackerUrl); void handleTorrentTrackerWarning(TorrentImpl *const torrent, const QString &trackerUrl); void handleTorrentTrackerError(TorrentImpl *const torrent, const QString &trackerUrl); diff --git a/src/base/bittorrent/torrentimpl.cpp b/src/base/bittorrent/torrentimpl.cpp index cae29edb8..bbc1bde31 100644 --- a/src/base/bittorrent/torrentimpl.cpp +++ b/src/base/bittorrent/torrentimpl.cpp @@ -39,13 +39,11 @@ #include #include -#include #include #include #include #include #include -#include #if (LIBTORRENT_VERSION_NUM >= 20000) #include @@ -61,7 +59,6 @@ #include "base/global.h" #include "base/logger.h" #include "base/preferences.h" -#include "base/profile.h" #include "base/utils/fs.h" #include "base/utils/string.h" #include "common.h" @@ -91,16 +88,6 @@ namespace return out; } - using ListType = lt::entry::list_type; - - ListType setToEntryList(const QSet &input) - { - ListType entryList; - for (const QString &setValue : input) - entryList.emplace_back(setValue.toStdString()); - return entryList; - } - lt::announce_entry makeNativeAnnouncerEntry(const QString &url, const int tier) { lt::announce_entry entry {url.toStdString()}; @@ -1759,29 +1746,7 @@ void TorrentImpl::handleSaveResumeDataAlert(const lt::save_resume_data_alert *p) m_ltAddTorrentParams = p->params; } - if (m_isStopped) - { - m_ltAddTorrentParams.flags |= lt::torrent_flags::paused; - m_ltAddTorrentParams.flags &= ~lt::torrent_flags::auto_managed; - } - else - { - // Torrent can be actually "running" but temporarily "paused" to perform some - // service jobs behind the scenes so we need to restore it as "running" - if (m_operatingMode == TorrentOperatingMode::AutoManaged) - { - m_ltAddTorrentParams.flags |= lt::torrent_flags::auto_managed; - } - else - { - m_ltAddTorrentParams.flags &= ~lt::torrent_flags::paused; - m_ltAddTorrentParams.flags &= ~lt::torrent_flags::auto_managed; - } - } - m_ltAddTorrentParams.added_time = addedTime().toSecsSinceEpoch(); - m_ltAddTorrentParams.save_path = Profile::instance()->toPortablePath( - QString::fromStdString(m_ltAddTorrentParams.save_path)).toStdString(); if (m_maintenanceJob == MaintenanceJob::HandleMetadata) { @@ -1794,20 +1759,21 @@ void TorrentImpl::handleSaveResumeDataAlert(const lt::save_resume_data_alert *p) m_session->findIncompleteFiles(metadata, m_savePath); } - auto resumeDataPtr = std::make_shared(lt::write_resume_data(m_ltAddTorrentParams)); - lt::entry &resumeData = *resumeDataPtr; - - resumeData["qBt-savePath"] = m_useAutoTMM ? "" : Profile::instance()->toPortablePath(m_savePath).toStdString(); - resumeData["qBt-ratioLimit"] = static_cast(m_ratioLimit * 1000); - resumeData["qBt-seedingTimeLimit"] = m_seedingTimeLimit; - resumeData["qBt-category"] = m_category.toStdString(); - resumeData["qBt-tags"] = setToEntryList(m_tags); - resumeData["qBt-name"] = m_name.toStdString(); - resumeData["qBt-seedStatus"] = m_hasSeedStatus; - resumeData["qBt-contentLayout"] = Utils::String::fromEnum(m_contentLayout).toStdString(); - resumeData["qBt-firstLastPiecePriority"] = m_hasFirstLastPiecePriority; - - m_session->handleTorrentResumeDataReady(this, resumeDataPtr); + LoadTorrentParams resumeData; + resumeData.name = m_name; + resumeData.category = m_category; + resumeData.savePath = m_useAutoTMM ? "" : m_savePath; + resumeData.tags = m_tags; + resumeData.contentLayout = m_contentLayout; + resumeData.ratioLimit = m_ratioLimit; + resumeData.seedingTimeLimit = m_seedingTimeLimit; + resumeData.firstLastPiecePriority = m_hasFirstLastPiecePriority; + resumeData.hasSeedStatus = m_hasSeedStatus; + resumeData.paused = m_isStopped; + resumeData.forced = (m_operatingMode == TorrentOperatingMode::Forced); + resumeData.ltAddTorrentParams = m_ltAddTorrentParams; + + m_session->handleTorrentResumeDataReady(this, resumeData); } void TorrentImpl::handleSaveResumeDataFailedAlert(const lt::save_resume_data_failed_alert *p)