public void DownloadTorrent(string torrentPath, string saveDir, int port) { var torrent = _torrentFactory.GetTorrentFromFile(torrentPath); var fileName = Path.GetFileNameWithoutExtension(torrent.Info.Name); string fullSaveDir = Path.Combine(saveDir, fileName); lock (_pieceLock) { foreach (var pieceIndex in Enumerable.Range(0, torrent.Info.PieceHashes.Count)) { var pieceLength = torrent.Info.PieceLength; if (pieceIndex == torrent.Info.PieceHashes.Count - 1) //Last piece is odd length { var tempPieceLength = torrent.Info.Length % pieceLength; if (tempPieceLength != 0) { pieceLength = tempPieceLength; } } var piece = new TorrentPiece(pieceIndex, pieceLength, fullSaveDir, torrent.Info.PieceHashes[pieceIndex]); _pieces.Add(piece); } } var tracker = new Tracker(_httpClientHelper, _bencodeParser, _trackerResponseFactory, _peerId, port); //Technically needs a factory for testing var peerConnector = new PeerConnector(_peerEventDataFactory, _tcpSocketHelper, _peerId, torrent.Info); //Technically needs a factory for testing while (GetNonCompletedPieces().Any()) { try { ConnectNewPeersIfNeeded(peerConnector, tracker, torrent); var neededPieces = GetAvailableForDownloadPieces(); foreach (var peer in peerConnector.Peers) { var neededPiecesIds = neededPieces .Select(p => p.PieceIndex) .ToList(); var nullablePieceIndex = peer.RetrievePieceIndexIfAny(neededPiecesIds); if (nullablePieceIndex == null) { if (peer.AmInterested) { peer.SendInterest(false); } continue; } if (!peer.AmInterested) { peer.SendInterest(true); continue; } if (!peer.PeerChocking && !peer.AmWaitingForPiece) { var pieceIndex = nullablePieceIndex.Value; var neededPiece = neededPieces.Find(p => p.PieceIndex == pieceIndex); neededPieces.Remove(neededPiece); lock (_pieceLock) { _pendingPieces.Add(neededPiece, peer); var block = neededPiece.GetNextBlock(); peer.RequestPiece((uint)pieceIndex, block.Offset, block.Length); } continue; } //peer.SendKeepAlive(); } FreeBlockedPieces(peerConnector); } //TODO: Bad practice catch (Exception ex) { } } var fullFilePath = Path.Combine(fullSaveDir, torrent.Info.Name); CombinePiecesIntoFile(fullFilePath); CleanupResources(peerConnector); IsDownloadCompleted = true; }
private bool IsCompleteOrPending(TorrentPiece piece) { return(piece.Complete || PendingPieces.TryGetValue(piece, out var tempPeer)); }