Browse Source

Merge pull request #14576 from glassez/save-resume

Wrap "resume data" in LoadTorrentParams
adaptive-webui-19844
Vladimir Golovnev 4 years ago committed by GitHub
parent
commit
9b31496b22
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 99
      src/base/bittorrent/session.cpp
  2. 2
      src/base/bittorrent/session.h
  3. 84
      src/base/bittorrent/torrentimpl.cpp
  4. 1
      src/base/bittorrent/torrentimpl.h

99
src/base/bittorrent/session.cpp

@ -44,6 +44,7 @@
#include <libtorrent/alert_types.hpp> #include <libtorrent/alert_types.hpp>
#include <libtorrent/bdecode.hpp> #include <libtorrent/bdecode.hpp>
#include <libtorrent/bencode.hpp> #include <libtorrent/bencode.hpp>
#include <libtorrent/entry.hpp>
#include <libtorrent/error_code.hpp> #include <libtorrent/error_code.hpp>
#include <libtorrent/extensions/smart_ban.hpp> #include <libtorrent/extensions/smart_ban.hpp>
#include <libtorrent/extensions/ut_metadata.hpp> #include <libtorrent/extensions/ut_metadata.hpp>
@ -55,6 +56,7 @@
#include <libtorrent/session_stats.hpp> #include <libtorrent/session_stats.hpp>
#include <libtorrent/session_status.hpp> #include <libtorrent/session_status.hpp>
#include <libtorrent/torrent_info.hpp> #include <libtorrent/torrent_info.hpp>
#include <libtorrent/write_resume_data.hpp>
#include <QDebug> #include <QDebug>
#include <QDir> #include <QDir>
@ -303,6 +305,17 @@ namespace
}; };
} }
using ListType = lt::entry::list_type;
ListType setToEntryList(const QSet<QString> &input)
{
ListType entryList;
entryList.reserve(input.size());
for (const QString &setValue : input)
entryList.emplace_back(setValue.toStdString());
return entryList;
}
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
QString convertIfaceNameToGuid(const QString &name) QString convertIfaceNameToGuid(const QString &name)
{ {
@ -3926,16 +3939,52 @@ void Session::handleTorrentFinished(TorrentImpl *const torrent)
emit allTorrentsFinished(); emit allTorrentsFinished();
} }
void Session::handleTorrentResumeDataReady(TorrentImpl *const torrent, const std::shared_ptr<lt::entry> &data) void Session::handleTorrentResumeDataReady(TorrentImpl *const torrent, const LoadTorrentParams &data)
{ {
--m_numResumeData; --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. // Separated thread is used for the blocking IO which results in slow processing of many torrents.
// Copying lt::entry objects around isn't cheap. // Copying lt::entry objects around isn't cheap.
auto resumeDataPtr = std::make_shared<lt::entry>(lt::write_resume_data(p));
lt::entry &resumeData = *resumeDataPtr;
resumeData["qBt-savePath"] = Profile::instance()->toPortablePath(data.savePath).toStdString();
resumeData["qBt-ratioLimit"] = static_cast<int>(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()); const QString filename = QString::fromLatin1("%1.fastresume").arg(torrent->id().toString());
QMetaObject::invokeMethod(m_resumeDataSavingManager 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) void Session::handleTorrentTrackerReply(TorrentImpl *const torrent, const QString &trackerUrl)
@ -4253,51 +4302,7 @@ bool Session::loadTorrentResumeData(const QByteArray &data, const TorrentInfo &m
const bool hasMetadata = (p.ti && p.ti->is_valid()); const bool hasMetadata = (p.ti && p.ti->is_valid());
if (!hasMetadata && !root.dict_find("info-hash")) if (!hasMetadata && !root.dict_find("info-hash"))
{ return false;
// 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<bool>(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 true; return true;
} }

2
src/base/bittorrent/session.h

@ -484,7 +484,7 @@ namespace BitTorrent
void handleTorrentTrackersChanged(TorrentImpl *const torrent); void handleTorrentTrackersChanged(TorrentImpl *const torrent);
void handleTorrentUrlSeedsAdded(TorrentImpl *const torrent, const QVector<QUrl> &newUrlSeeds); void handleTorrentUrlSeedsAdded(TorrentImpl *const torrent, const QVector<QUrl> &newUrlSeeds);
void handleTorrentUrlSeedsRemoved(TorrentImpl *const torrent, const QVector<QUrl> &urlSeeds); void handleTorrentUrlSeedsRemoved(TorrentImpl *const torrent, const QVector<QUrl> &urlSeeds);
void handleTorrentResumeDataReady(TorrentImpl *const torrent, const std::shared_ptr<lt::entry> &data); void handleTorrentResumeDataReady(TorrentImpl *const torrent, const LoadTorrentParams &data);
void handleTorrentTrackerReply(TorrentImpl *const torrent, const QString &trackerUrl); void handleTorrentTrackerReply(TorrentImpl *const torrent, const QString &trackerUrl);
void handleTorrentTrackerWarning(TorrentImpl *const torrent, const QString &trackerUrl); void handleTorrentTrackerWarning(TorrentImpl *const torrent, const QString &trackerUrl);
void handleTorrentTrackerError(TorrentImpl *const torrent, const QString &trackerUrl); void handleTorrentTrackerError(TorrentImpl *const torrent, const QString &trackerUrl);

84
src/base/bittorrent/torrentimpl.cpp

@ -39,13 +39,11 @@
#include <libtorrent/address.hpp> #include <libtorrent/address.hpp>
#include <libtorrent/alert_types.hpp> #include <libtorrent/alert_types.hpp>
#include <libtorrent/entry.hpp>
#include <libtorrent/magnet_uri.hpp> #include <libtorrent/magnet_uri.hpp>
#include <libtorrent/session.hpp> #include <libtorrent/session.hpp>
#include <libtorrent/storage_defs.hpp> #include <libtorrent/storage_defs.hpp>
#include <libtorrent/time.hpp> #include <libtorrent/time.hpp>
#include <libtorrent/version.hpp> #include <libtorrent/version.hpp>
#include <libtorrent/write_resume_data.hpp>
#if (LIBTORRENT_VERSION_NUM >= 20000) #if (LIBTORRENT_VERSION_NUM >= 20000)
#include <libtorrent/info_hash.hpp> #include <libtorrent/info_hash.hpp>
@ -61,7 +59,6 @@
#include "base/global.h" #include "base/global.h"
#include "base/logger.h" #include "base/logger.h"
#include "base/preferences.h" #include "base/preferences.h"
#include "base/profile.h"
#include "base/utils/fs.h" #include "base/utils/fs.h"
#include "base/utils/string.h" #include "base/utils/string.h"
#include "common.h" #include "common.h"
@ -91,16 +88,6 @@ namespace
return out; return out;
} }
using ListType = lt::entry::list_type;
ListType setToEntryList(const QSet<QString> &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 makeNativeAnnouncerEntry(const QString &url, const int tier)
{ {
lt::announce_entry entry {url.toStdString()}; lt::announce_entry entry {url.toStdString()};
@ -1676,6 +1663,9 @@ void TorrentImpl::handleTorrentCheckedAlert(const lt::torrent_checked_alert *p)
return; return;
} }
if (m_nativeHandle.need_save_resume_data())
m_session->handleTorrentNeedSaveResumeData(this);
if (m_fastresumeDataRejected && !m_hasMissingFiles) if (m_fastresumeDataRejected && !m_hasMissingFiles)
m_fastresumeDataRejected = false; m_fastresumeDataRejected = false;
@ -1756,29 +1746,7 @@ void TorrentImpl::handleSaveResumeDataAlert(const lt::save_resume_data_alert *p)
m_ltAddTorrentParams = p->params; 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.added_time = addedTime().toSecsSinceEpoch();
m_ltAddTorrentParams.save_path = Profile::instance()->toPortablePath(
QString::fromStdString(m_ltAddTorrentParams.save_path)).toStdString();
if (m_maintenanceJob == MaintenanceJob::HandleMetadata) if (m_maintenanceJob == MaintenanceJob::HandleMetadata)
{ {
@ -1791,37 +1759,21 @@ void TorrentImpl::handleSaveResumeDataAlert(const lt::save_resume_data_alert *p)
m_session->findIncompleteFiles(metadata, m_savePath); m_session->findIncompleteFiles(metadata, m_savePath);
} }
auto resumeDataPtr = std::make_shared<lt::entry>(lt::write_resume_data(m_ltAddTorrentParams)); LoadTorrentParams resumeData;
lt::entry &resumeData = *resumeDataPtr; resumeData.name = m_name;
resumeData.category = m_category;
// TODO: The following code is deprecated. Remove after several releases in 4.3.x. resumeData.savePath = m_useAutoTMM ? "" : m_savePath;
// === BEGIN DEPRECATED CODE === // resumeData.tags = m_tags;
const bool useDummyResumeData = !hasMetadata(); resumeData.contentLayout = m_contentLayout;
if (useDummyResumeData) resumeData.ratioLimit = m_ratioLimit;
{ resumeData.seedingTimeLimit = m_seedingTimeLimit;
updateStatus(); resumeData.firstLastPiecePriority = m_hasFirstLastPiecePriority;
resumeData.hasSeedStatus = m_hasSeedStatus;
resumeData["qBt-magnetUri"] = createMagnetURI().toStdString(); resumeData.paused = m_isStopped;
// sequentialDownload needs to be stored in the resumeData.forced = (m_operatingMode == TorrentOperatingMode::Forced);
// resume data if there is no metadata, otherwise they won't be resumeData.ltAddTorrentParams = m_ltAddTorrentParams;
// restored if qBittorrent quits before the metadata are retrieved:
resumeData["qBt-sequential"] = isSequentialDownload(); m_session->handleTorrentResumeDataReady(this, resumeData);
resumeData["qBt-addedTime"] = addedTime().toSecsSinceEpoch();
}
// === END DEPRECATED CODE === //
resumeData["qBt-savePath"] = m_useAutoTMM ? "" : Profile::instance()->toPortablePath(m_savePath).toStdString();
resumeData["qBt-ratioLimit"] = static_cast<int>(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);
} }
void TorrentImpl::handleSaveResumeDataFailedAlert(const lt::save_resume_data_failed_alert *p) void TorrentImpl::handleSaveResumeDataFailedAlert(const lt::save_resume_data_failed_alert *p)

1
src/base/bittorrent/torrentimpl.h

@ -68,7 +68,6 @@ namespace BitTorrent
bool forced = false; bool forced = false;
bool paused = false; bool paused = false;
qreal ratioLimit = Torrent::USE_GLOBAL_RATIO; qreal ratioLimit = Torrent::USE_GLOBAL_RATIO;
int seedingTimeLimit = Torrent::USE_GLOBAL_SEEDING_TIME; int seedingTimeLimit = Torrent::USE_GLOBAL_SEEDING_TIME;

Loading…
Cancel
Save