From 8cc9c64ff86beaf1f587e8b34cab962ac3177d24 Mon Sep 17 00:00:00 2001 From: "Vladimir Golovnev (Glassez)" Date: Thu, 4 Jun 2015 11:03:19 +0300 Subject: [PATCH] Fix resume torrents without metadata. --- src/core/bittorrent/session.cpp | 61 ++++++++++++++------------- src/core/bittorrent/session.h | 1 + src/core/bittorrent/torrenthandle.cpp | 40 +++++++++++------- src/core/bittorrent/torrenthandle.h | 3 +- src/core/bittorrent/torrentinfo.cpp | 7 --- src/core/bittorrent/torrentinfo.h | 1 - 6 files changed, 59 insertions(+), 54 deletions(-) diff --git a/src/core/bittorrent/session.cpp b/src/core/bittorrent/session.cpp index 49a463206..a883854f4 100644 --- a/src/core/bittorrent/session.cpp +++ b/src/core/bittorrent/session.cpp @@ -95,7 +95,7 @@ namespace libt = libtorrent; using namespace BitTorrent; static bool readFile(const QString &path, QByteArray &buf); -static bool loadTorrentResumeData(const QByteArray &data, AddTorrentData &out); +static bool loadTorrentResumeData(const QByteArray &data, AddTorrentData &out, MagnetUri &magnetUri); static void torrentQueuePositionUp(const libt::torrent_handle &handle); static void torrentQueuePositionDown(const libt::torrent_handle &handle); @@ -1086,33 +1086,34 @@ bool Session::addTorrent_impl(const AddTorrentData &addData, const MagnetUri &ma p = magnetUri.addTorrentParams(); hash = magnetUri.hash(); } - else { - if (!torrentInfo.isValid()) return false; - + else if (torrentInfo.isValid()) { // Metadata p.ti = torrentInfo.nativeInfo(); hash = torrentInfo.hash(); + } + else { + Q_ASSERT(false); + } - if (addData.resumed) { - // Set torrent fast resume data + if (addData.resumed && !fromMagnetUri) { + // Set torrent fast resume data #if LIBTORRENT_VERSION_NUM < 10000 - p.resume_data = &buf; + p.resume_data = &buf; #else - p.resume_data = buf; - p.flags |= libt::add_torrent_params::flag_use_resume_save_path; + p.resume_data = buf; + p.flags |= libt::add_torrent_params::flag_use_resume_save_path; #endif - p.flags |= libt::add_torrent_params::flag_merge_resume_trackers; + p.flags |= libt::add_torrent_params::flag_merge_resume_trackers; - } - else { - foreach (int prio, addData.filePriorities) - filePriorities.push_back(prio); + } + else { + foreach (int prio, addData.filePriorities) + filePriorities.push_back(prio); #if LIBTORRENT_VERSION_NUM < 10000 - p.file_priorities = &filePriorities; + p.file_priorities = &filePriorities; #else - p.file_priorities = filePriorities; + p.file_priorities = filePriorities; #endif - } } // We should not add torrent if it already @@ -1929,22 +1930,15 @@ void Session::startUpTorrents() resumeDataDir.absoluteFilePath(QString("%1.fastresume.%2").arg(hash).arg(prio)); QByteArray data; AddTorrentData resumeData; - if (readFile(fastresumePath, data) && loadTorrentResumeData(data, resumeData)) { + MagnetUri magnetUri; + if (readFile(fastresumePath, data) && loadTorrentResumeData(data, resumeData, magnetUri)) { filePath = resumeDataDir.filePath(QString("%1.torrent").arg(hash)); - if (QFile(filePath).exists()) { - qDebug("Starting up torrent %s ...", qPrintable(hash)); - if (!addTorrent_impl(resumeData, MagnetUri(), TorrentInfo::loadFromFile(filePath), data)) - logger->addMessage(tr("Unable to resume torrent '%1'.", "e.g: Unable to resume torrent 'hash'.") - .arg(Utils::Fs::toNativePath(hash)), Log::CRITICAL); - } - else { - logger->addMessage(tr("Unable to resume torrent '%1': torrent file not found.", "e.g: Unable to resume torrent 'hash': torrent file not found.") + qDebug("Starting up torrent %s ...", qPrintable(hash)); + if (!addTorrent_impl(resumeData, magnetUri, TorrentInfo::loadFromFile(filePath), data)) + logger->addMessage(tr("Unable to resume torrent '%1'.", "e.g: Unable to resume torrent 'hash'.") .arg(Utils::Fs::toNativePath(hash)), Log::CRITICAL); - } } } - - qDebug("Unfinished torrents resumed."); } quint64 Session::getAlltimeDL() const @@ -2121,6 +2115,9 @@ void Session::handleAddTorrentAlert(libtorrent::add_torrent_alert *p) 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())); } @@ -2363,7 +2360,7 @@ bool readFile(const QString &path, QByteArray &buf) return true; } -bool loadTorrentResumeData(const QByteArray &data, AddTorrentData &out) +bool loadTorrentResumeData(const QByteArray &data, AddTorrentData &out, MagnetUri &magnetUri) { out = AddTorrentData(); out.resumed = true; @@ -2381,6 +2378,10 @@ bool loadTorrentResumeData(const QByteArray &data, AddTorrentData &out) out.hasSeedStatus = fast.dict_find_int_value("qBt-seedStatus"); out.disableTempPath = fast.dict_find_int_value("qBt-tempPathDisabled"); + magnetUri = MagnetUri(Utils::String::fromStdString(fast.dict_find_string_value("qBt-magnetUri"))); + out.addPaused = fast.dict_find_int_value("qBt-paused"); + out.addForced = fast.dict_find_int_value("qBt-forced"); + return true; } diff --git a/src/core/bittorrent/session.h b/src/core/bittorrent/session.h index fa64c40d2..2e7284767 100644 --- a/src/core/bittorrent/session.h +++ b/src/core/bittorrent/session.h @@ -113,6 +113,7 @@ namespace BitTorrent QString savePath; bool disableTempPath; // e.g. for imported torrents bool sequential; + TriStateBool addForced; TriStateBool addPaused; QVector filePriorities; // used if TorrentInfo is set bool ignoreShareRatio; diff --git a/src/core/bittorrent/torrenthandle.cpp b/src/core/bittorrent/torrenthandle.cpp index 7337431fe..e446f2af8 100644 --- a/src/core/bittorrent/torrenthandle.cpp +++ b/src/core/bittorrent/torrenthandle.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #ifdef Q_OS_WIN @@ -130,6 +131,7 @@ AddTorrentData::AddTorrentData(const AddTorrentParams &in) , disableTempPath(in.disableTempPath) , sequential(in.sequential) , hasSeedStatus(in.skipChecking) + , addForced(in.addForced) , addPaused(in.addPaused) , filePriorities(in.filePriorities) , ratioLimit(TorrentHandle::USE_GLOBAL_RATIO) @@ -1437,26 +1439,34 @@ void TorrentHandle::handleTorrentResumedAlert(libtorrent::torrent_resumed_alert void TorrentHandle::handleSaveResumeDataAlert(libtorrent::save_resume_data_alert *p) { - if (p->resume_data) { - (*(p->resume_data))["qBt-addedTime"] = m_addedTime.toTime_t(); - (*(p->resume_data))["qBt-savePath"] = m_useDefaultSavePath ? "" : m_savePath.toUtf8().constData(); - (*(p->resume_data))["qBt-ratioLimit"] = QString::number(m_ratioLimit).toUtf8().constData(); - (*(p->resume_data))["qBt-label"] = m_label.toUtf8().constData(); - (*(p->resume_data))["qBt-name"] = m_name.toUtf8().constData(); - (*(p->resume_data))["qBt-seedStatus"] = m_hasSeedStatus; - (*(p->resume_data))["qBt-tempPathDisabled"] = m_tempPathDisabled; + const bool useDummyResumeData = !(p && p->resume_data); + libtorrent::entry dummyEntry; - m_session->handleTorrentResumeDataReady(this, *(p->resume_data)); - } - else { - m_session->handleTorrentResumeDataFailed(this); + libtorrent::entry &resumeData = useDummyResumeData ? dummyEntry : *(p->resume_data); + if (useDummyResumeData) { + resumeData["qBt-magnetUri"] = Utils::String::toStdString(toMagnetUri()); + resumeData["qBt-paused"] = isPaused(); + resumeData["qBt-forced"] = isForced(); } + resumeData["qBt-addedTime"] = m_addedTime.toTime_t(); + resumeData["qBt-savePath"] = m_useDefaultSavePath ? "" : Utils::String::toStdString(m_savePath); + resumeData["qBt-ratioLimit"] = Utils::String::toStdString(QString::number(m_ratioLimit)); + resumeData["qBt-label"] = Utils::String::toStdString(m_label); + resumeData["qBt-name"] = Utils::String::toStdString(m_name); + resumeData["qBt-seedStatus"] = m_hasSeedStatus; + resumeData["qBt-tempPathDisabled"] = m_tempPathDisabled; + + m_session->handleTorrentResumeDataReady(this, resumeData); } void TorrentHandle::handleSaveResumeDataFailedAlert(libtorrent::save_resume_data_failed_alert *p) { - Q_UNUSED(p); - m_session->handleTorrentResumeDataFailed(this); + // if torrent has no metadata we should save dummy fastresume data + // containing Magnet URI and qBittorrent own resume data only + if (p->error.value() == libt::errors::no_metadata) + handleSaveResumeDataAlert(0); + else + m_session->handleTorrentResumeDataFailed(this); } void TorrentHandle::handleFastResumeRejectedAlert(libtorrent::fastresume_rejected_alert *p) @@ -1808,7 +1818,7 @@ void TorrentHandle::flushCache() QString TorrentHandle::toMagnetUri() const { - return m_torrentInfo.toMagnetUri(); + return Utils::String::fromStdString(libt::make_magnet_uri(m_nativeHandle)); } void TorrentHandle::resolveCountries(bool b) diff --git a/src/core/bittorrent/torrenthandle.h b/src/core/bittorrent/torrenthandle.h index bbab9a73f..1b0401420 100644 --- a/src/core/bittorrent/torrenthandle.h +++ b/src/core/bittorrent/torrenthandle.h @@ -91,8 +91,9 @@ namespace BitTorrent bool disableTempPath; bool sequential; bool hasSeedStatus; - // for new torrents + TriStateBool addForced; TriStateBool addPaused; + // for new torrents QVector filePriorities; bool ignoreShareRatio; // for resumed torrents diff --git a/src/core/bittorrent/torrentinfo.cpp b/src/core/bittorrent/torrentinfo.cpp index 6447698bc..2d454e2e2 100644 --- a/src/core/bittorrent/torrentinfo.cpp +++ b/src/core/bittorrent/torrentinfo.cpp @@ -32,7 +32,6 @@ #include #include -#include #include "core/utils/misc.h" #include "core/utils/fs.h" @@ -212,12 +211,6 @@ QByteArray TorrentInfo::metadata() const return QByteArray(m_nativeInfo->metadata().get(), m_nativeInfo->metadata_size()); } -QString TorrentInfo::toMagnetUri() const -{ - if (!isValid()) return QString(); - return Utils::String::fromStdString(libt::make_magnet_uri(*m_nativeInfo)); -} - void TorrentInfo::renameFile(uint index, const QString &newPath) { if (!isValid()) return; diff --git a/src/core/bittorrent/torrentinfo.h b/src/core/bittorrent/torrentinfo.h index 44fc4adb2..392fa8b46 100644 --- a/src/core/bittorrent/torrentinfo.h +++ b/src/core/bittorrent/torrentinfo.h @@ -75,7 +75,6 @@ namespace BitTorrent QList trackers() const; QList urlSeeds() const; QByteArray metadata() const; - QString toMagnetUri() const; void renameFile(uint index, const QString &newPath); boost::intrusive_ptr nativeInfo() const;