diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index 95c7ac4be..cae03ba83 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -493,7 +493,6 @@ namespace BitTorrent void categoryOptionsChanged(const QString &categoryName); void fullDiskError(Torrent *torrent, const QString &msg); void IPFilterParsed(bool error, int ruleCount); - void loadTorrentFailed(const QString &error); void metadataDownloaded(const TorrentInfo &info); void restored(); void paused(); diff --git a/src/base/bittorrent/sessionimpl.cpp b/src/base/bittorrent/sessionimpl.cpp index bc3fca77e..1cbd1b3c6 100644 --- a/src/base/bittorrent/sessionimpl.cpp +++ b/src/base/bittorrent/sessionimpl.cpp @@ -30,6 +30,7 @@ #include "sessionimpl.h" #include +#include #include #include #include @@ -315,6 +316,44 @@ namespace break; } } + +#ifdef QBT_USES_LIBTORRENT2 + template + concept HasInfoHashMember = requires (T t) { { t.info_hashes } -> std::convertible_to; }; + + template + concept HasInfoHashMemberFn = requires (T t) { { t.info_hashes() } -> std::convertible_to; }; + + template + InfoHash getInfoHash(const T &t) { return t.info_hashes; } + + template + InfoHash getInfoHash(const T &t) { return t.info_hashes(); } + + InfoHash getInfoHash(const lt::add_torrent_params &addTorrentParams) + { + const bool hasMetadata = (addTorrentParams.ti && addTorrentParams.ti->is_valid()); + return hasMetadata ? getInfoHash(*addTorrentParams.ti) : InfoHash(addTorrentParams.info_hashes); + } + #else + template + concept HasInfoHashMember = requires (T t) { { t.info_hash } -> std::convertible_to; }; + + template + concept HasInfoHashMemberFn = requires (T t) { { t.info_hash() } -> std::convertible_to; }; + + template + InfoHash getInfoHash(const T &t) { return t.info_hash; } + + template + InfoHash getInfoHash(const T &t) { return t.info_hash(); } + + InfoHash getInfoHash(const lt::add_torrent_params &addTorrentParams) + { + const bool hasMetadata = (addTorrentParams.ti && addTorrentParams.ti->is_valid()); + return hasMetadata ? getInfoHash(*addTorrentParams.ti) : InfoHash(addTorrentParams.info_hash); + } + #endif } struct BitTorrent::SessionImpl::ResumeSessionContext final : public QObject @@ -1443,10 +1482,8 @@ void SessionImpl::processNextResumeData(ResumeSessionContext *context) LoadTorrentParams resumeData = *loadResumeDataResult; bool needStore = false; + const InfoHash infoHash = getInfoHash(resumeData.ltAddTorrentParams); #ifdef QBT_USES_LIBTORRENT2 - const InfoHash infoHash {(resumeData.ltAddTorrentParams.ti - ? resumeData.ltAddTorrentParams.ti->info_hashes() - : resumeData.ltAddTorrentParams.info_hashes)}; const bool isHybrid = infoHash.isHybrid(); const auto torrentIDv2 = TorrentID::fromInfoHash(infoHash); const auto torrentIDv1 = TorrentID::fromSHA1Hash(infoHash.v1()); @@ -1494,9 +1531,6 @@ void SessionImpl::processNextResumeData(ResumeSessionContext *context) return; } #else - const lt::sha1_hash infoHash = (resumeData.ltAddTorrentParams.ti - ? resumeData.ltAddTorrentParams.ti->info_hash() - : resumeData.ltAddTorrentParams.info_hash); if (torrentID != TorrentID::fromInfoHash(infoHash)) { LogMsg(tr("Failed to resume torrent: inconsistent torrent ID is detected. Torrent: \"%1\"") @@ -1586,16 +1620,23 @@ void SessionImpl::processNextResumeData(ResumeSessionContext *context) #endif qDebug() << "Starting up torrent" << torrentID.toString() << "..."; - m_loadingTorrents.insert(torrentID, resumeData); -#ifdef QBT_USES_LIBTORRENT2 - if (infoHash.isHybrid()) - { - // this allows to know the being added hybrid torrent by its v1 info hash - // without having yet another mapping table - m_hybridTorrentsByAltID.insert(torrentIDv1, nullptr); - } -#endif m_nativeSession->async_add_torrent(resumeData.ltAddTorrentParams); + m_addTorrentAlertHandlers.enqueue([this, resumeData = std::move(resumeData)](const lt::add_torrent_alert *alert) + { + if (alert->error) + { + const QString msg = QString::fromStdString(alert->message()); + LogMsg(tr("Failed to load torrent. Reason: \"%1\"").arg(msg), Log::WARNING); + } + else + { + Torrent *torrent = createTorrent(alert->handle, resumeData); + m_loadedTorrents.append(torrent); + + LogMsg(tr("Restored torrent. Torrent: \"%1\"").arg(torrent->name())); + } + }); + ++context->processingResumeDataCount; } @@ -2398,7 +2439,7 @@ Torrent *SessionImpl::getTorrent(const TorrentID &id) const Torrent *SessionImpl::findTorrent(const InfoHash &infoHash) const { const auto id = TorrentID::fromInfoHash(infoHash); - if (Torrent *torrent = m_torrents.value(id); torrent) + if (Torrent *torrent = m_torrents.value(id)) return torrent; if (!infoHash.isHybrid()) @@ -2515,7 +2556,7 @@ bool SessionImpl::cancelDownloadMetadata(const TorrentID &id) return true; #ifdef QBT_USES_LIBTORRENT2 - const InfoHash infoHash {nativeHandle.info_hashes()}; + const InfoHash infoHash = getInfoHash(nativeHandle); if (infoHash.isHybrid()) { // if magnet link was hybrid initially then it is indexed also by v1 info hash @@ -2744,14 +2785,6 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr // alternative ID can be useful to find existing torrent in case if hybrid torrent was added by v1 info hash const auto altID = (infoHash.isHybrid() ? TorrentID::fromSHA1Hash(infoHash.v1()) : TorrentID()); - // We should not add the torrent if it is already - // processed or is pending to add to session - if (m_loadingTorrents.contains(id) || (infoHash.isHybrid() && m_loadingTorrents.contains(altID))) - { - emit addTorrentFailed(infoHash, {AddTorrentError::DuplicateTorrent, tr("Duplicate torrent")}); - return false; - } - if (Torrent *torrent = findTorrent(infoHash)) { // a duplicate torrent is being added @@ -2869,14 +2902,7 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr } if (!loadTorrentParams.hasFinishedStatus) - { needFindIncompleteFiles = true; - } - else - { - for (int index = 0; index < filePaths.size(); ++index) - p.renamed_files[nativeIndexes[index]] = filePaths.at(index).toString().toStdString(); - } const int internalFilesCount = torrentInfo.nativeInfo()->files().num_files(); // including .pad files // Use qBittorrent default priority rather than libtorrent's (4) @@ -2896,8 +2922,6 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr loadTorrentParams.name = QString::fromStdString(p.name); } - p.save_path = actualSavePath.toString().toStdString(); - if (isAddTrackersEnabled() && !(hasMetadata && p.ti->priv())) { const auto maxTierIter = std::max_element(p.tracker_tiers.cbegin(), p.tracker_tiers.cend()); @@ -2968,38 +2992,64 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr p.storage = customStorageConstructor; #endif - m_loadingTorrents.insert(id, loadTorrentParams); - if (infoHash.isHybrid()) - m_hybridTorrentsByAltID.insert(altID, nullptr); - - if (needFindIncompleteFiles) + const auto resolveFileNames = [&, this] { - const Path actualDownloadPath = useAutoTMM + if (!needFindIncompleteFiles) + return QtFuture::makeReadyValueFuture(FileSearchResult {.savePath = actualSavePath, .fileNames = filePaths}); + + const Path actualDownloadPath = loadTorrentParams.useAutoTMM ? categoryDownloadPath(loadTorrentParams.category) : loadTorrentParams.downloadPath; - findIncompleteFiles(actualSavePath, actualDownloadPath, filePaths).then(this - , [this, id](const FileSearchResult &result) + return findIncompleteFiles(actualSavePath, actualDownloadPath, filePaths); + }; + + resolveFileNames().then(this, [this, id, loadTorrentParams = std::move(loadTorrentParams)](const FileSearchResult &result) mutable + { + lt::add_torrent_params &p = loadTorrentParams.ltAddTorrentParams; + + p.save_path = result.savePath.toString().toStdString(); + if (p.ti) { - const auto loadingTorrentsIter = m_loadingTorrents.find(id); - Q_ASSERT(loadingTorrentsIter != m_loadingTorrents.end()); - if (loadingTorrentsIter == m_loadingTorrents.end()) [[unlikely]] - return; - - LoadTorrentParams ¶ms = loadingTorrentsIter.value(); - lt::add_torrent_params &p = params.ltAddTorrentParams; - - p.save_path = result.savePath.toString().toStdString(); const TorrentInfo torrentInfo {*p.ti}; const auto nativeIndexes = torrentInfo.nativeIndexes(); for (int i = 0; i < result.fileNames.size(); ++i) p.renamed_files[nativeIndexes[i]] = result.fileNames[i].toString().toStdString(); + } - m_nativeSession->async_add_torrent(p); - }); - } - else - { m_nativeSession->async_add_torrent(p); - } + m_addTorrentAlertHandlers.enqueue([this, loadTorrentParams = std::move(loadTorrentParams)](const lt::add_torrent_alert *alert) + { + if (alert->error) + { + const QString msg = QString::fromStdString(alert->message()); + LogMsg(tr("Failed to add torrent. Reason: \"%1\"").arg(msg), Log::WARNING); + + const InfoHash infoHash = getInfoHash(alert->params); + const AddTorrentError::Kind errorKind = (alert->error == lt::errors::duplicate_torrent) + ? AddTorrentError::DuplicateTorrent : AddTorrentError::Other; + emit addTorrentFailed(infoHash, {errorKind, msg}); + } + else + { + if (loadTorrentParams.addToQueueTop) + alert->handle.queue_position_top(); + + TorrentImpl *torrent = createTorrent(alert->handle, loadTorrentParams); + m_loadedTorrents.append(torrent); + + torrent->requestResumeData(lt::torrent_handle::save_info_dict); + + LogMsg(tr("Added new torrent. Torrent: \"%1\"").arg(torrent->name())); + emit torrentAdded(torrent); + + // The following is useless for newly added magnet + if (torrent->hasMetadata()) + { + if (!torrentExportDirectory().isEmpty()) + exportTorrentFile(torrent, torrentExportDirectory()); + } + } + }); + }); return true; } @@ -3153,6 +3203,33 @@ bool SessionImpl::downloadMetadata(const TorrentDescriptor &torrentDescr) // Adding torrent to libtorrent session m_nativeSession->async_add_torrent(p); m_downloadedMetadata.insert(id, {}); + m_addTorrentAlertHandlers.enqueue([this](const lt::add_torrent_alert *alert) + { + if (alert->error) + { + const QString msg = QString::fromStdString(alert->message()); + LogMsg(tr("Failed to download torrent metadata. Reason: \"%1\"").arg(msg), Log::WARNING); + + m_downloadedMetadata.remove(getInfoHash(alert->params).toTorrentID()); + } + else + { + const InfoHash infoHash = getInfoHash(alert->handle); + const auto torrentID = TorrentID::fromInfoHash(infoHash); + + if (const auto downloadedMetadataIter = m_downloadedMetadata.find(torrentID) + ; downloadedMetadataIter != m_downloadedMetadata.end()) + { + downloadedMetadataIter.value() = alert->handle; + if (infoHash.isHybrid()) + { + // index hybrid magnet links by both v1 and v2 info hashes + const auto altID = TorrentID::fromSHA1Hash(infoHash.v1()); + m_downloadedMetadata[altID] = alert->handle; + } + } + } + }); return true; } @@ -5201,8 +5278,6 @@ bool SessionImpl::isKnownTorrent(const InfoHash &infoHash) const // in case if hybrid torrent was added by v1 info hash const auto altID = (isHybrid ? TorrentID::fromSHA1Hash(infoHash.v1()) : TorrentID()); - if (m_loadingTorrents.contains(id) || (isHybrid && m_loadingTorrents.contains(altID))) - return true; if (m_downloadedMetadata.contains(id) || (isHybrid && m_downloadedMetadata.contains(altID))) return true; return findTorrent(infoHash); @@ -5415,15 +5490,25 @@ bool SessionImpl::addMoveTorrentStorageJob(TorrentImpl *torrent, const Path &new return true; } +lt::torrent_handle SessionImpl::reloadTorrent(const lt::torrent_handle ¤tHandle, lt::add_torrent_params params) +{ + m_nativeSession->remove_torrent(currentHandle, lt::session::delete_partfile); + + auto *const extensionData = new ExtensionData; + params.userdata = LTClientData(extensionData); +#ifndef QBT_USES_LIBTORRENT2 + params.storage = customStorageConstructor; +#endif + + // libtorrent will post an add_torrent_alert anyway, so we have to add an empty handler to ignore it. + m_addTorrentAlertHandlers.enqueue({}); + return m_nativeSession->add_torrent(std::move(params)); +} + void SessionImpl::moveTorrentStorage(const MoveStorageJob &job) const { -#ifdef QBT_USES_LIBTORRENT2 - const auto id = TorrentID::fromInfoHash(job.torrentHandle.info_hashes()); -#else - const auto id = TorrentID::fromInfoHash(job.torrentHandle.info_hash()); -#endif - const TorrentImpl *torrent = m_torrents.value(id); - const QString torrentName = (torrent ? torrent->name() : id.toString()); + const TorrentImpl *torrent = getTorrent(job.torrentHandle); + const QString torrentName = (torrent ? torrent->name() : getInfoHash(job.torrentHandle).toTorrentID().toString()); LogMsg(tr("Start moving torrent. Torrent: \"%1\". Destination: \"%2\"").arg(torrentName, job.path.toString())); job.torrentHandle.move_storage(job.path.toString().toStdString(), toNative(job.mode)); @@ -5443,7 +5528,7 @@ void SessionImpl::handleMoveTorrentStorageJobFinished(const Path &newPath) const bool torrentHasOutstandingJob = (iter != m_moveStorageQueue.cend()); - TorrentImpl *torrent = m_torrents.value(finishedJob.torrentHandle.info_hash()); + TorrentImpl *torrent = getTorrent(finishedJob.torrentHandle); if (torrent) { torrent->handleMoveStorageJobFinished(newPath, finishedJob.context, torrentHasOutstandingJob); @@ -5451,8 +5536,9 @@ void SessionImpl::handleMoveTorrentStorageJobFinished(const Path &newPath) else if (!torrentHasOutstandingJob) { // Last job is completed for torrent that being removing, so actually remove it - const lt::torrent_handle nativeHandle {finishedJob.torrentHandle}; - const RemovingTorrentData &removingTorrentData = m_removingTorrents[nativeHandle.info_hash()]; + const lt::torrent_handle nativeHandle = finishedJob.torrentHandle; + const TorrentID torrentID = getInfoHash(nativeHandle).toTorrentID(); + const RemovingTorrentData &removingTorrentData = m_removingTorrents[torrentID]; if (removingTorrentData.removeOption == TorrentRemoveOption::KeepContent) m_nativeSession->remove_torrent(nativeHandle, lt::session::delete_partfile); } @@ -5743,72 +5829,12 @@ void SessionImpl::handleAddTorrentAlert(const lt::add_torrent_alert *alert) { ++m_receivedAddTorrentAlertsCount; - if (alert->error) - { - const QString msg = QString::fromStdString(alert->message()); - LogMsg(tr("Failed to load torrent. Reason: \"%1\"").arg(msg), Log::WARNING); - emit loadTorrentFailed(msg); - - const lt::add_torrent_params ¶ms = alert->params; - const bool hasMetadata = (params.ti && params.ti->is_valid()); - -#ifdef QBT_USES_LIBTORRENT2 - const InfoHash infoHash {(hasMetadata ? params.ti->info_hashes() : params.info_hashes)}; - if (infoHash.isHybrid()) - m_hybridTorrentsByAltID.remove(TorrentID::fromSHA1Hash(infoHash.v1())); -#else - const InfoHash infoHash {(hasMetadata ? params.ti->info_hash() : params.info_hash)}; -#endif - if (const auto loadingTorrentsIter = m_loadingTorrents.constFind(TorrentID::fromInfoHash(infoHash)) - ; loadingTorrentsIter != m_loadingTorrents.cend()) - { - const AddTorrentError::Kind errorKind = (alert->error == lt::errors::duplicate_torrent) - ? AddTorrentError::DuplicateTorrent : AddTorrentError::Other; - emit addTorrentFailed(infoHash, {errorKind, msg}); - m_loadingTorrents.erase(loadingTorrentsIter); - } - else if (const auto downloadedMetadataIter = m_downloadedMetadata.constFind(TorrentID::fromInfoHash(infoHash)) - ; downloadedMetadataIter != m_downloadedMetadata.cend()) - { - m_downloadedMetadata.erase(downloadedMetadataIter); - if (infoHash.isHybrid()) - { - // index hybrid magnet links by both v1 and v2 info hashes - const auto altID = TorrentID::fromSHA1Hash(infoHash.v1()); - m_downloadedMetadata.remove(altID); - } - } - + Q_ASSERT(!m_addTorrentAlertHandlers.isEmpty()); + if (m_addTorrentAlertHandlers.isEmpty()) [[unlikely]] return; - } -#ifdef QBT_USES_LIBTORRENT2 - const InfoHash infoHash {alert->handle.info_hashes()}; -#else - const InfoHash infoHash {alert->handle.info_hash()}; -#endif - const auto torrentID = TorrentID::fromInfoHash(infoHash); - - if (const auto loadingTorrentsIter = m_loadingTorrents.constFind(torrentID) - ; loadingTorrentsIter != m_loadingTorrents.cend()) - { - const LoadTorrentParams params = loadingTorrentsIter.value(); - m_loadingTorrents.erase(loadingTorrentsIter); - - Torrent *torrent = createTorrent(alert->handle, params); - m_loadedTorrents.append(torrent); - } - else if (const auto downloadedMetadataIter = m_downloadedMetadata.find(torrentID) - ; downloadedMetadataIter != m_downloadedMetadata.end()) - { - downloadedMetadataIter.value() = alert->handle; - if (infoHash.isHybrid()) - { - // index hybrid magnet links by both v1 and v2 info hashes - const auto altID = TorrentID::fromSHA1Hash(infoHash.v1()); - m_downloadedMetadata[altID] = alert->handle; - } - } + if (const AddTorrentAlertHandler handleAlert = m_addTorrentAlertHandlers.dequeue()) + handleAlert(alert); } void SessionImpl::handleAlert(const lt::alert *alert) @@ -5930,12 +5956,11 @@ void SessionImpl::dispatchTorrentAlert(const lt::torrent_alert *alert) --m_numResumeData; } - const TorrentID torrentID {alert->handle.info_hash()}; - TorrentImpl *torrent = m_torrents.value(torrentID); + TorrentImpl *torrent = getTorrent(alert->handle); #ifdef QBT_USES_LIBTORRENT2 if (!torrent && (alert->type() == lt::metadata_received_alert::alert_type)) { - const InfoHash infoHash {alert->handle.info_hashes()}; + const InfoHash infoHash = getInfoHash(alert->handle); if (infoHash.isHybrid()) torrent = m_torrents.value(TorrentID::fromSHA1Hash(infoHash.v1())); } @@ -5957,42 +5982,17 @@ void SessionImpl::dispatchTorrentAlert(const lt::torrent_alert *alert) TorrentImpl *SessionImpl::createTorrent(const lt::torrent_handle &nativeHandle, const LoadTorrentParams ¶ms) { - auto *const torrent = new TorrentImpl(this, m_nativeSession, nativeHandle, params); + auto *const torrent = new TorrentImpl(this, nativeHandle, params); m_torrents.insert(torrent->id(), torrent); if (const InfoHash infoHash = torrent->infoHash(); infoHash.isHybrid()) m_hybridTorrentsByAltID.insert(TorrentID::fromSHA1Hash(infoHash.v1()), torrent); - if (isRestored()) - { - if (params.addToQueueTop) - nativeHandle.queue_position_top(); - - torrent->requestResumeData(lt::torrent_handle::save_info_dict); - - // The following is useless for newly added magnet - if (torrent->hasMetadata()) - { - if (!torrentExportDirectory().isEmpty()) - exportTorrentFile(torrent, torrentExportDirectory()); - } - } - if (((torrent->ratioLimit() >= 0) || (torrent->seedingTimeLimit() >= 0)) && !m_seedingLimitTimer->isActive()) { m_seedingLimitTimer->start(); } - if (!isRestored()) - { - LogMsg(tr("Restored torrent. Torrent: \"%1\"").arg(torrent->name())); - } - else - { - LogMsg(tr("Added new torrent. Torrent: \"%1\"").arg(torrent->name())); - emit torrentAdded(torrent); - } - // Torrent could have error just after adding to libtorrent if (torrent->hasError()) LogMsg(tr("Torrent errored. Torrent: \"%1\". Error: \"%2\"").arg(torrent->name(), torrent->error()), Log::WARNING); @@ -6000,6 +6000,11 @@ TorrentImpl *SessionImpl::createTorrent(const lt::torrent_handle &nativeHandle, return torrent; } +TorrentImpl *SessionImpl::getTorrent(const lt::torrent_handle &nativeHandle) const +{ + return m_torrents.value(getInfoHash(nativeHandle).toTorrentID()); +} + void SessionImpl::handleTorrentRemovedAlert(const lt::torrent_removed_alert */*alert*/) { // We cannot consider `torrent_removed_alert` as a starting point for removing content, @@ -6009,34 +6014,19 @@ void SessionImpl::handleTorrentRemovedAlert(const lt::torrent_removed_alert */*a void SessionImpl::handleTorrentDeletedAlert(const lt::torrent_deleted_alert *alert) { -#ifdef QBT_USES_LIBTORRENT2 - const auto torrentID = TorrentID::fromInfoHash(alert->info_hashes); -#else - const auto torrentID = TorrentID::fromInfoHash(alert->info_hash); -#endif - handleRemovedTorrent(torrentID); + handleRemovedTorrent(getInfoHash(*alert).toTorrentID()); } void SessionImpl::handleTorrentDeleteFailedAlert(const lt::torrent_delete_failed_alert *alert) { -#ifdef QBT_USES_LIBTORRENT2 - const auto torrentID = TorrentID::fromInfoHash(alert->info_hashes); -#else - const auto torrentID = TorrentID::fromInfoHash(alert->info_hash); -#endif + const TorrentID torrentID = getInfoHash(*alert).toTorrentID(); const auto errorMessage = alert->error ? Utils::String::fromLocal8Bit(alert->error.message()) : QString(); handleRemovedTorrent(torrentID, errorMessage); } void SessionImpl::handleTorrentNeedCertAlert(const lt::torrent_need_cert_alert *alert) { -#ifdef QBT_USES_LIBTORRENT2 - const InfoHash infoHash {alert->handle.info_hashes()}; -#else - const InfoHash infoHash {alert->handle.info_hash()}; -#endif - const auto torrentID = TorrentID::fromInfoHash(infoHash); - + const TorrentID torrentID = getInfoHash(alert->handle).toTorrentID(); TorrentImpl *const torrent = m_torrents.value(torrentID); if (!torrent) [[unlikely]] return; @@ -6050,7 +6040,8 @@ void SessionImpl::handleTorrentNeedCertAlert(const lt::torrent_need_cert_alert * void SessionImpl::handleMetadataReceivedAlert(const lt::metadata_received_alert *alert) { - const TorrentID torrentID {alert->handle.info_hash()}; + const InfoHash infoHash = getInfoHash(alert->handle); + const TorrentID torrentID = infoHash.toTorrentID(); bool found = false; if (const auto iter = m_downloadedMetadata.constFind(torrentID); iter != m_downloadedMetadata.cend()) @@ -6059,7 +6050,6 @@ void SessionImpl::handleMetadataReceivedAlert(const lt::metadata_received_alert m_downloadedMetadata.erase(iter); } #ifdef QBT_USES_LIBTORRENT2 - const InfoHash infoHash {alert->handle.info_hashes()}; if (infoHash.isHybrid()) { const auto altID = TorrentID::fromSHA1Hash(infoHash.v1()); @@ -6081,7 +6071,7 @@ void SessionImpl::handleMetadataReceivedAlert(const lt::metadata_received_alert void SessionImpl::handleFileErrorAlert(const lt::file_error_alert *alert) { - TorrentImpl *const torrent = m_torrents.value(alert->handle.info_hash()); + TorrentImpl *const torrent = getTorrent(alert->handle); if (!torrent) return; @@ -6152,7 +6142,7 @@ void SessionImpl::handlePeerBanAlert(const lt::peer_ban_alert *alert) void SessionImpl::handleUrlSeedAlert(const lt::url_seed_alert *alert) { - const TorrentImpl *torrent = m_torrents.value(alert->handle.info_hash()); + const TorrentImpl *torrent = getTorrent(alert->handle); if (!torrent) return; @@ -6331,14 +6321,8 @@ void SessionImpl::handleStorageMovedAlert(const lt::storage_moved_alert *alert) const Path newPath {QString::fromUtf8(alert->storage_path())}; Q_ASSERT(newPath == currentJob.path); -#ifdef QBT_USES_LIBTORRENT2 - const auto id = TorrentID::fromInfoHash(currentJob.torrentHandle.info_hashes()); -#else - const auto id = TorrentID::fromInfoHash(currentJob.torrentHandle.info_hash()); -#endif - - TorrentImpl *torrent = m_torrents.value(id); - const QString torrentName = (torrent ? torrent->name() : id.toString()); + TorrentImpl *torrent = getTorrent(currentJob.torrentHandle); + const QString torrentName = (torrent ? torrent->name() : getInfoHash(currentJob.torrentHandle).toTorrentID().toString()); LogMsg(tr("Moved torrent successfully. Torrent: \"%1\". Destination: \"%2\"").arg(torrentName, newPath.toString())); handleMoveTorrentStorageJobFinished(newPath); @@ -6351,14 +6335,8 @@ void SessionImpl::handleStorageMovedFailedAlert(const lt::storage_moved_failed_a const MoveStorageJob ¤tJob = m_moveStorageQueue.constFirst(); Q_ASSERT(currentJob.torrentHandle == alert->handle); -#ifdef QBT_USES_LIBTORRENT2 - const auto id = TorrentID::fromInfoHash(currentJob.torrentHandle.info_hashes()); -#else - const auto id = TorrentID::fromInfoHash(currentJob.torrentHandle.info_hash()); -#endif - - TorrentImpl *torrent = m_torrents.value(id); - const QString torrentName = (torrent ? torrent->name() : id.toString()); + TorrentImpl *torrent = getTorrent(currentJob.torrentHandle); + const QString torrentName = (torrent ? torrent->name() : getInfoHash(currentJob.torrentHandle).toTorrentID().toString()); const Path currentLocation = (torrent ? torrent->actualStorageLocation() : Path(alert->handle.status(lt::torrent_handle::query_save_path).save_path)); const QString errorMessage = QString::fromStdString(alert->message()); @@ -6375,12 +6353,7 @@ void SessionImpl::handleStateUpdateAlert(const lt::state_update_alert *alert) for (const lt::torrent_status &status : alert->status) { -#ifdef QBT_USES_LIBTORRENT2 - const auto id = TorrentID::fromInfoHash(status.info_hashes); -#else - const auto id = TorrentID::fromInfoHash(status.info_hash); -#endif - TorrentImpl *const torrent = m_torrents.value(id); + TorrentImpl *const torrent = getTorrent(status.handle); if (!torrent) continue; @@ -6424,7 +6397,7 @@ void SessionImpl::handleI2PAlert(const lt::i2p_alert *alert) const void SessionImpl::handleTrackerAlert(const lt::tracker_alert *alert) { - TorrentImpl *torrent = m_torrents.value(alert->handle.info_hash()); + TorrentImpl *torrent = getTorrent(alert->handle); if (!torrent) return; @@ -6450,8 +6423,9 @@ void SessionImpl::handleTrackerAlert(const lt::tracker_alert *alert) #ifdef QBT_USES_LIBTORRENT2 void SessionImpl::handleTorrentConflictAlert(const lt::torrent_conflict_alert *alert) { - const auto torrentIDv1 = TorrentID::fromSHA1Hash(alert->metadata->info_hashes().v1); - const auto torrentIDv2 = TorrentID::fromSHA256Hash(alert->metadata->info_hashes().v2); + const InfoHash infoHash = getInfoHash(*alert->metadata); + const auto torrentIDv1 = TorrentID::fromSHA1Hash(infoHash.v1()); + const auto torrentIDv2 = TorrentID::fromSHA256Hash(infoHash.v2()); TorrentImpl *torrent1 = m_torrents.value(torrentIDv1); TorrentImpl *torrent2 = m_torrents.value(torrentIDv2); if (torrent2) diff --git a/src/base/bittorrent/sessionimpl.h b/src/base/bittorrent/sessionimpl.h index e878cf4a6..aec79c4ea 100644 --- a/src/base/bittorrent/sessionimpl.h +++ b/src/base/bittorrent/sessionimpl.h @@ -30,6 +30,7 @@ #pragma once #include +#include #include #include @@ -44,6 +45,7 @@ #include #include #include +#include #include #include @@ -482,6 +484,8 @@ namespace BitTorrent bool addMoveTorrentStorageJob(TorrentImpl *torrent, const Path &newPath, MoveStorageMode mode, MoveStorageContext context); + lt::torrent_handle reloadTorrent(const lt::torrent_handle ¤tHandle, lt::add_torrent_params params); + QFuture findIncompleteFiles(const Path &savePath, const Path &downloadPath, const PathList &filePaths = {}) const; void enablePortMapping(); @@ -606,6 +610,7 @@ namespace BitTorrent #endif TorrentImpl *createTorrent(const lt::torrent_handle &nativeHandle, const LoadTorrentParams ¶ms); + TorrentImpl *getTorrent(const lt::torrent_handle &nativeHandle) const; void saveResumeData(); void saveTorrentsQueue(); @@ -812,11 +817,13 @@ namespace BitTorrent FileSearcher *m_fileSearcher = nullptr; TorrentContentRemover *m_torrentContentRemover = nullptr; + using AddTorrentAlertHandler = std::function; + QQueue m_addTorrentAlertHandlers; + QHash m_downloadedMetadata; QHash m_torrents; QHash m_hybridTorrentsByAltID; - QHash m_loadingTorrents; QHash m_removingTorrents; QHash m_changedTorrentIDs; QMap m_categories; diff --git a/src/base/bittorrent/torrentimpl.cpp b/src/base/bittorrent/torrentimpl.cpp index 03ca62eca..97921246c 100644 --- a/src/base/bittorrent/torrentimpl.cpp +++ b/src/base/bittorrent/torrentimpl.cpp @@ -290,11 +290,9 @@ namespace // TorrentImpl -TorrentImpl::TorrentImpl(SessionImpl *session, lt::session *nativeSession - , const lt::torrent_handle &nativeHandle, const LoadTorrentParams ¶ms) +TorrentImpl::TorrentImpl(SessionImpl *session, const lt::torrent_handle &nativeHandle, const LoadTorrentParams ¶ms) : Torrent(session) , m_session(session) - , m_nativeSession(nativeSession) , m_nativeHandle(nativeHandle) #ifdef QBT_USES_LIBTORRENT2 , m_infoHash(m_nativeHandle.info_hashes()) @@ -1837,16 +1835,6 @@ void TorrentImpl::reload() { try { - m_completedFiles.fill(false); - m_filesProgress.fill(0); - m_pieces.fill(false); - m_nativeStatus.pieces.clear_all(); - m_nativeStatus.num_pieces = 0; - - const auto queuePos = m_nativeHandle.queue_position(); - - m_nativeSession->remove_torrent(m_nativeHandle, lt::session::delete_partfile); - lt::add_torrent_params p = m_ltAddTorrentParams; p.flags |= lt::torrent_flags::update_subscribe | lt::torrent_flags::override_trackers @@ -1866,19 +1854,21 @@ void TorrentImpl::reload() p.flags &= ~(lt::torrent_flags::auto_managed | lt::torrent_flags::paused); } - auto *const extensionData = new ExtensionData; - p.userdata = LTClientData(extensionData); -#ifndef QBT_USES_LIBTORRENT2 - p.storage = customStorageConstructor; -#endif - m_nativeHandle = m_nativeSession->add_torrent(p); + const auto queuePos = m_nativeHandle.queue_position(); - m_nativeStatus = extensionData->status; + m_nativeHandle = m_session->reloadTorrent(m_nativeHandle, std::move(p)); + m_nativeStatus = static_cast(m_nativeHandle.userdata())->status; if (queuePos >= lt::queue_position_t {}) m_nativeHandle.queue_position_set(queuePos); m_nativeStatus.queue_position = queuePos; + m_completedFiles.fill(false); + m_filesProgress.fill(0); + m_pieces.fill(false); + m_nativeStatus.pieces.clear_all(); + m_nativeStatus.num_pieces = 0; + updateState(); } catch (const lt::system_error &err) diff --git a/src/base/bittorrent/torrentimpl.h b/src/base/bittorrent/torrentimpl.h index 87137cd73..1875ba11c 100644 --- a/src/base/bittorrent/torrentimpl.h +++ b/src/base/bittorrent/torrentimpl.h @@ -94,8 +94,7 @@ namespace BitTorrent Q_DISABLE_COPY_MOVE(TorrentImpl) public: - TorrentImpl(SessionImpl *session, lt::session *nativeSession - , const lt::torrent_handle &nativeHandle, const LoadTorrentParams ¶ms); + TorrentImpl(SessionImpl *session, const lt::torrent_handle &nativeHandle, const LoadTorrentParams ¶ms); ~TorrentImpl() override; bool isValid() const; @@ -325,7 +324,6 @@ namespace BitTorrent QFuture> invokeAsync(Func &&func) const; SessionImpl *const m_session = nullptr; - lt::session *m_nativeSession = nullptr; lt::torrent_handle m_nativeHandle; mutable lt::torrent_status m_nativeStatus; TorrentState m_state = TorrentState::Unknown;