Browse Source

Merge pull request #9180 from glassez/resume-data

Save resume data on torrent change events. Closes #9174
adaptive-webui-19844
Vladimir Golovnev 6 years ago committed by GitHub
parent
commit
5d931ef9ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 152
      src/base/bittorrent/session.cpp
  2. 7
      src/base/bittorrent/session.h
  3. 83
      src/base/bittorrent/torrenthandle.cpp
  4. 21
      src/base/bittorrent/torrenthandle.h

152
src/base/bittorrent/session.cpp

@ -111,7 +111,7 @@ using namespace BitTorrent;
namespace namespace
{ {
bool readFile(const QString &path, QByteArray &buf); bool readFile(const QString &path, QByteArray &buf);
bool loadTorrentResumeData(const QByteArray &data, AddTorrentData &torrentData, int &prio, MagnetUri &magnetUri); bool loadTorrentResumeData(const QByteArray &data, CreateTorrentParams &torrentParams, int &prio, MagnetUri &magnetUri);
void torrentQueuePositionUp(const libt::torrent_handle &handle); void torrentQueuePositionUp(const libt::torrent_handle &handle);
void torrentQueuePositionDown(const libt::torrent_handle &handle); void torrentQueuePositionDown(const libt::torrent_handle &handle);
@ -2110,15 +2110,15 @@ bool Session::addTorrent(const TorrentInfo &torrentInfo, const AddTorrentParams
} }
// Add a torrent to the BitTorrent session // Add a torrent to the BitTorrent session
bool Session::addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri, bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magnetUri,
TorrentInfo torrentInfo, const QByteArray &fastresumeData) TorrentInfo torrentInfo, const QByteArray &fastresumeData)
{ {
addData.savePath = normalizeSavePath(addData.savePath, ""); params.savePath = normalizeSavePath(params.savePath, "");
if (!addData.category.isEmpty()) { if (!params.category.isEmpty()) {
if (!m_categories.contains(addData.category) && !addCategory(addData.category)) { if (!m_categories.contains(params.category) && !addCategory(params.category)) {
qWarning() << "Couldn't create category" << addData.category; qWarning() << "Couldn't create category" << params.category;
addData.category = ""; params.category = "";
} }
} }
@ -2127,10 +2127,10 @@ bool Session::addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri
std::vector<boost::uint8_t> filePriorities; std::vector<boost::uint8_t> filePriorities;
QString savePath; QString savePath;
if (addData.savePath.isEmpty()) // using Automatic mode if (params.savePath.isEmpty()) // using Automatic mode
savePath = categorySavePath(addData.category); savePath = categorySavePath(params.category);
else // using Manual mode else // using Manual mode
savePath = addData.savePath; savePath = params.savePath;
bool fromMagnetUri = magnetUri.isValid(); bool fromMagnetUri = magnetUri.isValid();
if (fromMagnetUri) { if (fromMagnetUri) {
@ -2151,7 +2151,7 @@ bool Session::addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri
adjustLimits(); adjustLimits();
// use common 2nd step of torrent addition // use common 2nd step of torrent addition
m_addingTorrents.insert(hash, addData); m_addingTorrents.insert(hash, params);
createTorrentHandle(handle); createTorrentHandle(handle);
return true; return true;
} }
@ -2159,23 +2159,23 @@ bool Session::addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri
p = magnetUri.addTorrentParams(); p = magnetUri.addTorrentParams();
} }
else if (torrentInfo.isValid()) { else if (torrentInfo.isValid()) {
if (!addData.resumed) { if (!params.restored) {
if (!addData.hasRootFolder) if (!params.hasRootFolder)
torrentInfo.stripRootFolder(); torrentInfo.stripRootFolder();
// Metadata // Metadata
if (!addData.hasSeedStatus) if (!params.hasSeedStatus)
findIncompleteFiles(torrentInfo, savePath); findIncompleteFiles(torrentInfo, savePath);
// if torrent name wasn't explicitly set we handle the case of // if torrent name wasn't explicitly set we handle the case of
// initial renaming of torrent content and rename torrent accordingly // initial renaming of torrent content and rename torrent accordingly
if (addData.name.isEmpty()) { if (params.name.isEmpty()) {
QString contentName = torrentInfo.rootFolder(); QString contentName = torrentInfo.rootFolder();
if (contentName.isEmpty() && (torrentInfo.filesCount() == 1)) if (contentName.isEmpty() && (torrentInfo.filesCount() == 1))
contentName = torrentInfo.fileName(0); contentName = torrentInfo.fileName(0);
if (!contentName.isEmpty() && (contentName != torrentInfo.name())) if (!contentName.isEmpty() && (contentName != torrentInfo.name()))
addData.name = contentName; params.name = contentName;
} }
} }
@ -2189,13 +2189,13 @@ bool Session::addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri
return false; return false;
} }
if (addData.resumed && !fromMagnetUri) { if (params.restored && !fromMagnetUri) {
// Set torrent fast resume data // Set torrent fast resume data
p.resume_data = {fastresumeData.constData(), fastresumeData.constData() + fastresumeData.size()}; p.resume_data = {fastresumeData.constData(), fastresumeData.constData() + fastresumeData.size()};
p.flags |= libt::add_torrent_params::flag_use_resume_save_path; p.flags |= libt::add_torrent_params::flag_use_resume_save_path;
} }
else { else {
foreach (int prio, addData.filePriorities) foreach (int prio, params.filePriorities)
filePriorities.push_back(prio); filePriorities.push_back(prio);
p.file_priorities = filePriorities; p.file_priorities = filePriorities;
} }
@ -2228,7 +2228,7 @@ bool Session::addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri
// Seeding mode // Seeding mode
// Skip checking and directly start seeding (new in libtorrent v0.15) // Skip checking and directly start seeding (new in libtorrent v0.15)
if (addData.skipChecking) if (params.skipChecking)
p.flags |= libt::add_torrent_params::flag_seed_mode; p.flags |= libt::add_torrent_params::flag_seed_mode;
else else
p.flags &= ~libt::add_torrent_params::flag_seed_mode; p.flags &= ~libt::add_torrent_params::flag_seed_mode;
@ -2237,10 +2237,10 @@ bool Session::addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri
p.max_connections = maxConnectionsPerTorrent(); p.max_connections = maxConnectionsPerTorrent();
p.max_uploads = maxUploadsPerTorrent(); p.max_uploads = maxUploadsPerTorrent();
p.save_path = Utils::Fs::toNativePath(savePath).toStdString(); p.save_path = Utils::Fs::toNativePath(savePath).toStdString();
p.upload_limit = addData.uploadLimit; p.upload_limit = params.uploadLimit;
p.download_limit = addData.downloadLimit; p.download_limit = params.downloadLimit;
m_addingTorrents.insert(hash, addData); m_addingTorrents.insert(hash, params);
// Adding torrent to BitTorrent session // Adding torrent to BitTorrent session
m_nativeSession->async_add_torrent(p); m_nativeSession->async_add_torrent(p);
return true; return true;
@ -2362,7 +2362,6 @@ void Session::generateResumeData(bool final)
if (!final && !torrent->needSaveResumeData()) continue; if (!final && !torrent->needSaveResumeData()) continue;
saveTorrentResumeData(torrent, final); saveTorrentResumeData(torrent, final);
qDebug("Saving fastresume data for %s", qUtf8Printable(torrent->name()));
} }
} }
@ -3529,45 +3528,58 @@ void Session::updateSeedingLimitTimer()
void Session::handleTorrentShareLimitChanged(TorrentHandle *const torrent) void Session::handleTorrentShareLimitChanged(TorrentHandle *const torrent)
{ {
Q_UNUSED(torrent); saveTorrentResumeData(torrent);
updateSeedingLimitTimer(); updateSeedingLimitTimer();
} }
void Session::saveTorrentResumeData(TorrentHandle *const torrent, bool finalSave) void Session::saveTorrentResumeData(TorrentHandle *const torrent, bool finalSave)
{ {
qDebug("Saving fastresume data for %s", qUtf8Printable(torrent->name()));
torrent->saveResumeData(finalSave); torrent->saveResumeData(finalSave);
++m_numResumeData; ++m_numResumeData;
} }
void Session::handleTorrentNameChanged(TorrentHandle *const torrent)
{
saveTorrentResumeData(torrent);
}
void Session::handleTorrentSavePathChanged(TorrentHandle *const torrent) void Session::handleTorrentSavePathChanged(TorrentHandle *const torrent)
{ {
saveTorrentResumeData(torrent);
emit torrentSavePathChanged(torrent); emit torrentSavePathChanged(torrent);
} }
void Session::handleTorrentCategoryChanged(TorrentHandle *const torrent, const QString &oldCategory) void Session::handleTorrentCategoryChanged(TorrentHandle *const torrent, const QString &oldCategory)
{ {
saveTorrentResumeData(torrent);
emit torrentCategoryChanged(torrent, oldCategory); emit torrentCategoryChanged(torrent, oldCategory);
} }
void Session::handleTorrentTagAdded(TorrentHandle *const torrent, const QString &tag) void Session::handleTorrentTagAdded(TorrentHandle *const torrent, const QString &tag)
{ {
saveTorrentResumeData(torrent);
emit torrentTagAdded(torrent, tag); emit torrentTagAdded(torrent, tag);
} }
void Session::handleTorrentTagRemoved(TorrentHandle *const torrent, const QString &tag) void Session::handleTorrentTagRemoved(TorrentHandle *const torrent, const QString &tag)
{ {
saveTorrentResumeData(torrent);
emit torrentTagRemoved(torrent, tag); emit torrentTagRemoved(torrent, tag);
} }
void Session::handleTorrentSavingModeChanged(TorrentHandle *const torrent) void Session::handleTorrentSavingModeChanged(TorrentHandle *const torrent)
{ {
saveTorrentResumeData(torrent);
emit torrentSavingModeChanged(torrent); emit torrentSavingModeChanged(torrent);
} }
void Session::handleTorrentTrackersAdded(TorrentHandle *const torrent, const QList<TrackerEntry> &newTrackers) void Session::handleTorrentTrackersAdded(TorrentHandle *const torrent, const QList<TrackerEntry> &newTrackers)
{ {
foreach (const TrackerEntry &newTracker, newTrackers) saveTorrentResumeData(torrent);
Logger::instance()->addMessage(tr("Tracker '%1' was added to torrent '%2'").arg(newTracker.url(), torrent->name()));
for (const TrackerEntry &newTracker : newTrackers)
LogMsg(tr("Tracker '%1' was added to torrent '%2'").arg(newTracker.url(), torrent->name()));
emit trackersAdded(torrent, newTrackers); emit trackersAdded(torrent, newTrackers);
if (torrent->trackers().size() == newTrackers.size()) if (torrent->trackers().size() == newTrackers.size())
emit trackerlessStateChanged(torrent, false); emit trackerlessStateChanged(torrent, false);
@ -3576,8 +3588,10 @@ void Session::handleTorrentTrackersAdded(TorrentHandle *const torrent, const QLi
void Session::handleTorrentTrackersRemoved(TorrentHandle *const torrent, const QList<TrackerEntry> &deletedTrackers) void Session::handleTorrentTrackersRemoved(TorrentHandle *const torrent, const QList<TrackerEntry> &deletedTrackers)
{ {
foreach (const TrackerEntry &deletedTracker, deletedTrackers) saveTorrentResumeData(torrent);
Logger::instance()->addMessage(tr("Tracker '%1' was deleted from torrent '%2'").arg(deletedTracker.url(), torrent->name()));
for (const TrackerEntry &deletedTracker : deletedTrackers)
LogMsg(tr("Tracker '%1' was deleted from torrent '%2'").arg(deletedTracker.url(), torrent->name()));
emit trackersRemoved(torrent, deletedTrackers); emit trackersRemoved(torrent, deletedTrackers);
if (torrent->trackers().size() == 0) if (torrent->trackers().size() == 0)
emit trackerlessStateChanged(torrent, true); emit trackerlessStateChanged(torrent, true);
@ -3586,19 +3600,22 @@ void Session::handleTorrentTrackersRemoved(TorrentHandle *const torrent, const Q
void Session::handleTorrentTrackersChanged(TorrentHandle *const torrent) void Session::handleTorrentTrackersChanged(TorrentHandle *const torrent)
{ {
saveTorrentResumeData(torrent);
emit trackersChanged(torrent); emit trackersChanged(torrent);
} }
void Session::handleTorrentUrlSeedsAdded(TorrentHandle *const torrent, const QList<QUrl> &newUrlSeeds) void Session::handleTorrentUrlSeedsAdded(TorrentHandle *const torrent, const QList<QUrl> &newUrlSeeds)
{ {
foreach (const QUrl &newUrlSeed, newUrlSeeds) saveTorrentResumeData(torrent);
Logger::instance()->addMessage(tr("URL seed '%1' was added to torrent '%2'").arg(newUrlSeed.toString(), torrent->name())); for (const QUrl &newUrlSeed : newUrlSeeds)
LogMsg(tr("URL seed '%1' was added to torrent '%2'").arg(newUrlSeed.toString(), torrent->name()));
} }
void Session::handleTorrentUrlSeedsRemoved(TorrentHandle *const torrent, const QList<QUrl> &urlSeeds) void Session::handleTorrentUrlSeedsRemoved(TorrentHandle *const torrent, const QList<QUrl> &urlSeeds)
{ {
foreach (const QUrl &urlSeed, urlSeeds) saveTorrentResumeData(torrent);
Logger::instance()->addMessage(tr("URL seed '%1' was removed from torrent '%2'").arg(urlSeed.toString(), torrent->name())); for (const QUrl &urlSeed : urlSeeds)
LogMsg(tr("URL seed '%1' was removed from torrent '%2'").arg(urlSeed.toString(), torrent->name()));
} }
void Session::handleTorrentMetadataReceived(TorrentHandle *const torrent) void Session::handleTorrentMetadataReceived(TorrentHandle *const torrent)
@ -3626,6 +3643,7 @@ void Session::handleTorrentPaused(TorrentHandle *const torrent)
void Session::handleTorrentResumed(TorrentHandle *const torrent) void Session::handleTorrentResumed(TorrentHandle *const torrent)
{ {
saveTorrentResumeData(torrent);
emit torrentResumed(torrent); emit torrentResumed(torrent);
} }
@ -3831,7 +3849,7 @@ void Session::startUpTorrents()
{ {
QString hash; QString hash;
MagnetUri magnetUri; MagnetUri magnetUri;
AddTorrentData addTorrentData; CreateTorrentParams addTorrentData;
QByteArray data; QByteArray data;
} TorrentResumeData; } TorrentResumeData;
@ -3864,12 +3882,12 @@ void Session::startUpTorrents()
QString hash = rxMatch.captured(1); QString hash = rxMatch.captured(1);
QString fastresumePath = resumeDataDir.absoluteFilePath(fastresumeName); QString fastresumePath = resumeDataDir.absoluteFilePath(fastresumeName);
QByteArray data; QByteArray data;
AddTorrentData resumeData; CreateTorrentParams torrentParams;
MagnetUri magnetUri; MagnetUri magnetUri;
int queuePosition; int queuePosition;
if (readFile(fastresumePath, data) && loadTorrentResumeData(data, resumeData, queuePosition, magnetUri)) { if (readFile(fastresumePath, data) && loadTorrentResumeData(data, torrentParams, queuePosition, magnetUri)) {
if (queuePosition <= nextQueuePosition) { if (queuePosition <= nextQueuePosition) {
startupTorrent({ hash, magnetUri, resumeData, data }); startupTorrent({ hash, magnetUri, torrentParams, data });
if (queuePosition == nextQueuePosition) { if (queuePosition == nextQueuePosition) {
++nextQueuePosition; ++nextQueuePosition;
@ -3886,7 +3904,7 @@ void Session::startUpTorrents()
if (q != queuePosition) { if (q != queuePosition) {
++numOfRemappedFiles; ++numOfRemappedFiles;
} }
queuedResumeData[q] = {hash, magnetUri, resumeData, data}; queuedResumeData[q] = {hash, magnetUri, torrentParams, data};
} }
} }
} }
@ -4012,6 +4030,7 @@ void Session::handleAlert(libt::alert *a)
case libt::storage_moved_alert::alert_type: case libt::storage_moved_alert::alert_type:
case libt::storage_moved_failed_alert::alert_type: case libt::storage_moved_failed_alert::alert_type:
case libt::torrent_paused_alert::alert_type: case libt::torrent_paused_alert::alert_type:
case libt::torrent_resumed_alert::alert_type:
case libt::tracker_error_alert::alert_type: case libt::tracker_error_alert::alert_type:
case libt::tracker_reply_alert::alert_type: case libt::tracker_reply_alert::alert_type:
case libt::tracker_warning_alert::alert_type: case libt::tracker_warning_alert::alert_type:
@ -4089,25 +4108,19 @@ void Session::createTorrentHandle(const libt::torrent_handle &nativeHandle)
// Magnet added for preload its metadata // Magnet added for preload its metadata
if (!m_addingTorrents.contains(nativeHandle.info_hash())) return; if (!m_addingTorrents.contains(nativeHandle.info_hash())) return;
AddTorrentData data = m_addingTorrents.take(nativeHandle.info_hash()); CreateTorrentParams params = m_addingTorrents.take(nativeHandle.info_hash());
TorrentHandle *const torrent = new TorrentHandle(this, nativeHandle, data); TorrentHandle *const torrent = new TorrentHandle(this, nativeHandle, params);
m_torrents.insert(torrent->hash(), torrent); m_torrents.insert(torrent->hash(), torrent);
Logger *const logger = Logger::instance(); Logger *const logger = Logger::instance();
bool fromMagnetUri = !torrent->hasMetadata(); bool fromMagnetUri = !torrent->hasMetadata();
if (data.resumed) { if (params.restored) {
if (fromMagnetUri && !data.addPaused) logger->addMessage(tr("'%1' restored.", "'torrent name' restored.").arg(torrent->name()));
torrent->resume(data.addForced);
logger->addMessage(tr("'%1' resumed. (fast resume)", "'torrent name' was resumed. (fast resume)")
.arg(torrent->name()));
} }
else { else {
qDebug("This is a NEW torrent (first time)...");
// The following is useless for newly added magnet // The following is useless for newly added magnet
if (!fromMagnetUri) { if (!fromMagnetUri) {
// Backup torrent file // Backup torrent file
@ -4126,9 +4139,6 @@ void Session::createTorrentHandle(const libt::torrent_handle &nativeHandle)
if (isAddTrackersEnabled() && !torrent->isPrivate()) if (isAddTrackersEnabled() && !torrent->isPrivate())
torrent->addTrackers(m_additionalTrackerList); torrent->addTrackers(m_additionalTrackerList);
// Start torrent because it was added in paused state
if (!data.addPaused)
torrent->resume();
logger->addMessage(tr("'%1' added to download list.", "'torrent name' was added to download list.") logger->addMessage(tr("'%1' added to download list.", "'torrent name' was added to download list.")
.arg(torrent->name())); .arg(torrent->name()));
@ -4144,7 +4154,7 @@ void Session::createTorrentHandle(const libt::torrent_handle &nativeHandle)
// Send torrent addition signal // Send torrent addition signal
emit torrentAdded(torrent); emit torrentAdded(torrent);
// Send new torrent signal // Send new torrent signal
if (!data.resumed) if (!params.restored)
emit torrentNew(torrent); emit torrentNew(torrent);
} }
@ -4494,11 +4504,11 @@ namespace
return true; return true;
} }
bool loadTorrentResumeData(const QByteArray &data, AddTorrentData &torrentData, int &prio, MagnetUri &magnetUri) bool loadTorrentResumeData(const QByteArray &data, CreateTorrentParams &torrentParams, int &prio, MagnetUri &magnetUri)
{ {
torrentData = AddTorrentData(); torrentParams = CreateTorrentParams();
torrentData.resumed = true; torrentParams.restored = true;
torrentData.skipChecking = false; torrentParams.skipChecking = false;
libt::error_code ec; libt::error_code ec;
#if LIBTORRENT_VERSION_NUM < 10100 #if LIBTORRENT_VERSION_NUM < 10100
@ -4511,36 +4521,36 @@ namespace
if (ec || (fast.type() != libt::bdecode_node::dict_t)) return false; if (ec || (fast.type() != libt::bdecode_node::dict_t)) return false;
#endif #endif
torrentData.savePath = Profile::instance().fromPortablePath( torrentParams.savePath = Profile::instance().fromPortablePath(
Utils::Fs::fromNativePath(QString::fromStdString(fast.dict_find_string_value("qBt-savePath")))); Utils::Fs::fromNativePath(QString::fromStdString(fast.dict_find_string_value("qBt-savePath"))));
std::string ratioLimitString = fast.dict_find_string_value("qBt-ratioLimit"); std::string ratioLimitString = fast.dict_find_string_value("qBt-ratioLimit");
if (ratioLimitString.empty()) if (ratioLimitString.empty())
torrentData.ratioLimit = fast.dict_find_int_value("qBt-ratioLimit", TorrentHandle::USE_GLOBAL_RATIO * 1000) / 1000.0; torrentParams.ratioLimit = fast.dict_find_int_value("qBt-ratioLimit", TorrentHandle::USE_GLOBAL_RATIO * 1000) / 1000.0;
else else
torrentData.ratioLimit = QString::fromStdString(ratioLimitString).toDouble(); torrentParams.ratioLimit = QString::fromStdString(ratioLimitString).toDouble();
torrentData.seedingTimeLimit = fast.dict_find_int_value("qBt-seedingTimeLimit", TorrentHandle::USE_GLOBAL_SEEDING_TIME); torrentParams.seedingTimeLimit = fast.dict_find_int_value("qBt-seedingTimeLimit", TorrentHandle::USE_GLOBAL_SEEDING_TIME);
// ************************************************************************************** // **************************************************************************************
// Workaround to convert legacy label to category // Workaround to convert legacy label to category
// TODO: Should be removed in future // TODO: Should be removed in future
torrentData.category = QString::fromStdString(fast.dict_find_string_value("qBt-label")); torrentParams.category = QString::fromStdString(fast.dict_find_string_value("qBt-label"));
if (torrentData.category.isEmpty()) if (torrentParams.category.isEmpty())
// ************************************************************************************** // **************************************************************************************
torrentData.category = QString::fromStdString(fast.dict_find_string_value("qBt-category")); torrentParams.category = QString::fromStdString(fast.dict_find_string_value("qBt-category"));
// auto because the return type depends on the #if above. // auto because the return type depends on the #if above.
const auto tagsEntry = fast.dict_find_list("qBt-tags"); const auto tagsEntry = fast.dict_find_list("qBt-tags");
if (isList(tagsEntry)) if (isList(tagsEntry))
torrentData.tags = entryListToSet(tagsEntry); torrentParams.tags = entryListToSet(tagsEntry);
torrentData.name = QString::fromStdString(fast.dict_find_string_value("qBt-name")); torrentParams.name = QString::fromStdString(fast.dict_find_string_value("qBt-name"));
torrentData.hasSeedStatus = fast.dict_find_int_value("qBt-seedStatus"); torrentParams.hasSeedStatus = fast.dict_find_int_value("qBt-seedStatus");
torrentData.disableTempPath = fast.dict_find_int_value("qBt-tempPathDisabled"); torrentParams.disableTempPath = fast.dict_find_int_value("qBt-tempPathDisabled");
torrentData.hasRootFolder = fast.dict_find_int_value("qBt-hasRootFolder"); torrentParams.hasRootFolder = fast.dict_find_int_value("qBt-hasRootFolder");
magnetUri = MagnetUri(QString::fromStdString(fast.dict_find_string_value("qBt-magnetUri"))); magnetUri = MagnetUri(QString::fromStdString(fast.dict_find_string_value("qBt-magnetUri")));
torrentData.addPaused = fast.dict_find_int_value("qBt-paused"); torrentParams.paused = fast.dict_find_int_value("qBt-paused");
torrentData.addForced = fast.dict_find_int_value("qBt-forced"); torrentParams.forced = fast.dict_find_int_value("qBt-forced");
torrentData.firstLastPiecePriority = fast.dict_find_int_value("qBt-firstLastPiecePriority"); torrentParams.firstLastPiecePriority = fast.dict_find_int_value("qBt-firstLastPiecePriority");
torrentData.sequential = fast.dict_find_int_value("qBt-sequential"); torrentParams.sequential = fast.dict_find_int_value("qBt-sequential");
prio = fast.dict_find_int_value("qBt-queuePosition"); prio = fast.dict_find_int_value("qBt-queuePosition");

7
src/base/bittorrent/session.h

@ -138,7 +138,7 @@ namespace BitTorrent
class Tracker; class Tracker;
class MagnetUri; class MagnetUri;
class TrackerEntry; class TrackerEntry;
struct AddTorrentData; struct CreateTorrentParams;
struct TorrentStatusReport struct TorrentStatusReport
{ {
@ -480,6 +480,7 @@ namespace BitTorrent
// TorrentHandle interface // TorrentHandle interface
void handleTorrentShareLimitChanged(TorrentHandle *const torrent); void handleTorrentShareLimitChanged(TorrentHandle *const torrent);
void handleTorrentNameChanged(TorrentHandle *const torrent);
void handleTorrentSavePathChanged(TorrentHandle *const torrent); void handleTorrentSavePathChanged(TorrentHandle *const torrent);
void handleTorrentCategoryChanged(TorrentHandle *const torrent, const QString &oldCategory); void handleTorrentCategoryChanged(TorrentHandle *const torrent, const QString &oldCategory);
void handleTorrentTagAdded(TorrentHandle *const torrent, const QString &tag); void handleTorrentTagAdded(TorrentHandle *const torrent, const QString &tag);
@ -597,7 +598,7 @@ namespace BitTorrent
void enableIPFilter(); void enableIPFilter();
void disableIPFilter(); void disableIPFilter();
bool addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri, bool addTorrent_impl(CreateTorrentParams params, const MagnetUri &magnetUri,
TorrentInfo torrentInfo = TorrentInfo(), TorrentInfo torrentInfo = TorrentInfo(),
const QByteArray &fastresumeData = QByteArray()); const QByteArray &fastresumeData = QByteArray());
bool findIncompleteFiles(TorrentInfo &torrentInfo, QString &savePath) const; bool findIncompleteFiles(TorrentInfo &torrentInfo, QString &savePath) const;
@ -757,7 +758,7 @@ namespace BitTorrent
QHash<InfoHash, TorrentInfo> m_loadedMetadata; QHash<InfoHash, TorrentInfo> m_loadedMetadata;
QHash<InfoHash, TorrentHandle *> m_torrents; QHash<InfoHash, TorrentHandle *> m_torrents;
QHash<InfoHash, AddTorrentData> m_addingTorrents; QHash<InfoHash, CreateTorrentParams> m_addingTorrents;
QHash<QString, AddTorrentParams> m_downloadedTorrents; QHash<QString, AddTorrentParams> m_downloadedTorrents;
QHash<InfoHash, RemovingTorrentData> m_removingTorrents; QHash<InfoHash, RemovingTorrentData> m_removingTorrents;
TorrentStatusReport m_torrentStatusReport; TorrentStatusReport m_torrentStatusReport;

83
src/base/bittorrent/torrenthandle.cpp

@ -85,16 +85,16 @@ namespace
// AddTorrentData // AddTorrentData
AddTorrentData::AddTorrentData() CreateTorrentParams::CreateTorrentParams()
: resumed(false) : restored(false)
, disableTempPath(false) , disableTempPath(false)
, sequential(false) , sequential(false)
, firstLastPiecePriority(false) , firstLastPiecePriority(false)
, hasSeedStatus(false) , hasSeedStatus(false)
, skipChecking(false) , skipChecking(false)
, hasRootFolder(true) , hasRootFolder(true)
, addForced(false) , forced(false)
, addPaused(false) , paused(false)
, uploadLimit(-1) , uploadLimit(-1)
, downloadLimit(-1) , downloadLimit(-1)
, ratioLimit(TorrentHandle::USE_GLOBAL_RATIO) , ratioLimit(TorrentHandle::USE_GLOBAL_RATIO)
@ -102,8 +102,8 @@ AddTorrentData::AddTorrentData()
{ {
} }
AddTorrentData::AddTorrentData(const AddTorrentParams &params) CreateTorrentParams::CreateTorrentParams(const AddTorrentParams &params)
: resumed(false) : restored(false)
, name(params.name) , name(params.name)
, category(params.category) , category(params.category)
, tags(params.tags) , tags(params.tags)
@ -116,8 +116,8 @@ AddTorrentData::AddTorrentData(const AddTorrentParams &params)
, hasRootFolder(params.createSubfolder == TriStateBool::Undefined , hasRootFolder(params.createSubfolder == TriStateBool::Undefined
? Session::instance()->isCreateTorrentSubfolder() ? Session::instance()->isCreateTorrentSubfolder()
: params.createSubfolder == TriStateBool::True) : params.createSubfolder == TriStateBool::True)
, addForced(params.addForced == TriStateBool::True) , forced(params.addForced == TriStateBool::True)
, addPaused(params.addPaused == TriStateBool::Undefined , paused(params.addPaused == TriStateBool::Undefined
? Session::instance()->isAddTorrentPaused() ? Session::instance()->isAddTorrentPaused()
: params.addPaused == TriStateBool::True) : params.addPaused == TriStateBool::True)
, uploadLimit(params.uploadLimit) , uploadLimit(params.uploadLimit)
@ -172,26 +172,25 @@ namespace
} }
TorrentHandle::TorrentHandle(Session *session, const libtorrent::torrent_handle &nativeHandle, TorrentHandle::TorrentHandle(Session *session, const libtorrent::torrent_handle &nativeHandle,
const AddTorrentData &data) const CreateTorrentParams &params)
: QObject(session) : QObject(session)
, m_session(session) , m_session(session)
, m_nativeHandle(nativeHandle) , m_nativeHandle(nativeHandle)
, m_state(TorrentState::Unknown) , m_state(TorrentState::Unknown)
, m_renameCount(0) , m_renameCount(0)
, m_useAutoTMM(data.savePath.isEmpty()) , m_useAutoTMM(params.savePath.isEmpty())
, m_name(data.name) , m_name(params.name)
, m_savePath(Utils::Fs::toNativePath(data.savePath)) , m_savePath(Utils::Fs::toNativePath(params.savePath))
, m_category(data.category) , m_category(params.category)
, m_tags(data.tags) , m_tags(params.tags)
, m_hasSeedStatus(data.hasSeedStatus) , m_hasSeedStatus(params.hasSeedStatus)
, m_ratioLimit(data.ratioLimit) , m_ratioLimit(params.ratioLimit)
, m_seedingTimeLimit(data.seedingTimeLimit) , m_seedingTimeLimit(params.seedingTimeLimit)
, m_tempPathDisabled(data.disableTempPath) , m_tempPathDisabled(params.disableTempPath)
, m_hasMissingFiles(false) , m_hasMissingFiles(false)
, m_hasRootFolder(data.hasRootFolder) , m_hasRootFolder(params.hasRootFolder)
, m_needsToSetFirstLastPiecePriority(false) , m_needsToSetFirstLastPiecePriority(false)
, m_pauseAfterRecheck(false) , m_pauseAfterRecheck(false)
, m_needSaveResumeData(false)
{ {
if (m_useAutoTMM) if (m_useAutoTMM)
m_savePath = Utils::Fs::toNativePath(m_session->categorySavePath(m_category)); m_savePath = Utils::Fs::toNativePath(m_session->categorySavePath(m_category));
@ -207,15 +206,29 @@ TorrentHandle::TorrentHandle(Session *session, const libtorrent::torrent_handle
// download sequentially or have first/last piece priority enabled when // download sequentially or have first/last piece priority enabled when
// its resume data was saved. These two settings are restored later. But // its resume data was saved. These two settings are restored later. But
// if we set them to false now, both will erroneously not be restored. // if we set them to false now, both will erroneously not be restored.
if (!data.resumed || data.sequential) if (!params.restored || params.sequential)
setSequentialDownload(data.sequential); setSequentialDownload(params.sequential);
if (!data.resumed || data.firstLastPiecePriority) if (!params.restored || params.firstLastPiecePriority)
setFirstLastPiecePriority(data.firstLastPiecePriority); setFirstLastPiecePriority(params.firstLastPiecePriority);
if (!data.resumed && hasMetadata()) { if (!params.restored && hasMetadata()) {
if (filesCount() == 1) if (filesCount() == 1)
m_hasRootFolder = false; m_hasRootFolder = false;
} }
// "started" means "all initialization has completed and torrent has started regular processing".
// When torrent added/restored in "paused" state it become "started" immediately after construction.
// When it is added/restored in "resumed" state, it become "started" after it is really resumed
// (i.e. after receiving "torrent resumed" alert).
m_started = (params.restored && hasMetadata() ? isPaused() : params.paused);
if (!m_started) {
if (!params.restored || !hasMetadata()) {
// Resume torrent because it was added in "resumed" state
// but it's actually paused during initialization
resume(params.forced);
}
}
} }
TorrentHandle::~TorrentHandle() {} TorrentHandle::~TorrentHandle() {}
@ -488,8 +501,6 @@ bool TorrentHandle::connectPeer(const PeerAddress &peerAddress)
bool TorrentHandle::needSaveResumeData() const bool TorrentHandle::needSaveResumeData() const
{ {
if (m_needSaveResumeData) return true;
return m_nativeHandle.need_save_resume_data(); return m_nativeHandle.need_save_resume_data();
} }
@ -499,7 +510,6 @@ void TorrentHandle::saveResumeData(bool updateStatus)
this->updateStatus(); this->updateStatus();
m_nativeHandle.save_resume_data(); m_nativeHandle.save_resume_data();
m_needSaveResumeData = false;
} }
int TorrentHandle::filesCount() const int TorrentHandle::filesCount() const
@ -573,7 +583,6 @@ bool TorrentHandle::addTag(const QString &tag)
return false; return false;
m_tags.insert(tag); m_tags.insert(tag);
m_session->handleTorrentTagAdded(this, tag); m_session->handleTorrentTagAdded(this, tag);
m_needSaveResumeData = true;
return true; return true;
} }
return false; return false;
@ -583,7 +592,6 @@ bool TorrentHandle::removeTag(const QString &tag)
{ {
if (m_tags.remove(tag)) { if (m_tags.remove(tag)) {
m_session->handleTorrentTagRemoved(this, tag); m_session->handleTorrentTagRemoved(this, tag);
m_needSaveResumeData = true;
return true; return true;
} }
return false; return false;
@ -1198,7 +1206,7 @@ void TorrentHandle::setName(const QString &name)
{ {
if (m_name != name) { if (m_name != name) {
m_name = name; m_name = name;
m_needSaveResumeData = true; m_session->handleTorrentNameChanged(this);
} }
} }
@ -1214,7 +1222,6 @@ bool TorrentHandle::setCategory(const QString &category)
QString oldCategory = m_category; QString oldCategory = m_category;
m_category = category; m_category = category;
m_needSaveResumeData = true;
m_session->handleTorrentCategoryChanged(this, oldCategory); m_session->handleTorrentCategoryChanged(this, oldCategory);
if (m_useAutoTMM) { if (m_useAutoTMM) {
@ -1252,7 +1259,6 @@ void TorrentHandle::move_impl(QString path, bool overwrite)
} }
else { else {
m_savePath = path; m_savePath = path;
m_needSaveResumeData = true;
m_session->handleTorrentSavePathChanged(this); m_session->handleTorrentSavePathChanged(this);
} }
} }
@ -1597,7 +1603,11 @@ void TorrentHandle::handleTorrentPausedAlert(const libtorrent::torrent_paused_al
void TorrentHandle::handleTorrentResumedAlert(const libtorrent::torrent_resumed_alert *p) void TorrentHandle::handleTorrentResumedAlert(const libtorrent::torrent_resumed_alert *p)
{ {
Q_UNUSED(p); Q_UNUSED(p);
m_session->handleTorrentResumed(this);
if (m_started)
m_session->handleTorrentResumed(this);
else
m_started = true;
} }
void TorrentHandle::handleSaveResumeDataAlert(const libtorrent::save_resume_data_alert *p) void TorrentHandle::handleSaveResumeDataAlert(const libtorrent::save_resume_data_alert *p)
@ -1806,6 +1816,9 @@ void TorrentHandle::handleAlert(libtorrent::alert *a)
case libt::torrent_paused_alert::alert_type: case libt::torrent_paused_alert::alert_type:
handleTorrentPausedAlert(static_cast<libt::torrent_paused_alert*>(a)); handleTorrentPausedAlert(static_cast<libt::torrent_paused_alert*>(a));
break; break;
case libt::torrent_resumed_alert::alert_type:
handleTorrentResumedAlert(static_cast<libt::torrent_resumed_alert*>(a));
break;
case libt::tracker_error_alert::alert_type: case libt::tracker_error_alert::alert_type:
handleTrackerErrorAlert(static_cast<libt::tracker_error_alert*>(a)); handleTrackerErrorAlert(static_cast<libt::tracker_error_alert*>(a));
break; break;
@ -1928,7 +1941,6 @@ void TorrentHandle::setRatioLimit(qreal limit)
if (m_ratioLimit != limit) { if (m_ratioLimit != limit) {
m_ratioLimit = limit; m_ratioLimit = limit;
m_needSaveResumeData = true;
m_session->handleTorrentShareLimitChanged(this); m_session->handleTorrentShareLimitChanged(this);
} }
} }
@ -1942,7 +1954,6 @@ void TorrentHandle::setSeedingTimeLimit(int limit)
if (m_seedingTimeLimit != limit) { if (m_seedingTimeLimit != limit) {
m_seedingTimeLimit = limit; m_seedingTimeLimit = limit;
m_needSaveResumeData = true;
m_session->handleTorrentShareLimitChanged(this); m_session->handleTorrentShareLimitChanged(this);
} }
} }

21
src/base/bittorrent/torrenthandle.h

@ -88,10 +88,10 @@ namespace BitTorrent
class TrackerEntry; class TrackerEntry;
struct AddTorrentParams; struct AddTorrentParams;
struct AddTorrentData struct CreateTorrentParams
{ {
bool resumed; bool restored; // is existing torrent job?
// for both new and resumed torrents // for both new and restored torrents
QString name; QString name;
QString category; QString category;
QSet<QString> tags; QSet<QString> tags;
@ -102,18 +102,18 @@ namespace BitTorrent
bool hasSeedStatus; bool hasSeedStatus;
bool skipChecking; bool skipChecking;
bool hasRootFolder; bool hasRootFolder;
bool addForced; bool forced;
bool addPaused; bool paused;
int uploadLimit; int uploadLimit;
int downloadLimit; int downloadLimit;
// for new torrents // for new torrents
QVector<int> filePriorities; QVector<int> filePriorities;
// for resumed torrents // for restored torrents
qreal ratioLimit; qreal ratioLimit;
int seedingTimeLimit; int seedingTimeLimit;
AddTorrentData(); CreateTorrentParams();
AddTorrentData(const AddTorrentParams &params); CreateTorrentParams(const AddTorrentParams &params);
}; };
struct TrackerInfo struct TrackerInfo
@ -170,7 +170,7 @@ namespace BitTorrent
static const int MAX_SEEDING_TIME; static const int MAX_SEEDING_TIME;
TorrentHandle(Session *session, const libtorrent::torrent_handle &nativeHandle, TorrentHandle(Session *session, const libtorrent::torrent_handle &nativeHandle,
const AddTorrentData &data); const CreateTorrentParams &params);
~TorrentHandle(); ~TorrentHandle();
bool isValid() const; bool isValid() const;
@ -461,8 +461,9 @@ namespace BitTorrent
bool m_needsToSetFirstLastPiecePriority; bool m_needsToSetFirstLastPiecePriority;
bool m_pauseAfterRecheck; bool m_pauseAfterRecheck;
bool m_needSaveResumeData;
QHash<QString, TrackerInfo> m_trackerInfos; QHash<QString, TrackerInfo> m_trackerInfos;
bool m_started = false;
}; };
} }

Loading…
Cancel
Save