From 7ebd63a60f704f7f685368a61a3e19c954d8f93b Mon Sep 17 00:00:00 2001 From: "Vladimir Golovnev (Glassez)" Date: Tue, 10 Jul 2018 14:37:45 +0300 Subject: [PATCH 1/2] Save resume data on torrent change events Closes #9174. --- src/base/bittorrent/session.cpp | 39 ++++++++++++++++++++------- src/base/bittorrent/session.h | 1 + src/base/bittorrent/torrenthandle.cpp | 15 +++-------- src/base/bittorrent/torrenthandle.h | 1 - 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index 7a78a6acc..f43688f57 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -2362,7 +2362,6 @@ void Session::generateResumeData(bool final) if (!final && !torrent->needSaveResumeData()) continue; 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) { - Q_UNUSED(torrent); + saveTorrentResumeData(torrent); updateSeedingLimitTimer(); } void Session::saveTorrentResumeData(TorrentHandle *const torrent, bool finalSave) { + qDebug("Saving fastresume data for %s", qUtf8Printable(torrent->name())); torrent->saveResumeData(finalSave); ++m_numResumeData; } +void Session::handleTorrentNameChanged(TorrentHandle *const torrent) +{ + saveTorrentResumeData(torrent); +} + void Session::handleTorrentSavePathChanged(TorrentHandle *const torrent) { + saveTorrentResumeData(torrent); emit torrentSavePathChanged(torrent); } void Session::handleTorrentCategoryChanged(TorrentHandle *const torrent, const QString &oldCategory) { + saveTorrentResumeData(torrent); emit torrentCategoryChanged(torrent, oldCategory); } void Session::handleTorrentTagAdded(TorrentHandle *const torrent, const QString &tag) { + saveTorrentResumeData(torrent); emit torrentTagAdded(torrent, tag); } void Session::handleTorrentTagRemoved(TorrentHandle *const torrent, const QString &tag) { + saveTorrentResumeData(torrent); emit torrentTagRemoved(torrent, tag); } void Session::handleTorrentSavingModeChanged(TorrentHandle *const torrent) { + saveTorrentResumeData(torrent); emit torrentSavingModeChanged(torrent); } void Session::handleTorrentTrackersAdded(TorrentHandle *const torrent, const QList &newTrackers) { - foreach (const TrackerEntry &newTracker, newTrackers) - Logger::instance()->addMessage(tr("Tracker '%1' was added to torrent '%2'").arg(newTracker.url(), torrent->name())); + saveTorrentResumeData(torrent); + + for (const TrackerEntry &newTracker : newTrackers) + LogMsg(tr("Tracker '%1' was added to torrent '%2'").arg(newTracker.url(), torrent->name())); emit trackersAdded(torrent, newTrackers); if (torrent->trackers().size() == newTrackers.size()) emit trackerlessStateChanged(torrent, false); @@ -3576,8 +3588,10 @@ void Session::handleTorrentTrackersAdded(TorrentHandle *const torrent, const QLi void Session::handleTorrentTrackersRemoved(TorrentHandle *const torrent, const QList &deletedTrackers) { - foreach (const TrackerEntry &deletedTracker, deletedTrackers) - Logger::instance()->addMessage(tr("Tracker '%1' was deleted from torrent '%2'").arg(deletedTracker.url(), torrent->name())); + saveTorrentResumeData(torrent); + + for (const TrackerEntry &deletedTracker : deletedTrackers) + LogMsg(tr("Tracker '%1' was deleted from torrent '%2'").arg(deletedTracker.url(), torrent->name())); emit trackersRemoved(torrent, deletedTrackers); if (torrent->trackers().size() == 0) emit trackerlessStateChanged(torrent, true); @@ -3586,19 +3600,22 @@ void Session::handleTorrentTrackersRemoved(TorrentHandle *const torrent, const Q void Session::handleTorrentTrackersChanged(TorrentHandle *const torrent) { + saveTorrentResumeData(torrent); emit trackersChanged(torrent); } void Session::handleTorrentUrlSeedsAdded(TorrentHandle *const torrent, const QList &newUrlSeeds) { - foreach (const QUrl &newUrlSeed, newUrlSeeds) - Logger::instance()->addMessage(tr("URL seed '%1' was added to torrent '%2'").arg(newUrlSeed.toString(), torrent->name())); + saveTorrentResumeData(torrent); + 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 &urlSeeds) { - foreach (const QUrl &urlSeed, urlSeeds) - Logger::instance()->addMessage(tr("URL seed '%1' was removed from torrent '%2'").arg(urlSeed.toString(), torrent->name())); + saveTorrentResumeData(torrent); + 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) @@ -3626,6 +3643,7 @@ void Session::handleTorrentPaused(TorrentHandle *const torrent) void Session::handleTorrentResumed(TorrentHandle *const torrent) { + saveTorrentResumeData(torrent); emit torrentResumed(torrent); } @@ -4012,6 +4030,7 @@ void Session::handleAlert(libt::alert *a) case libt::storage_moved_alert::alert_type: case libt::storage_moved_failed_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_reply_alert::alert_type: case libt::tracker_warning_alert::alert_type: diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index ec563766e..4153840a6 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -480,6 +480,7 @@ namespace BitTorrent // TorrentHandle interface void handleTorrentShareLimitChanged(TorrentHandle *const torrent); + void handleTorrentNameChanged(TorrentHandle *const torrent); void handleTorrentSavePathChanged(TorrentHandle *const torrent); void handleTorrentCategoryChanged(TorrentHandle *const torrent, const QString &oldCategory); void handleTorrentTagAdded(TorrentHandle *const torrent, const QString &tag); diff --git a/src/base/bittorrent/torrenthandle.cpp b/src/base/bittorrent/torrenthandle.cpp index d478b374d..ea91a067e 100644 --- a/src/base/bittorrent/torrenthandle.cpp +++ b/src/base/bittorrent/torrenthandle.cpp @@ -191,7 +191,6 @@ TorrentHandle::TorrentHandle(Session *session, const libtorrent::torrent_handle , m_hasRootFolder(data.hasRootFolder) , m_needsToSetFirstLastPiecePriority(false) , m_pauseAfterRecheck(false) - , m_needSaveResumeData(false) { if (m_useAutoTMM) m_savePath = Utils::Fs::toNativePath(m_session->categorySavePath(m_category)); @@ -488,8 +487,6 @@ bool TorrentHandle::connectPeer(const PeerAddress &peerAddress) bool TorrentHandle::needSaveResumeData() const { - if (m_needSaveResumeData) return true; - return m_nativeHandle.need_save_resume_data(); } @@ -499,7 +496,6 @@ void TorrentHandle::saveResumeData(bool updateStatus) this->updateStatus(); m_nativeHandle.save_resume_data(); - m_needSaveResumeData = false; } int TorrentHandle::filesCount() const @@ -573,7 +569,6 @@ bool TorrentHandle::addTag(const QString &tag) return false; m_tags.insert(tag); m_session->handleTorrentTagAdded(this, tag); - m_needSaveResumeData = true; return true; } return false; @@ -583,7 +578,6 @@ bool TorrentHandle::removeTag(const QString &tag) { if (m_tags.remove(tag)) { m_session->handleTorrentTagRemoved(this, tag); - m_needSaveResumeData = true; return true; } return false; @@ -1198,7 +1192,7 @@ void TorrentHandle::setName(const QString &name) { if (m_name != name) { m_name = name; - m_needSaveResumeData = true; + m_session->handleTorrentNameChanged(this); } } @@ -1214,7 +1208,6 @@ bool TorrentHandle::setCategory(const QString &category) QString oldCategory = m_category; m_category = category; - m_needSaveResumeData = true; m_session->handleTorrentCategoryChanged(this, oldCategory); if (m_useAutoTMM) { @@ -1252,7 +1245,6 @@ void TorrentHandle::move_impl(QString path, bool overwrite) } else { m_savePath = path; - m_needSaveResumeData = true; m_session->handleTorrentSavePathChanged(this); } } @@ -1806,6 +1798,9 @@ void TorrentHandle::handleAlert(libtorrent::alert *a) case libt::torrent_paused_alert::alert_type: handleTorrentPausedAlert(static_cast(a)); break; + case libt::torrent_resumed_alert::alert_type: + handleTorrentResumedAlert(static_cast(a)); + break; case libt::tracker_error_alert::alert_type: handleTrackerErrorAlert(static_cast(a)); break; @@ -1928,7 +1923,6 @@ void TorrentHandle::setRatioLimit(qreal limit) if (m_ratioLimit != limit) { m_ratioLimit = limit; - m_needSaveResumeData = true; m_session->handleTorrentShareLimitChanged(this); } } @@ -1942,7 +1936,6 @@ void TorrentHandle::setSeedingTimeLimit(int limit) if (m_seedingTimeLimit != limit) { m_seedingTimeLimit = limit; - m_needSaveResumeData = true; m_session->handleTorrentShareLimitChanged(this); } } diff --git a/src/base/bittorrent/torrenthandle.h b/src/base/bittorrent/torrenthandle.h index 61445b532..b225d5140 100644 --- a/src/base/bittorrent/torrenthandle.h +++ b/src/base/bittorrent/torrenthandle.h @@ -461,7 +461,6 @@ namespace BitTorrent bool m_needsToSetFirstLastPiecePriority; bool m_pauseAfterRecheck; - bool m_needSaveResumeData; QHash m_trackerInfos; }; } From cd44ab2fc6f9d6b765d9c40b877b0aede76e3368 Mon Sep 17 00:00:00 2001 From: "Vladimir Golovnev (Glassez)" Date: Wed, 11 Jul 2018 15:44:15 +0300 Subject: [PATCH 2/2] Improve torrent initialization Don't post "torrent resumed" event when torrent starts in "resumed" state. Fix confusing names. Now "resumed torrent" means "unpaused torrent" only. When we load previously added torrent it is called "restored torrent". --- src/base/bittorrent/session.cpp | 113 ++++++++++++-------------- src/base/bittorrent/session.h | 6 +- src/base/bittorrent/torrenthandle.cpp | 68 ++++++++++------ src/base/bittorrent/torrenthandle.h | 20 +++-- 4 files changed, 109 insertions(+), 98 deletions(-) diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index f43688f57..a39fc748b 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -111,7 +111,7 @@ using namespace BitTorrent; namespace { 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 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 -bool Session::addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri, +bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magnetUri, TorrentInfo torrentInfo, const QByteArray &fastresumeData) { - addData.savePath = normalizeSavePath(addData.savePath, ""); + params.savePath = normalizeSavePath(params.savePath, ""); - if (!addData.category.isEmpty()) { - if (!m_categories.contains(addData.category) && !addCategory(addData.category)) { - qWarning() << "Couldn't create category" << addData.category; - addData.category = ""; + if (!params.category.isEmpty()) { + if (!m_categories.contains(params.category) && !addCategory(params.category)) { + qWarning() << "Couldn't create category" << params.category; + params.category = ""; } } @@ -2127,10 +2127,10 @@ bool Session::addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri std::vector filePriorities; QString savePath; - if (addData.savePath.isEmpty()) // using Automatic mode - savePath = categorySavePath(addData.category); + if (params.savePath.isEmpty()) // using Automatic mode + savePath = categorySavePath(params.category); else // using Manual mode - savePath = addData.savePath; + savePath = params.savePath; bool fromMagnetUri = magnetUri.isValid(); if (fromMagnetUri) { @@ -2151,7 +2151,7 @@ bool Session::addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri adjustLimits(); // use common 2nd step of torrent addition - m_addingTorrents.insert(hash, addData); + m_addingTorrents.insert(hash, params); createTorrentHandle(handle); return true; } @@ -2159,23 +2159,23 @@ bool Session::addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri p = magnetUri.addTorrentParams(); } else if (torrentInfo.isValid()) { - if (!addData.resumed) { - if (!addData.hasRootFolder) + if (!params.restored) { + if (!params.hasRootFolder) torrentInfo.stripRootFolder(); // Metadata - if (!addData.hasSeedStatus) + if (!params.hasSeedStatus) findIncompleteFiles(torrentInfo, savePath); // if torrent name wasn't explicitly set we handle the case of // initial renaming of torrent content and rename torrent accordingly - if (addData.name.isEmpty()) { + if (params.name.isEmpty()) { QString contentName = torrentInfo.rootFolder(); if (contentName.isEmpty() && (torrentInfo.filesCount() == 1)) contentName = torrentInfo.fileName(0); 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; } - if (addData.resumed && !fromMagnetUri) { + if (params.restored && !fromMagnetUri) { // Set torrent fast resume data p.resume_data = {fastresumeData.constData(), fastresumeData.constData() + fastresumeData.size()}; p.flags |= libt::add_torrent_params::flag_use_resume_save_path; } else { - foreach (int prio, addData.filePriorities) + foreach (int prio, params.filePriorities) filePriorities.push_back(prio); p.file_priorities = filePriorities; } @@ -2228,7 +2228,7 @@ bool Session::addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri // Seeding mode // 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; else 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_uploads = maxUploadsPerTorrent(); p.save_path = Utils::Fs::toNativePath(savePath).toStdString(); - p.upload_limit = addData.uploadLimit; - p.download_limit = addData.downloadLimit; + p.upload_limit = params.uploadLimit; + p.download_limit = params.downloadLimit; - m_addingTorrents.insert(hash, addData); + m_addingTorrents.insert(hash, params); // Adding torrent to BitTorrent session m_nativeSession->async_add_torrent(p); return true; @@ -3849,7 +3849,7 @@ void Session::startUpTorrents() { QString hash; MagnetUri magnetUri; - AddTorrentData addTorrentData; + CreateTorrentParams addTorrentData; QByteArray data; } TorrentResumeData; @@ -3882,12 +3882,12 @@ void Session::startUpTorrents() QString hash = rxMatch.captured(1); QString fastresumePath = resumeDataDir.absoluteFilePath(fastresumeName); QByteArray data; - AddTorrentData resumeData; + CreateTorrentParams torrentParams; MagnetUri magnetUri; int queuePosition; - if (readFile(fastresumePath, data) && loadTorrentResumeData(data, resumeData, queuePosition, magnetUri)) { + if (readFile(fastresumePath, data) && loadTorrentResumeData(data, torrentParams, queuePosition, magnetUri)) { if (queuePosition <= nextQueuePosition) { - startupTorrent({ hash, magnetUri, resumeData, data }); + startupTorrent({ hash, magnetUri, torrentParams, data }); if (queuePosition == nextQueuePosition) { ++nextQueuePosition; @@ -3904,7 +3904,7 @@ void Session::startUpTorrents() if (q != queuePosition) { ++numOfRemappedFiles; } - queuedResumeData[q] = {hash, magnetUri, resumeData, data}; + queuedResumeData[q] = {hash, magnetUri, torrentParams, data}; } } } @@ -4108,25 +4108,19 @@ void Session::createTorrentHandle(const libt::torrent_handle &nativeHandle) // Magnet added for preload its metadata 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); Logger *const logger = Logger::instance(); bool fromMagnetUri = !torrent->hasMetadata(); - if (data.resumed) { - if (fromMagnetUri && !data.addPaused) - torrent->resume(data.addForced); - - logger->addMessage(tr("'%1' resumed. (fast resume)", "'torrent name' was resumed. (fast resume)") - .arg(torrent->name())); + if (params.restored) { + logger->addMessage(tr("'%1' restored.", "'torrent name' restored.").arg(torrent->name())); } else { - qDebug("This is a NEW torrent (first time)..."); - // The following is useless for newly added magnet if (!fromMagnetUri) { // Backup torrent file @@ -4145,9 +4139,6 @@ void Session::createTorrentHandle(const libt::torrent_handle &nativeHandle) if (isAddTrackersEnabled() && !torrent->isPrivate()) 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.") .arg(torrent->name())); @@ -4163,7 +4154,7 @@ void Session::createTorrentHandle(const libt::torrent_handle &nativeHandle) // Send torrent addition signal emit torrentAdded(torrent); // Send new torrent signal - if (!data.resumed) + if (!params.restored) emit torrentNew(torrent); } @@ -4513,11 +4504,11 @@ namespace 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(); - torrentData.resumed = true; - torrentData.skipChecking = false; + torrentParams = CreateTorrentParams(); + torrentParams.restored = true; + torrentParams.skipChecking = false; libt::error_code ec; #if LIBTORRENT_VERSION_NUM < 10100 @@ -4530,36 +4521,36 @@ namespace if (ec || (fast.type() != libt::bdecode_node::dict_t)) return false; #endif - torrentData.savePath = Profile::instance().fromPortablePath( + torrentParams.savePath = Profile::instance().fromPortablePath( Utils::Fs::fromNativePath(QString::fromStdString(fast.dict_find_string_value("qBt-savePath")))); std::string ratioLimitString = fast.dict_find_string_value("qBt-ratioLimit"); 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 - torrentData.ratioLimit = QString::fromStdString(ratioLimitString).toDouble(); - torrentData.seedingTimeLimit = fast.dict_find_int_value("qBt-seedingTimeLimit", TorrentHandle::USE_GLOBAL_SEEDING_TIME); + torrentParams.ratioLimit = QString::fromStdString(ratioLimitString).toDouble(); + torrentParams.seedingTimeLimit = fast.dict_find_int_value("qBt-seedingTimeLimit", TorrentHandle::USE_GLOBAL_SEEDING_TIME); // ************************************************************************************** // Workaround to convert legacy label to category // TODO: Should be removed in future - torrentData.category = QString::fromStdString(fast.dict_find_string_value("qBt-label")); - if (torrentData.category.isEmpty()) + torrentParams.category = QString::fromStdString(fast.dict_find_string_value("qBt-label")); + 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. const auto tagsEntry = fast.dict_find_list("qBt-tags"); if (isList(tagsEntry)) - torrentData.tags = entryListToSet(tagsEntry); - torrentData.name = QString::fromStdString(fast.dict_find_string_value("qBt-name")); - torrentData.hasSeedStatus = fast.dict_find_int_value("qBt-seedStatus"); - torrentData.disableTempPath = fast.dict_find_int_value("qBt-tempPathDisabled"); - torrentData.hasRootFolder = fast.dict_find_int_value("qBt-hasRootFolder"); + torrentParams.tags = entryListToSet(tagsEntry); + torrentParams.name = QString::fromStdString(fast.dict_find_string_value("qBt-name")); + torrentParams.hasSeedStatus = fast.dict_find_int_value("qBt-seedStatus"); + torrentParams.disableTempPath = fast.dict_find_int_value("qBt-tempPathDisabled"); + torrentParams.hasRootFolder = fast.dict_find_int_value("qBt-hasRootFolder"); magnetUri = MagnetUri(QString::fromStdString(fast.dict_find_string_value("qBt-magnetUri"))); - torrentData.addPaused = fast.dict_find_int_value("qBt-paused"); - torrentData.addForced = fast.dict_find_int_value("qBt-forced"); - torrentData.firstLastPiecePriority = fast.dict_find_int_value("qBt-firstLastPiecePriority"); - torrentData.sequential = fast.dict_find_int_value("qBt-sequential"); + torrentParams.paused = fast.dict_find_int_value("qBt-paused"); + torrentParams.forced = fast.dict_find_int_value("qBt-forced"); + torrentParams.firstLastPiecePriority = fast.dict_find_int_value("qBt-firstLastPiecePriority"); + torrentParams.sequential = fast.dict_find_int_value("qBt-sequential"); prio = fast.dict_find_int_value("qBt-queuePosition"); diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index 4153840a6..1d41eec03 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -138,7 +138,7 @@ namespace BitTorrent class Tracker; class MagnetUri; class TrackerEntry; - struct AddTorrentData; + struct CreateTorrentParams; struct TorrentStatusReport { @@ -598,7 +598,7 @@ namespace BitTorrent void enableIPFilter(); void disableIPFilter(); - bool addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri, + bool addTorrent_impl(CreateTorrentParams params, const MagnetUri &magnetUri, TorrentInfo torrentInfo = TorrentInfo(), const QByteArray &fastresumeData = QByteArray()); bool findIncompleteFiles(TorrentInfo &torrentInfo, QString &savePath) const; @@ -758,7 +758,7 @@ namespace BitTorrent QHash m_loadedMetadata; QHash m_torrents; - QHash m_addingTorrents; + QHash m_addingTorrents; QHash m_downloadedTorrents; QHash m_removingTorrents; TorrentStatusReport m_torrentStatusReport; diff --git a/src/base/bittorrent/torrenthandle.cpp b/src/base/bittorrent/torrenthandle.cpp index ea91a067e..cb6efb875 100644 --- a/src/base/bittorrent/torrenthandle.cpp +++ b/src/base/bittorrent/torrenthandle.cpp @@ -85,16 +85,16 @@ namespace // AddTorrentData -AddTorrentData::AddTorrentData() - : resumed(false) +CreateTorrentParams::CreateTorrentParams() + : restored(false) , disableTempPath(false) , sequential(false) , firstLastPiecePriority(false) , hasSeedStatus(false) , skipChecking(false) , hasRootFolder(true) - , addForced(false) - , addPaused(false) + , forced(false) + , paused(false) , uploadLimit(-1) , downloadLimit(-1) , ratioLimit(TorrentHandle::USE_GLOBAL_RATIO) @@ -102,8 +102,8 @@ AddTorrentData::AddTorrentData() { } -AddTorrentData::AddTorrentData(const AddTorrentParams ¶ms) - : resumed(false) +CreateTorrentParams::CreateTorrentParams(const AddTorrentParams ¶ms) + : restored(false) , name(params.name) , category(params.category) , tags(params.tags) @@ -116,8 +116,8 @@ AddTorrentData::AddTorrentData(const AddTorrentParams ¶ms) , hasRootFolder(params.createSubfolder == TriStateBool::Undefined ? Session::instance()->isCreateTorrentSubfolder() : params.createSubfolder == TriStateBool::True) - , addForced(params.addForced == TriStateBool::True) - , addPaused(params.addPaused == TriStateBool::Undefined + , forced(params.addForced == TriStateBool::True) + , paused(params.addPaused == TriStateBool::Undefined ? Session::instance()->isAddTorrentPaused() : params.addPaused == TriStateBool::True) , uploadLimit(params.uploadLimit) @@ -172,23 +172,23 @@ namespace } TorrentHandle::TorrentHandle(Session *session, const libtorrent::torrent_handle &nativeHandle, - const AddTorrentData &data) + const CreateTorrentParams ¶ms) : QObject(session) , m_session(session) , m_nativeHandle(nativeHandle) , m_state(TorrentState::Unknown) , m_renameCount(0) - , m_useAutoTMM(data.savePath.isEmpty()) - , m_name(data.name) - , m_savePath(Utils::Fs::toNativePath(data.savePath)) - , m_category(data.category) - , m_tags(data.tags) - , m_hasSeedStatus(data.hasSeedStatus) - , m_ratioLimit(data.ratioLimit) - , m_seedingTimeLimit(data.seedingTimeLimit) - , m_tempPathDisabled(data.disableTempPath) + , m_useAutoTMM(params.savePath.isEmpty()) + , m_name(params.name) + , m_savePath(Utils::Fs::toNativePath(params.savePath)) + , m_category(params.category) + , m_tags(params.tags) + , m_hasSeedStatus(params.hasSeedStatus) + , m_ratioLimit(params.ratioLimit) + , m_seedingTimeLimit(params.seedingTimeLimit) + , m_tempPathDisabled(params.disableTempPath) , m_hasMissingFiles(false) - , m_hasRootFolder(data.hasRootFolder) + , m_hasRootFolder(params.hasRootFolder) , m_needsToSetFirstLastPiecePriority(false) , m_pauseAfterRecheck(false) { @@ -206,15 +206,29 @@ TorrentHandle::TorrentHandle(Session *session, const libtorrent::torrent_handle // download sequentially or have first/last piece priority enabled when // 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 (!data.resumed || data.sequential) - setSequentialDownload(data.sequential); - if (!data.resumed || data.firstLastPiecePriority) - setFirstLastPiecePriority(data.firstLastPiecePriority); + if (!params.restored || params.sequential) + setSequentialDownload(params.sequential); + if (!params.restored || params.firstLastPiecePriority) + setFirstLastPiecePriority(params.firstLastPiecePriority); - if (!data.resumed && hasMetadata()) { + if (!params.restored && hasMetadata()) { if (filesCount() == 1) 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() {} @@ -1589,7 +1603,11 @@ void TorrentHandle::handleTorrentPausedAlert(const libtorrent::torrent_paused_al void TorrentHandle::handleTorrentResumedAlert(const libtorrent::torrent_resumed_alert *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) diff --git a/src/base/bittorrent/torrenthandle.h b/src/base/bittorrent/torrenthandle.h index b225d5140..d5ad32bf7 100644 --- a/src/base/bittorrent/torrenthandle.h +++ b/src/base/bittorrent/torrenthandle.h @@ -88,10 +88,10 @@ namespace BitTorrent class TrackerEntry; struct AddTorrentParams; - struct AddTorrentData + struct CreateTorrentParams { - bool resumed; - // for both new and resumed torrents + bool restored; // is existing torrent job? + // for both new and restored torrents QString name; QString category; QSet tags; @@ -102,18 +102,18 @@ namespace BitTorrent bool hasSeedStatus; bool skipChecking; bool hasRootFolder; - bool addForced; - bool addPaused; + bool forced; + bool paused; int uploadLimit; int downloadLimit; // for new torrents QVector filePriorities; - // for resumed torrents + // for restored torrents qreal ratioLimit; int seedingTimeLimit; - AddTorrentData(); - AddTorrentData(const AddTorrentParams ¶ms); + CreateTorrentParams(); + CreateTorrentParams(const AddTorrentParams ¶ms); }; struct TrackerInfo @@ -170,7 +170,7 @@ namespace BitTorrent static const int MAX_SEEDING_TIME; TorrentHandle(Session *session, const libtorrent::torrent_handle &nativeHandle, - const AddTorrentData &data); + const CreateTorrentParams ¶ms); ~TorrentHandle(); bool isValid() const; @@ -462,6 +462,8 @@ namespace BitTorrent bool m_pauseAfterRecheck; QHash m_trackerInfos; + + bool m_started = false; }; }