diff --git a/libi2pd_client/Torrents.cpp b/libi2pd_client/Torrents.cpp index e29687cb..a5e6ea7c 100644 --- a/libi2pd_client/Torrents.cpp +++ b/libi2pd_client/Torrents.cpp @@ -305,10 +305,13 @@ namespace torrents size_t Torrent::ParsePieces (std::string_view buf) { auto [hashes, len] = ExtractByteString (buf); - while (!hashes.empty ()) + size_t totalLen = 0; + while (!hashes.empty () && totalLen < m_Length) { - m_Pieces.emplace_back (m_PieceLength, (const uint8_t *)hashes.substr (0, SHA_DIGEST_LENGTH).data ()); + auto l = (totalLen + m_PieceLength <= m_Length) ? m_PieceLength : m_Length - totalLen; + m_Pieces.emplace_back (l, (const uint8_t *)hashes.substr (0, SHA_DIGEST_LENGTH).data ()); hashes = hashes.substr (SHA_DIGEST_LENGTH); + totalLen += l; } return len; } @@ -419,9 +422,9 @@ namespace torrents return { ret, empty }; } - void Torrent::ApplyBitfield (const std::vector& bitfield) + bool Torrent::ApplyBitfield (const std::vector& bitfield) { - m_IsComplete = true; + bool complete = true; size_t numPieces = m_Pieces.size (); size_t idx = 0; for (size_t i = 0; i < bitfield.size (); i++) @@ -433,12 +436,13 @@ namespace torrents if (bitfield[i] & bit) m_Pieces[idx].Complete (); else - m_IsComplete = false; + complete = false; bit >>= 1; idx++; } if (idx >= numPieces) break; } + return complete; } std::tuple Torrent::GetNextBlockToRequest (std::shared_ptr conn) @@ -469,15 +473,16 @@ namespace torrents return { 0, 0, 0 }; } - void Torrent::UpdateStatus (uint64_t ts) + bool Torrent::UpdateStatus (uint64_t ts) { - //bool complete = true; + bool complete = true; for (auto& it: m_Pieces) { - // if (!it.IsComplete ()) complete = false; - if (ts > it.GetLastActivityTimestamp () + PIECE_INACTIVITY_TIMEOUT) // piece was incactive recently + if (!it.IsComplete ()) complete = false; + if (ts > it.GetLastActivityTimestamp () + PIECE_INACTIVITY_TIMEOUT) // piece was inactive recently it.Reset (); } + return complete; } void Torrent::SetComplete () @@ -1163,7 +1168,8 @@ namespace torrents rs.seekg(0, std::ios::beg); std::vector bitfield(l); rs.read((char *)bitfield.data (), l); - torrent->ApplyBitfield (bitfield); + if (torrent->ApplyBitfield (bitfield)) + CompleteTorrent (torrent); } } } @@ -1178,6 +1184,24 @@ namespace torrents LogPrint (eLogError, "Torrents: Can't open file ", path); } + void TorrentsTunnel::CompleteTorrent (std::shared_ptr torrent) + { + boost::asio::post (GetDiskIOService (), [torrent, + filePath = GetTorrentFilePath (torrent->GetName ()), + partFilePath = GetTorrentFilePath (torrent->GetName () + ".part"), + resumeFilePath = GetTorrentFilePath (torrent->GetName () + ".resume")]() + { + if (i2p::fs::Rename (partFilePath, filePath)) + { + torrent->SetComplete (); + i2p::fs::Remove (resumeFilePath); + LogPrint (eLogInfo, "Torrents: Download complete ", filePath); + } + else + LogPrint (eLogError, "Torrents: Can't rename ", partFilePath); + }); + } + std::shared_ptr TorrentsTunnel::FindTorrent (const Torrent::InfoHash& infoHash) const { auto it = m_Torrents.find (infoHash); @@ -1396,7 +1420,8 @@ namespace torrents { auto ts = i2p::util::GetMonotonicSeconds (); for (auto it: m_Torrents) - it.second->UpdateStatus (ts); + if (!it.second->IsComplete () && it.second->UpdateStatus (ts)) + CompleteTorrent (it.second); ScheduleStatusUpdate (); } } diff --git a/libi2pd_client/Torrents.h b/libi2pd_client/Torrents.h index efde83bf..df8ad955 100644 --- a/libi2pd_client/Torrents.h +++ b/libi2pd_client/Torrents.h @@ -142,10 +142,10 @@ namespace torrents size_t GetNumPieces () const { return m_Pieces.size (); } Piece& GetPiece (int index) { return m_Pieces[index]; } std::pair, bool> CreateBitfield () const; // (bitfield, empty) - void ApplyBitfield (const std::vector& bitfield); + bool ApplyBitfield (const std::vector& bitfield); // return true if complete const std::unordered_set& GetPeers () const { return m_Peers; } std::tuple GetNextBlockToRequest (std::shared_ptr conn); // return (index, offset, len) - void UpdateStatus (uint64_t ts); + bool UpdateStatus (uint64_t ts); // return true if complete uint64_t GetNextTrackerRequestTime () const { return m_NextTrackerRequestTime; } void SetNextTrackerRequestTime (uint64_t ts) { m_NextTrackerRequestTime = ts; } @@ -280,6 +280,7 @@ namespace torrents void Accept (); void ReadTorrentFile (const std::string& path); + void CompleteTorrent (std::shared_ptr torrent); void RequestTracker (std::shared_ptr torrent); void TrackerRequestSent (const boost::beast::error_code& ecode, size_t bytes_transferred, std::shared_ptr httpStream, std::shared_ptr torrent,