Пример #1
0
        /// <summary> 执行下载 </summary>
        bool DownloadPackages(DoWorkEventArgs e)
        {
            Directory.CreateDirectory(Context.UpdatePackagePath);

            Trace.TraceInformation("开始下载网络更新包");

            var workerCount = Math.Max(1, Context.MultipleDownloadCount);
            var workers     = new List <WebClient>(workerCount);
            var evt         = new AutoResetEvent(false);
            var hasError    = false;

            //Ping
            if (!string.IsNullOrEmpty(Context.UpdateMeta.UpdatePingUrl))
            {
                try
                {
                    Context.CreateWebClient().UploadData(new Uri(Context.UpdateMeta.UpdatePingUrl), new byte[0]);
                }
                catch (Exception)
                {
                }
            }

            //生成下载队列
            Trace.TraceInformation("正在初始化 {0} 个WebClient", workerCount);
            for (var i = 0; i < workerCount; i++)
            {
                var client = Context.CreateWebClient();
                client.DownloadFileCompleted += (s, e) =>
                {
                    var pkg = e.UserState as Package;
                    var cnt = s as WebClient;

                    pkg.LastError = e.Error;
                    if (e.Error != null)
                    {
                        Trace.TraceWarning($"包【{pkg.Name}】下载失败:{e.Error.Message}");
                        OnPackageDownloadFailed(new PackageEventArgs(pkg));
                    }
                    else if (pkg.IsLocalFileValid != true)
                    {
                        Trace.TraceWarning($"包【{pkg.Name}】MD5校验失败", "错误");
                        pkg.LastError = new Exception("不文件哈希值不正确或文件不存在");
                        OnPackageHashMismatch(new PackageEventArgs(pkg));
                    }

                    if (pkg.LastError != null)
                    {
                        //如果出错,且重试次数在限制范围内,则重试
                        pkg.IncreaseFailureCounter();
                        if (pkg.RetryCount <= Context.MaxiumRetryDownloadCount)
                        {
                            Trace.TraceWarning($"包【{pkg.Name}】未能成功下载,正在进行第 {pkg.RetryCount} 次重试,最大重试次数为 {Context.MaxiumRetryDownloadCount}", "错误");
                            cnt.DownloadFileAsync(new Uri(pkg.SourceUri), pkg.LocalSavePath, pkg);
                            OnPackageDownloadRetried(new PackageEventArgs(pkg));
                            return;
                        }
                        //标记出错
                        hasError = true;
                    }

                    //包下载完成事件
                    pkg.IsDownloading = false;
                    pkg.IsDownloaded  = pkg.LastError == null;
                    OnPackageDownloadFinished(new PackageEventArgs(e.UserState as Package));

                    lock (Packages)
                    {
                        Trace.TraceInformation($"包【{pkg.Name}】下载操作完成:{(pkg.IsDownloaded ? "下载成功" : "下载失败")}");
                        evt.Set();
                    }
                };
                client.DownloadProgressChanged += (s, e) =>
                {
                    var pkg = e.UserState as Package;
                    pkg.DownloadedSize = e.BytesReceived;
                    pkg.Size           = e.TotalBytesToReceive > 0 ? e.TotalBytesToReceive : pkg.Size;
                    OnDownloadProgressChanged(new PackageDownloadProgressChangedEventArgs(pkg, pkg.Size,
                                                                                          pkg.DownloadedSize, e.ProgressPercentage));
                };
                workers.Add(client);
            }

            //开始处理事务
            while (!hasError)
            {
                var breakFlag = false;
                lock (Packages)
                {
                    //没有错误,则分配下个任务
                    WebClient client;
                    while ((client = workers.Find(s => !s.IsBusy)) != null)
                    {
                        var nextPkg = Packages.Find(s => !s.IsDownloading && !s.IsDownloaded);
                        if (nextPkg == null)
                        {
                            breakFlag = true;
                            break;
                        }

                        nextPkg.IsDownloading = true;
                        Trace.TraceInformation($"包【{nextPkg.Name}】开始下载");
                        OnPackageDownload(new PackageEventArgs(nextPkg));
                        Context.ResetWebClient(client);
                        client.DownloadFileAsync(new Uri(Context.GetUpdatePackageFullUrl(nextPkg.Name)), nextPkg.LocalSavePath, nextPkg);
                    }
                }
                if (breakFlag)
                {
                    break;
                }
                evt.WaitOne();
                Trace.TraceInformation("线程同步事件已收到");
            }
            //不管任何原因中止下载,到这里时都需要等待所有客户端中止
            while (true)
            {
                //出错了,那么对所有的客户端发出中止命令。这里不需要判断是否忙碌。
                if (hasError)
                {
                    Trace.TraceWarning("出现错误,正在取消所有包的下载队列");
                    workers.ForEach(s => s.CancelAsync());
                }
                lock (Packages)
                {
                    Trace.TraceInformation("等待下载队列完成操作");
                    if (workers.FindIndex(s => s.IsBusy) == -1)
                    {
                        break;
                    }
                }
                evt.WaitOne();
            }
            Trace.TraceInformation("完成下载网络更新包");

            var errorPkgs = Packages.FindAll(m => m.LastError != null);

            if (errorPkgs.Count > 0)
            {
                throw new PackageDownloadException(errorPkgs.ToArray());
            }

            return(!hasError);
        }