/// <summary> /// Gets the data from the given dht name. /// </summary> /// <param name="nameSpace">The name space.</param> /// <param name="name">The name.</param> /// <param name="waitHandle">The wait handle.</param> /// <param name="downloadPath">The download path.</param> /// <returns>Torrent bytes</returns> /// <exception cref="DictionaryKeyNotFoundException">Torrent at the given key is /// invalid.</exception> /// <remarks>MonoTorrent library provides easy conversion from bytes to /// Torrent object but not vise versa so we return bytes.</remarks> byte[] GetData(string nameSpace, string name, out string downloadPath, bool peek) { ManualResetEvent waitHandle = new ManualResetEvent(false); byte[] torrentDhtKey = ServiceUtil.GetDictKeyBytes(nameSpace, name); downloadPath = _bittorrentCache.GetPathOfItemInDownloads(nameSpace, name); // @TODO Check integrity of the data -- How do we know the download is complete? // A possbile solution. Use the name <name.part> and change it to <name> after // download completes. byte[] torrentBytes; if (!CacheRegistry.IsInCacheRegistry(nameSpace, name)) { try { var torrentSavePath = _bittorrentCache.GetTorrentFilePath(nameSpace, name); torrentBytes = _torrentHelper.ReadOrDownloadTorrent(nameSpace, name, _dictProxy); var torrent = Torrent.Load(torrentBytes); if (!peek) { GetDataInternal(torrentDhtKey, torrent, downloadPath, waitHandle); // Wait until downloading finishes waitHandle.WaitOne(); // Download completed. CacheRegistry.AddPathToRegistry(downloadPath, true); } else { // If we are only peeking, we don't add it to the registry. } } catch (TorrentException ex) { throw new DictionaryKeyNotFoundException(string.Format( "Torrent at key {0} (UrlBase64) is invalid.", UrlBase64.Encode(torrentDhtKey)), ex); } } else { torrentBytes = _torrentHelper.ReadOrDownloadTorrent(nameSpace, name, _dictProxy); var torrent = Torrent.Load(torrentBytes); if (!_clientEngine.Contains(torrent)) { // This is the case where the manager start seeding data when it boots up. GetDataInternal(torrentDhtKey, torrent, downloadPath, null); } else { // If the data is already there and the client engine is busily downloading or // seeding, we don't need to do it again. return(torrentBytes); } } return(torrentBytes); }
/// <summary> /// Gets a block of data. /// </summary> /// <param name="nameSpace">The name space.</param> /// <param name="name">The name.</param> /// <param name="offset">The offset.</param> /// <param name="bytesToRead">The bytes to read.</param> /// <param name="waitHandle">The wait handle.</param> /// <returns></returns> public byte[] GetDataBlock(string nameSpace, string name, long offset, int bytesToRead) { // Download whole torrent. var wholeTorrentBytes = _torrentHelper.ReadOrDownloadTorrent( nameSpace, name, _dhtProxy); Torrent wholeTorrent = Torrent.Load(wholeTorrentBytes); // Find out the piece to download. int pieceIndex = (int)Math.Floor(offset / (double)wholeTorrent.PieceLength); var pieceName = MakePieceDataName(name, pieceIndex); int offsetInPiece = (int)(offset % wholeTorrent.PieceLength); // If the piece is already downloaded, we just return it. string piecePath = _bittorrentCache.GetPathOfItemInDownloads( nameSpace, pieceName); if (IOUtil.FileOrDirectoryExists(piecePath)) { return(IOUtil.Read(piecePath, offsetInPiece, bytesToRead)); } var pieceTorrentBytes = DownloadPieceTorrent(nameSpace, name, wholeTorrent, pieceIndex); // Write it to filesys so that the ordinary torrent downloading can pick it up. var pieceTorrentPath = _torrentHelper.WriteTorrentFile(nameSpace, pieceName, pieceTorrentBytes); Logger.WriteLineIf(LogLevel.Verbose, _log_props, string.Format( "Piece torrent downloaded and written to path {0}", pieceTorrentPath)); // Download as a regular torrent. string pieceDownloadPath; _manager.GetData(nameSpace, pieceName, out pieceDownloadPath); return(IOUtil.Read(pieceDownloadPath, offsetInPiece, bytesToRead)); }