Ejemplo n.º 1
0
        /// <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));
        }