Пример #1
0
        private void DownloadFileAsync(string path, string url, string auth, string referer, HashType hashType, byte[] correctHash, DownloadFileEndCallback downloadEndCallback)
        {
            ConnectionManager connectionManager   = ConnectionManager.GetInstance(url);
            string            connectionGroupName = connectionManager.ObtainConnectionGroupName();

            int tryNumber = 0;

            byte[] prevHash = null;
            long?  prevDownloadedFileSize = null;

            void TryDownload()
            {
                void EndTryDownload(DownloadResult result)
                {
                    connectionManager.ReleaseConnectionGroupName(connectionGroupName);
                    downloadEndCallback(result);
                }

                tryNumber++;
                if (IsStopping || tryNumber > _maxDownloadTries)
                {
                    EndTryDownload(DownloadResult.RetryLater);
                    return;
                }

                long                downloadID             = (long)(General.BytesTo64BitXor(Guid.NewGuid().ToByteArray()) & 0x7FFFFFFFFFFFFFFFUL);
                FileStream          fileStream             = null;
                long?               totalFileSize          = null;
                long                downloadedFileSize     = 0;
                bool                createdFile            = false;
                HashGeneratorStream hashStream             = null;
                bool                removedDownloadAborter = false;

                void Cleanup(bool successful)
                {
                    if (fileStream != null)
                    {
                        try { fileStream.Close(); } catch { }
                    }
                    if (hashStream != null)
                    {
                        try { hashStream.Close(); } catch { }
                    }
                    if (!successful && createdFile)
                    {
                        try { File.Delete(path); } catch { }
                    }
                    lock (_downloadAborters) {
                        _downloadAborters.Remove(downloadID);
                        removedDownloadAborter = true;
                    }
                }

                Action abortDownload = General.DownloadAsync(url, auth, referer, connectionGroupName, null,
                                                             (response) => {
                    fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read);
                    if (response.ContentLength != -1)
                    {
                        totalFileSize = response.ContentLength;
                        fileStream.SetLength(totalFileSize.Value);
                    }
                    createdFile = true;
                    if (hashType != HashType.None)
                    {
                        hashStream = new HashGeneratorStream(hashType);
                    }
                    OnDownloadStart(new DownloadStartEventArgs(downloadID, url, tryNumber, totalFileSize));
                },
                                                             (data, dataLength) => {
                    fileStream.Write(data, 0, dataLength);
                    if (hashStream != null)
                    {
                        hashStream.Write(data, 0, dataLength);
                    }
                    downloadedFileSize += dataLength;
                    OnDownloadProgress(new DownloadProgressEventArgs(downloadID, downloadedFileSize));
                },
                                                             () => {
                    byte[] hash = (hashType != HashType.None) ? hashStream.GetDataHash() : null;
                    if (totalFileSize != null && downloadedFileSize != totalFileSize)
                    {
                        fileStream.SetLength(downloadedFileSize);
                    }
                    bool incorrectHash = hashType != HashType.None && !General.ArraysAreEqual(hash, correctHash) &&
                                         (prevHash == null || !General.ArraysAreEqual(hash, prevHash));
                    bool incompleteDownload = totalFileSize != null && downloadedFileSize != totalFileSize &&
                                              (prevDownloadedFileSize == null || downloadedFileSize != prevDownloadedFileSize);
                    if (incorrectHash || incompleteDownload)
                    {
                        // Corrupt download, retry
                        prevHash = hash;
                        prevDownloadedFileSize = downloadedFileSize;
                        throw new Exception("Download is corrupt.");
                    }
                    Cleanup(true);
                    OnDownloadEnd(new DownloadEndEventArgs(downloadID, downloadedFileSize, true));
                    EndTryDownload(DownloadResult.Completed);
                },
                                                             (ex) => {
                    Cleanup(false);
                    OnDownloadEnd(new DownloadEndEventArgs(downloadID, downloadedFileSize, false));
                    if (ex is DirectoryNotFoundException || ex is UnauthorizedAccessException)
                    {
                        // Fatal IO error, stop
                        Stop(StopReason.IOError);
                        EndTryDownload(DownloadResult.Skipped);
                    }
                    else if (ex is Http404Exception)
                    {
                        // Fatal problem with this file, skip
                        EndTryDownload(DownloadResult.Skipped);
                    }
                    else
                    {
                        // Other error, retry
                        connectionGroupName = connectionManager.SwapForFreshConnection(connectionGroupName, url);
                        TryDownload();
                    }
                });

                lock (_downloadAborters) {
                    if (!removedDownloadAborter)
                    {
                        _downloadAborters[downloadID] = abortDownload;
                    }
                }
            }

            TryDownload();
        }
Пример #2
0
        private void DownloadPageAsync(string path, string url, string auth, DateTime?cacheLastModifiedTime, DownloadPageEndCallback downloadEndCallback)
        {
            ConnectionManager connectionManager   = ConnectionManager.GetInstance(url);
            string            connectionGroupName = connectionManager.ObtainConnectionGroupName();

            string backupPath             = path + ".bak";
            int    tryNumber              = 0;
            long?  prevDownloadedFileSize = null;

            void TryDownload()
            {
                string   httpContentType  = null;
                DateTime?lastModifiedTime = null;
                Encoding encoding         = null;
                string   content          = null;

                void EndTryDownload(DownloadResult result)
                {
                    connectionManager.ReleaseConnectionGroupName(connectionGroupName);
                    downloadEndCallback(result, content, lastModifiedTime, encoding);
                }

                tryNumber++;
                if (IsStopping || tryNumber > _maxDownloadTries)
                {
                    EndTryDownload(DownloadResult.RetryLater);
                    return;
                }

                long         downloadID             = (long)(General.BytesTo64BitXor(Guid.NewGuid().ToByteArray()) & 0x7FFFFFFFFFFFFFFFUL);
                FileStream   fileStream             = null;
                long?        totalFileSize          = null;
                long         downloadedFileSize     = 0;
                bool         createdFile            = false;
                MemoryStream memoryStream           = null;
                bool         removedDownloadAborter = false;

                void Cleanup(bool successful)
                {
                    if (fileStream != null)
                    {
                        try { fileStream.Close(); } catch { }
                    }
                    if (memoryStream != null)
                    {
                        try { memoryStream.Close(); } catch { }
                    }
                    if (!successful && createdFile)
                    {
                        try { File.Delete(path); } catch { }
                        if (File.Exists(backupPath))
                        {
                            try { File.Move(backupPath, path); } catch { }
                        }
                    }
                    lock (_downloadAborters) {
                        _downloadAborters.Remove(downloadID);
                        removedDownloadAborter = true;
                    }
                }

                Action abortDownload = General.DownloadAsync(url, auth, null, connectionGroupName, cacheLastModifiedTime,
                                                             (response) => {
                    if (File.Exists(path))
                    {
                        if (File.Exists(backupPath))
                        {
                            try { File.Delete(backupPath); } catch { }
                        }
                        try { File.Move(path, backupPath); } catch { }
                    }
                    fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read);
                    if (response.ContentLength != -1)
                    {
                        totalFileSize = response.ContentLength;
                        fileStream.SetLength(totalFileSize.Value);
                    }
                    createdFile      = true;
                    memoryStream     = new MemoryStream();
                    httpContentType  = response.ContentType;
                    lastModifiedTime = General.GetResponseLastModifiedTime(response);
                    OnDownloadStart(new DownloadStartEventArgs(downloadID, url, tryNumber, totalFileSize));
                },
                                                             (data, dataLength) => {
                    fileStream.Write(data, 0, dataLength);
                    memoryStream.Write(data, 0, dataLength);
                    downloadedFileSize += dataLength;
                    OnDownloadProgress(new DownloadProgressEventArgs(downloadID, downloadedFileSize));
                },
                                                             () => {
                    byte[] pageBytes = memoryStream.ToArray();
                    if (totalFileSize != null && downloadedFileSize != totalFileSize)
                    {
                        fileStream.SetLength(downloadedFileSize);
                    }
                    bool incompleteDownload = totalFileSize != null && downloadedFileSize != totalFileSize &&
                                              (prevDownloadedFileSize == null || downloadedFileSize != prevDownloadedFileSize);
                    if (incompleteDownload)
                    {
                        // Corrupt download, retry
                        prevDownloadedFileSize = downloadedFileSize;
                        throw new Exception("Download is corrupt.");
                    }
                    Cleanup(true);
                    OnDownloadEnd(new DownloadEndEventArgs(downloadID, downloadedFileSize, true));
                    encoding = General.DetectHtmlEncoding(pageBytes, httpContentType);
                    content  = encoding.GetString(pageBytes);
                    EndTryDownload(DownloadResult.Completed);
                },
                                                             (ex) => {
                    Cleanup(false);
                    OnDownloadEnd(new DownloadEndEventArgs(downloadID, downloadedFileSize, false));
                    if (ex is Http304Exception)
                    {
                        // Page not modified, skip
                        EndTryDownload(DownloadResult.Skipped);
                    }
                    else if (ex is Http404Exception)
                    {
                        // Page not found, stop
                        Stop(StopReason.PageNotFound);
                        EndTryDownload(DownloadResult.Skipped);
                    }
                    else if (ex is IOException || ex is UnauthorizedAccessException)
                    {
                        // Fatal IO error, stop
                        Stop(StopReason.IOError);
                        EndTryDownload(DownloadResult.Skipped);
                    }
                    else
                    {
                        // Other error, retry
                        connectionGroupName = connectionManager.SwapForFreshConnection(connectionGroupName, url);
                        TryDownload();
                    }
                });

                lock (_downloadAborters) {
                    if (!removedDownloadAborter)
                    {
                        _downloadAborters[downloadID] = abortDownload;
                    }
                }
            }

            TryDownload();
        }