Exemplo n.º 1
0
        /// <summary>
        /// Sets up the initial values of the downloader.
        /// </summary>
        /// <param name="savePath">The path to which to save the file.
        /// If <paramref name="useDefaultFileName"/> is <c>false</c>, this value should be a complete
        /// path, including filename. If <paramref name="useDefaultFileName"/> is <c>true</c>,
        /// this value should be the directory in which to save the file.</param>
        /// <param name="useDefaultFileName">Whether to use the file name suggested by the server.</param>
        private void Initialize(string savePath, bool useDefaultFileName)
        {
            _metadata = GetMetadata(URL);

            var strFilename = useDefaultFileName ? _metadata.SuggestedFileName : Path.GetFileName(savePath);

            strFilename = Uri.UnescapeDataString(strFilename);

            foreach (var chrInvalid in Path.GetInvalidFileNameChars())
            {
                strFilename = strFilename.Replace(chrInvalid, '_');
            }

            savePath = Path.Combine(savePath, strFilename);

            _savePath         = savePath + ".partial";
            _fileMetadataPath = savePath + ".parts";

            var metaDataPathExists = File.Exists(_fileMetadataPath);

            if (!_metadata.SupportsResume)
            {
                if (metaDataPathExists)
                {
                    File.Delete(_fileMetadataPath);
                }

                if (File.Exists(_savePath))
                {
                    File.Delete(_savePath);
                }
            }

            //get the list of ranges we have already downloaded
            var rgsRanges = new RangeSet();

            if (metaDataPathExists)
            {
                var strRanges = File.ReadAllLines(_fileMetadataPath);

                foreach (var strRange in strRanges)
                {
                    var strCleanRange = strRange.Trim().Trim('\0');

                    if (string.IsNullOrEmpty(strCleanRange))
                    {
                        continue;
                    }

                    rgsRanges.AddRange(Range.Parse(strCleanRange));
                }
            }

            _initialByteCount = rgsRanges.TotalSize;

            ResumedByteCount = rgsRanges.TotalSize / 1024;
        }
Exemplo n.º 2
0
        /// <summary>
        /// A simple consturctor that initializes the object with the given values.
        /// </summary>
        /// <param name="p_strFilePath">The path of the file to which to write. If the
        /// file does not exist, is will be created.</param>
        /// <param name="p_strFileMetadataPath">The path of the file containing the metadata
        /// describing which parts of the file are already written.</param>
        public FileWriter(string p_strFilePath, string p_strFileMetadataPath)
        {
            m_strFilePath         = p_strFilePath;
            m_strFileMetadataPath = p_strFileMetadataPath;

            if (File.Exists(p_strFileMetadataPath))
            {
                string[] strRanges = File.ReadAllLines(p_strFileMetadataPath);
                foreach (string strRange in strRanges)
                {
                    string strCleanRange = strRange.Trim().Trim('\0');
                    if (String.IsNullOrEmpty(strCleanRange))
                    {
                        continue;
                    }
                    m_rgsWrittenRanges.AddRange(Range.Parse(strCleanRange));
                }
            }

            m_thdWrite = new TrackedThread(WaitForData);
            m_thdWrite.Start();
        }
        /// <summary>
        /// Sets up the initial values of the downloader.
        /// </summary>
        /// <param name="p_strSavePath">The path to which to save the file.
        /// If <paramref name="p_booUseDefaultFileName"/> is <c>false</c>, this value should be a complete
        /// path, including filename. If <paramref name="p_booUseDefaultFileName"/> is <c>true</c>,
        /// this value should be the directory in which to save the file.</param>
        /// <param name="p_booUseDefaultFileName">Whether to use the file name suggested by the server.</param>
        private void Initialize(string p_strSavePath, bool p_booUseDefaultFileName)
        {
            m_fmdInfo = GetMetadata();

            string strFilename = p_booUseDefaultFileName ? m_fmdInfo.SuggestedFileName : Path.GetFileName(p_strSavePath);

            strFilename = Uri.UnescapeDataString(strFilename);

            foreach (char chrInvalid in Path.GetInvalidFileNameChars())
            {
                strFilename = strFilename.Replace(chrInvalid, '_');
            }
            p_strSavePath = Path.Combine(p_strSavePath, strFilename);

            m_strSavePath         = p_strSavePath + ".partial";
            m_strFileMetadataPath = p_strSavePath + ".parts";

            if (!m_fmdInfo.SupportsResume)
            {
                File.Delete(m_strFileMetadataPath);
                File.Delete(m_strSavePath);
            }

            //get the list of ranges we have already downloaded
            RangeSet rgsRanges = new RangeSet();

            if (File.Exists(m_strFileMetadataPath))
            {
                string[] strRanges = File.ReadAllLines(m_strFileMetadataPath);
                foreach (string strRange in strRanges)
                {
                    string strCleanRange = strRange.Trim().Trim('\0');
                    if (String.IsNullOrEmpty(strCleanRange))
                    {
                        continue;
                    }
                    rgsRanges.AddRange(Range.Parse(strCleanRange));
                }
            }
            m_intInitialByteCount           = rgsRanges.TotalSize;
            m_intInitialDownloadedByteCount = rgsRanges.TotalSize / 1024;
        }
Exemplo n.º 4
0
        /// <summary>
        /// Starts the file download.
        /// </summary>
        public void StartDownload()
        {
            Trace.TraceInformation($"[{URL}] Downloading.");

            if (!FileExists)
            {
                throw new FileNotFoundException("The file to download does not exist.", URL.ToString());
            }

            int intConnectionsToUse = _metadata.SupportsResume ? _maxConnections : 1;

            if (ServicePointManager.DefaultConnectionLimit < 1)
            {
                throw new Exception(string.Format("Only {0} connections can be created to the same file; {1} are wanted.", ServicePointManager.DefaultConnectionLimit, 1));
            }

            if (ServicePointManager.DefaultConnectionLimit < intConnectionsToUse)
            {
                intConnectionsToUse = ServicePointManager.DefaultConnectionLimit;
            }

            //get the list of ranges we have not already downloaded
            RangeSet rgsMissingRanges = new RangeSet();

            rgsMissingRanges.AddRange(new Range(0, _metadata.Length - 1));

            if (File.Exists(_fileMetadataPath))
            {
                string[] strRanges = File.ReadAllLines(_fileMetadataPath);
                foreach (string strRange in strRanges)
                {
                    string strCleanRange = strRange.Trim().Trim('\0');
                    if (string.IsNullOrEmpty(strCleanRange))
                    {
                        continue;
                    }
                    rgsMissingRanges.RemoveRange(Range.Parse(strCleanRange));
                }
            }
            else if (File.Exists(_savePath))
            {
                File.Delete(_savePath);
            }

            int intMinBlockSize  = (int)Math.Min((ulong)_minBlockSize, rgsMissingRanges.TotalSize);
            int intBaseBlockSize = (int)Math.Max(rgsMissingRanges.TotalSize / (ulong)intConnectionsToUse, (ulong)intMinBlockSize);

            if (intConnectionsToUse > 1)
            {
                intBaseBlockSize = Math.Min(intBaseBlockSize, MaxBlockSize);
            }

            //break the ranges into blocks to be downloaded
            foreach (Range rngNeeded in rgsMissingRanges)
            {
                //find out how many blocks will fit into the range
                int intBlockCount = (int)(rngNeeded.Size / (ulong)intBaseBlockSize);

                if (intBlockCount == 0)
                {
                    intBlockCount = 1;
                }

                //there is likely to be some remainder (there are likely a fractional number of blocks
                // in the range), so lets distrubute the remainder amongst all of the blocks
                // we do this by elarging our blocksize
                ulong intBlockSize  = (ulong)Math.Ceiling(rngNeeded.Size / (double)intBlockCount);
                ulong intBlockStart = rngNeeded.StartByte;

                for (; intBlockStart + intBlockSize < rngNeeded.EndByte; intBlockStart += intBlockSize)
                {
                    _requiredBlocks.Enqueue(new Range(intBlockStart, intBlockStart + intBlockSize - 1));
                }

                _requiredBlocks.Enqueue(new Range(intBlockStart, rngNeeded.EndByte));
            }

            _writer = new FileWriter(_savePath, _fileMetadataPath);

            _startTime = DateTime.Now;

            //spawn the downloading threads
            int intRequiredBlocks = _requiredBlocks.Count;

            lock (_downloaders)
            {
                for (int i = 0; i < (intRequiredBlocks < intConnectionsToUse ? intRequiredBlocks : intConnectionsToUse); i++)
                {
                    BlockDownloader bdrDownloader = new BlockDownloader(this, _metadata, _writer, _writeBufferSize, _userAgent);
                    bdrDownloader.FinishedDownloading += new EventHandler(Downloader_FinishedDownloading);
                    bdrDownloader.Start();

                    _downloaders.Add(bdrDownloader);
                }
            }
        }