mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-08-14 10:37:06 -07:00
Merge pull request #10929 from glassez/backport
Fix torrent checking issues (backport to v4.1.x)
This commit is contained in:
commit
4682e31ab7
4 changed files with 133 additions and 62 deletions
|
@ -2147,26 +2147,26 @@ bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magne
|
|||
if (fromMagnetUri) {
|
||||
hash = magnetUri.hash();
|
||||
|
||||
if (m_loadedMetadata.contains(hash)) {
|
||||
// Adding preloaded torrent
|
||||
m_loadedMetadata.remove(hash);
|
||||
libt::torrent_handle handle = m_nativeSession->find_torrent(hash);
|
||||
--m_extraLimit;
|
||||
|
||||
try {
|
||||
handle.auto_managed(false);
|
||||
// Preloaded torrent is in "Upload mode" so we need to disable it
|
||||
// otherwise the torrent never be downloaded (until application restart)
|
||||
handle.set_upload_mode(false);
|
||||
handle.pause();
|
||||
const auto it = m_loadedMetadata.constFind(hash);
|
||||
if (it != m_loadedMetadata.constEnd()) {
|
||||
// Adding preloaded torrent...
|
||||
const TorrentInfo metadata = it.value();
|
||||
if (metadata.isValid()) {
|
||||
// Metadata is received and torrent_handle is being deleted
|
||||
// so we can't reuse it. Just add torrent using its metadata.
|
||||
return addTorrent_impl(params
|
||||
, MagnetUri {}, metadata, fastresumeData);
|
||||
}
|
||||
catch (std::exception &) {}
|
||||
|
||||
adjustLimits();
|
||||
// Reuse existing torrent_handle
|
||||
lt::torrent_handle handle = m_nativeSession->find_torrent(hash);
|
||||
// We need to pause it first to create TorrentHandle within the same
|
||||
// underlying state as in other cases.
|
||||
handle.auto_managed(false);
|
||||
handle.pause();
|
||||
|
||||
// use common 2nd step of torrent addition
|
||||
m_loadedMetadata.remove(hash);
|
||||
m_addingTorrents.insert(hash, params);
|
||||
createTorrentHandle(handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2225,9 +2225,12 @@ bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magne
|
|||
else
|
||||
p.storage_mode = libt::storage_mode_sparse;
|
||||
|
||||
p.flags |= libt::add_torrent_params::flag_paused; // Start in pause
|
||||
p.flags &= ~libt::add_torrent_params::flag_auto_managed; // Because it is added in paused state
|
||||
p.flags &= ~libt::add_torrent_params::flag_duplicate_is_error; // Already checked
|
||||
// Make sure the torrent will be initially checked and then paused
|
||||
// to perform some service jobs on it. We will start it if needed.
|
||||
p.flags |= lt::add_torrent_params::flag_paused;
|
||||
p.flags |= lt::add_torrent_params::flag_auto_managed;
|
||||
p.flags |= lt::add_torrent_params::flag_stop_when_ready;
|
||||
|
||||
// Seeding mode
|
||||
// Skip checking and directly start seeding (new in libtorrent v0.15)
|
||||
|
@ -2239,7 +2242,15 @@ bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magne
|
|||
if (!fromMagnetUri) {
|
||||
if (params.restored) {
|
||||
// Set torrent fast resume data
|
||||
p.resume_data = {fastresumeData.constData(), fastresumeData.constData() + fastresumeData.size()};
|
||||
// Make sure the torrent will be initially checked and then paused
|
||||
// to perform some service jobs on it. We will start it if needed.
|
||||
// (Workaround to easily support libtorrent-1.1)
|
||||
QByteArray patchedFastresumeData = fastresumeData;
|
||||
patchedFastresumeData.replace("6:pausedi0e", "6:pausedi1e");
|
||||
patchedFastresumeData.replace("12:auto_managedi0e", "12:auto_managedi1e");
|
||||
|
||||
p.resume_data = std::vector<char> {patchedFastresumeData.constData()
|
||||
, (patchedFastresumeData.constData() + patchedFastresumeData.size())};
|
||||
p.flags |= libt::add_torrent_params::flag_use_resume_save_path;
|
||||
}
|
||||
else {
|
||||
|
@ -2247,12 +2258,6 @@ bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magne
|
|||
}
|
||||
}
|
||||
|
||||
if (params.restored && !params.paused) {
|
||||
// Make sure the torrent will restored in "paused" state
|
||||
// Then we will start it if needed
|
||||
p.flags |= libt::add_torrent_params::flag_stop_when_ready;
|
||||
}
|
||||
|
||||
// Limits
|
||||
p.max_connections = maxConnectionsPerTorrent();
|
||||
p.max_uploads = maxUploadsPerTorrent();
|
||||
|
@ -4148,10 +4153,7 @@ void Session::handleAlert(libt::alert *a)
|
|||
case libt::tracker_warning_alert::alert_type:
|
||||
case libt::fastresume_rejected_alert::alert_type:
|
||||
case libt::torrent_checked_alert::alert_type:
|
||||
dispatchTorrentAlert(a);
|
||||
break;
|
||||
case libt::metadata_received_alert::alert_type:
|
||||
handleMetadataReceivedAlert(static_cast<libt::metadata_received_alert*>(a));
|
||||
dispatchTorrentAlert(a);
|
||||
break;
|
||||
case libt::state_update_alert::alert_type:
|
||||
|
@ -4211,8 +4213,19 @@ void Session::handleAlert(libt::alert *a)
|
|||
void Session::dispatchTorrentAlert(libt::alert *a)
|
||||
{
|
||||
TorrentHandle *const torrent = m_torrents.value(static_cast<libt::torrent_alert*>(a)->handle.info_hash());
|
||||
if (torrent)
|
||||
if (torrent) {
|
||||
torrent->handleAlert(a);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (a->type()) {
|
||||
case libt::torrent_paused_alert::alert_type:
|
||||
handleTorrentPausedAlert(static_cast<const libt::torrent_paused_alert*>(a));
|
||||
break;
|
||||
case libt::metadata_received_alert::alert_type:
|
||||
handleMetadataReceivedAlert(static_cast<const libt::metadata_received_alert*>(a));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Session::createTorrentHandle(const libt::torrent_handle &nativeHandle)
|
||||
|
@ -4326,7 +4339,7 @@ void Session::handleTorrentDeleteFailedAlert(libt::torrent_delete_failed_alert *
|
|||
}
|
||||
}
|
||||
|
||||
void Session::handleMetadataReceivedAlert(libt::metadata_received_alert *p)
|
||||
void Session::handleMetadataReceivedAlert(const libt::metadata_received_alert *p)
|
||||
{
|
||||
InfoHash hash = p->handle.info_hash();
|
||||
|
||||
|
@ -4338,6 +4351,25 @@ void Session::handleMetadataReceivedAlert(libt::metadata_received_alert *p)
|
|||
}
|
||||
}
|
||||
|
||||
void Session::handleTorrentPausedAlert(const libtorrent::torrent_paused_alert *p)
|
||||
{
|
||||
const InfoHash hash {p->handle.info_hash()};
|
||||
|
||||
if (m_addingTorrents.contains(hash)) {
|
||||
// Adding preloaded torrent
|
||||
lt::torrent_handle handle = p->handle;
|
||||
--m_extraLimit;
|
||||
|
||||
// Preloaded torrent is in "Upload mode" so we need to disable it
|
||||
// otherwise the torrent never be downloaded (until application restart)
|
||||
handle.set_upload_mode(false);
|
||||
|
||||
adjustLimits();
|
||||
// use common 2nd step of torrent addition
|
||||
createTorrentHandle(handle);
|
||||
}
|
||||
}
|
||||
|
||||
void Session::handleFileErrorAlert(libt::file_error_alert *p)
|
||||
{
|
||||
TorrentHandle *const torrent = m_torrents.value(p->handle.info_hash());
|
||||
|
|
|
@ -614,7 +614,8 @@ namespace BitTorrent
|
|||
void dispatchTorrentAlert(libtorrent::alert *a);
|
||||
void handleAddTorrentAlert(libtorrent::add_torrent_alert *p);
|
||||
void handleStateUpdateAlert(libtorrent::state_update_alert *p);
|
||||
void handleMetadataReceivedAlert(libtorrent::metadata_received_alert *p);
|
||||
void handleMetadataReceivedAlert(const libtorrent::metadata_received_alert *p);
|
||||
void handleTorrentPausedAlert(const libtorrent::torrent_paused_alert *p);
|
||||
void handleFileErrorAlert(libtorrent::file_error_alert *p);
|
||||
void handleTorrentRemovedAlert(libtorrent::torrent_removed_alert *p);
|
||||
void handleTorrentDeletedAlert(libtorrent::torrent_deleted_alert *p);
|
||||
|
|
|
@ -192,6 +192,7 @@ TorrentHandle::TorrentHandle(Session *session, const libtorrent::torrent_handle
|
|||
, m_hasRootFolder(params.hasRootFolder)
|
||||
, m_needsToSetFirstLastPiecePriority(false)
|
||||
, m_needsToStartForced(params.forced)
|
||||
, m_pauseWhenReady(params.paused)
|
||||
{
|
||||
if (m_useAutoTMM)
|
||||
m_savePath = Utils::Fs::toNativePath(m_session->categorySavePath(m_category));
|
||||
|
@ -217,18 +218,18 @@ TorrentHandle::TorrentHandle(Session *session, const libtorrent::torrent_handle
|
|||
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).
|
||||
if (params.paused) {
|
||||
m_startupState = Started;
|
||||
}
|
||||
else if (!params.restored || !hasMetadata()) {
|
||||
// Resume torrent because it was added in "resumed" state
|
||||
// but it's actually paused during initialization
|
||||
m_startupState = Starting;
|
||||
resume(params.forced);
|
||||
if (!hasMetadata()) {
|
||||
// There is nothing to prepare
|
||||
if (!m_pauseWhenReady) {
|
||||
// Resume torrent because it was added in "resumed" state
|
||||
// but it's actually paused during initialization.
|
||||
m_startupState = Starting;
|
||||
resume_impl(m_needsToStartForced);
|
||||
}
|
||||
else {
|
||||
m_startupState = Started;
|
||||
m_pauseWhenReady = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1230,6 +1231,8 @@ bool TorrentHandle::setCategory(const QString &category)
|
|||
|
||||
void TorrentHandle::move(QString path)
|
||||
{
|
||||
if (m_startupState != Started) return;
|
||||
|
||||
m_useAutoTMM = false;
|
||||
m_session->handleTorrentSavingModeChanged(this);
|
||||
|
||||
|
@ -1268,6 +1271,7 @@ void TorrentHandle::forceDHTAnnounce()
|
|||
|
||||
void TorrentHandle::forceRecheck()
|
||||
{
|
||||
if (m_startupState != Started) return;
|
||||
if (!hasMetadata()) return;
|
||||
|
||||
m_nativeHandle.force_recheck();
|
||||
|
@ -1275,7 +1279,8 @@ void TorrentHandle::forceRecheck()
|
|||
|
||||
if (isPaused()) {
|
||||
m_nativeHandle.stop_when_ready(true);
|
||||
resume_impl(false);
|
||||
m_nativeHandle.auto_managed(true);
|
||||
m_pauseWhenReady = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1344,6 +1349,13 @@ void TorrentHandle::toggleFirstLastPiecePriority()
|
|||
|
||||
void TorrentHandle::pause()
|
||||
{
|
||||
if (m_startupState != Started) return;
|
||||
if (m_pauseWhenReady) return;
|
||||
if (isChecking()) {
|
||||
m_pauseWhenReady = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPaused()) return;
|
||||
|
||||
m_nativeHandle.auto_managed(false);
|
||||
|
@ -1358,6 +1370,9 @@ void TorrentHandle::pause()
|
|||
|
||||
void TorrentHandle::resume(bool forced)
|
||||
{
|
||||
if (m_startupState != Started) return;
|
||||
|
||||
m_pauseWhenReady = false;
|
||||
resume_impl(forced);
|
||||
}
|
||||
|
||||
|
@ -1406,6 +1421,8 @@ void TorrentHandle::setTrackerLogin(const QString &username, const QString &pass
|
|||
|
||||
void TorrentHandle::renameFile(int index, const QString &name)
|
||||
{
|
||||
if (m_startupState != Started) return;
|
||||
|
||||
m_oldPath[LTFileIndex {index}].push_back(filePath(index));
|
||||
++m_renameCount;
|
||||
qDebug() << Q_FUNC_INFO << index << name;
|
||||
|
@ -1554,17 +1571,22 @@ void TorrentHandle::handleTorrentCheckedAlert(const libtorrent::torrent_checked_
|
|||
Q_UNUSED(p);
|
||||
qDebug("\"%s\" have just finished checking", qUtf8Printable(name()));
|
||||
|
||||
if (m_startupState == NotStarted) {
|
||||
if (!m_hasMissingFiles) {
|
||||
// Resume torrent because it was added in "resumed" state
|
||||
// but it's actually paused during initialization.
|
||||
m_startupState = Starting;
|
||||
resume(m_needsToStartForced);
|
||||
if (m_startupState == Preparing) {
|
||||
if (!m_pauseWhenReady) {
|
||||
if (!m_hasMissingFiles) {
|
||||
// Resume torrent because it was added in "resumed" state
|
||||
// but it's actually paused during initialization.
|
||||
m_startupState = Starting;
|
||||
resume_impl(m_needsToStartForced);
|
||||
}
|
||||
else {
|
||||
// Torrent that has missing files is paused.
|
||||
m_startupState = Started;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Torrent that has missing files is marked as "started"
|
||||
// but it remains paused.
|
||||
m_startupState = Started;
|
||||
m_pauseWhenReady = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1588,10 +1610,10 @@ void TorrentHandle::handleTorrentFinishedAlert(const libtorrent::torrent_finishe
|
|||
Q_UNUSED(p);
|
||||
qDebug("Got a torrent finished alert for \"%s\"", qUtf8Printable(name()));
|
||||
qDebug("Torrent has seed status: %s", m_hasSeedStatus ? "yes" : "no");
|
||||
m_hasMissingFiles = false;
|
||||
if (m_hasSeedStatus) return;
|
||||
|
||||
updateStatus();
|
||||
m_hasMissingFiles = false;
|
||||
m_hasSeedStatus = true;
|
||||
|
||||
adjustActualSavePath();
|
||||
|
@ -1615,9 +1637,14 @@ void TorrentHandle::handleTorrentPausedAlert(const libtorrent::torrent_paused_al
|
|||
Q_UNUSED(p);
|
||||
|
||||
if (m_startupState == Started) {
|
||||
updateStatus();
|
||||
m_speedMonitor.reset();
|
||||
m_session->handleTorrentPaused(this);
|
||||
if (!m_pauseWhenReady) {
|
||||
updateStatus();
|
||||
m_speedMonitor.reset();
|
||||
m_session->handleTorrentPaused(this);
|
||||
}
|
||||
else {
|
||||
m_pauseWhenReady = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1639,8 +1666,8 @@ void TorrentHandle::handleSaveResumeDataAlert(const libtorrent::save_resume_data
|
|||
libtorrent::entry &resumeData = useDummyResumeData ? dummyEntry : *(p->resume_data);
|
||||
if (useDummyResumeData) {
|
||||
resumeData["qBt-magnetUri"] = toMagnetUri().toStdString();
|
||||
resumeData["qBt-paused"] = isPaused();
|
||||
resumeData["qBt-forced"] = isForced();
|
||||
resumeData["paused"] = isPaused();
|
||||
resumeData["auto_managed"] = m_nativeStatus.auto_managed;
|
||||
// Both firstLastPiecePriority and sequential need 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:
|
||||
|
@ -1662,6 +1689,14 @@ void TorrentHandle::handleSaveResumeDataAlert(const libtorrent::save_resume_data
|
|||
resumeData["qBt-queuePosition"] = (nativeHandle().queue_position() + 1); // qBt starts queue at 1
|
||||
resumeData["qBt-hasRootFolder"] = m_hasRootFolder;
|
||||
|
||||
if (m_pauseWhenReady) {
|
||||
// We need to redefine these values when torrent starting/rechecking
|
||||
// in "paused" state since native values can be logically wrong
|
||||
// (torrent can be not paused and auto_managed when it is checking).
|
||||
resumeData["paused"] = true;
|
||||
resumeData["auto_managed"] = false;
|
||||
}
|
||||
|
||||
m_session->handleTorrentResumeDataReady(this, resumeData);
|
||||
}
|
||||
|
||||
|
|
|
@ -476,12 +476,15 @@ namespace BitTorrent
|
|||
|
||||
enum StartupState
|
||||
{
|
||||
NotStarted,
|
||||
Starting,
|
||||
Started
|
||||
Preparing, // torrent is preparing to start regular processing
|
||||
Starting, // torrent is prepared and starting to perform regular processing
|
||||
Started // torrent is performing regular processing
|
||||
};
|
||||
StartupState m_startupState = Preparing;
|
||||
// Handle torrent state when it starts performing some service job
|
||||
// being in Paused state so it might be unpaused internally and then paused again
|
||||
bool m_pauseWhenReady;
|
||||
|
||||
StartupState m_startupState = NotStarted;
|
||||
bool m_unchecked = false;
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue