From 65d56297fdc35e5190a9cf23db2a9756a2dc72a3 Mon Sep 17 00:00:00 2001 From: CJKmkp <2564608840@qq.com> Date: Tue, 22 Jul 2025 18:25:04 +0800 Subject: [PATCH] =?UTF-8?q?improve:=E8=87=AA=E5=8A=A8=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Ink Canvas/Helpers/AutoUpdateHelper.cs | 381 +++++------------- Ink Canvas/Windows/HasNewUpdateWindow.xaml.cs | 121 +----- .../Windows/HistoryRollbackWindow.xaml.cs | 128 ++---- 3 files changed, 143 insertions(+), 487 deletions(-) diff --git a/Ink Canvas/Helpers/AutoUpdateHelper.cs b/Ink Canvas/Helpers/AutoUpdateHelper.cs index 4ca9de9d..1b35cd53 100644 --- a/Ink Canvas/Helpers/AutoUpdateHelper.cs +++ b/Ink Canvas/Helpers/AutoUpdateHelper.cs @@ -10,6 +10,7 @@ using System.Linq; using System.Windows.Controls; using System.Text; using System.Collections.Generic; +using System.Threading; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -514,323 +515,125 @@ namespace Ink_Canvas.Helpers } // 下载文件的具体实现 - private static async Task DownloadFile(string fileUrl, string destinationPath, Action progressCallback = null) + public static async Task DownloadFile(string fileUrl, string destinationPath, Action progressCallback = null) { - LogHelper.WriteLogToFile($"AutoUpdate | 正在尝试下载: {fileUrl}"); + LogHelper.WriteLogToFile($"AutoUpdate | 正在尝试多线程下载: {fileUrl}"); int maxRetry = 3; - int retryCount = 0; - while (retryCount < maxRetry) + int threadCount = 32; // 提升线程数至32 + // 1. 获取文件总大小 + long totalSize = await GetContentLength(fileUrl); + if (totalSize <= 0) { - try + progressCallback?.Invoke(0, "无法获取文件大小,取消下载"); + return false; + } + int blockSize = (int)Math.Ceiling((double)totalSize / threadCount); + long[] blockDownloaded = new long[threadCount]; + var tasks = new List(); + CancellationTokenSource cts = new CancellationTokenSource(); + for (int i = 0; i < threadCount; i++) + { + int blockIndex = i; + long start = blockIndex * blockSize; + long end = Math.Min(start + blockSize - 1, totalSize - 1); + string tempPath = destinationPath + $".part{blockIndex}"; + tasks.Add(Task.Run(async () => { - // 检测是否为Windows 7 - var osVersion = Environment.OSVersion; - bool isWindows7 = osVersion.Version.Major == 6 && osVersion.Version.Minor == 1; - if (isWindows7) + int retryCount = 0; + while (retryCount < maxRetry) { - // Windows 7使用特殊配置 - using (var handler = new HttpClientHandler()) + try { - try + using (var client = new HttpClient()) { - // 配置HttpClientHandler以支持Windows 7 - handler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true; - - using (HttpClient client = new HttpClient(handler)) + var req = new HttpRequestMessage(HttpMethod.Get, fileUrl); + req.Headers.Range = new System.Net.Http.Headers.RangeHeaderValue(start, end); + using (var resp = await client.SendAsync(req, HttpCompletionOption.ResponseHeadersRead, cts.Token)) { - client.Timeout = TimeSpan.FromMinutes(5); - client.DefaultRequestHeaders.Add("User-Agent", "ICC-CE Auto Updater"); - - LogHelper.WriteLogToFile($"AutoUpdate | 开始下载: {fileUrl}"); - - string tempFilePath = destinationPath + ".tmp"; - - string directory = Path.GetDirectoryName(destinationPath); - if (!Directory.Exists(directory)) - { - Directory.CreateDirectory(directory); - } - - var downloadTask = client.GetAsync(fileUrl, HttpCompletionOption.ResponseHeadersRead); - var initialTimeoutTask = Task.Delay(RequestTimeout); - - var completedTask = await Task.WhenAny(downloadTask, initialTimeoutTask); - if (completedTask == initialTimeoutTask) - { - LogHelper.WriteLogToFile($"AutoUpdate | 初始连接超时", LogHelper.LogType.Error); - return false; - } - - HttpResponseMessage response = await downloadTask; - LogHelper.WriteLogToFile($"AutoUpdate | HTTP响应状态: {response.StatusCode}"); - response.EnsureSuccessStatusCode(); - - long? totalBytes = response.Content.Headers.ContentLength; - LogHelper.WriteLogToFile($"AutoUpdate | 文件大小: {(totalBytes.HasValue ? (totalBytes.Value / 1024.0 / 1024.0).ToString("F2") + " MB" : "未知")}"); - - using (var fileStream = new FileStream(tempFilePath, FileMode.Create, FileAccess.Write, FileShare.None)) - { - using (var downloadStream = await response.Content.ReadAsStreamAsync()) - { - byte[] buffer = new byte[8192]; - long totalBytesRead = 0; - int bytesRead; - DateTime lastProgressUpdate = DateTime.Now; - - var downloadTimeoutTask = Task.Delay(TimeSpan.FromSeconds(60)); - var readTask = Task.Run(async () => { - while ((bytesRead = await downloadStream.ReadAsync(buffer, 0, buffer.Length)) > 0) - { - await fileStream.WriteAsync(buffer, 0, bytesRead); - totalBytesRead += bytesRead; - - if ((DateTime.Now - lastProgressUpdate).TotalSeconds >= 5) - { - if (totalBytes.HasValue) - { - double percentage = (double)totalBytesRead / totalBytes.Value * 100; - LogHelper.WriteLogToFile($"AutoUpdate | 下载进度: {percentage:F1}% ({(totalBytesRead / 1024.0 / 1024.0):F2} MB / {(totalBytes.Value / 1024.0 / 1024.0):F2} MB)"); - progressCallback?.Invoke(percentage, $"下载中: {percentage:F1}%"); - } - else - { - LogHelper.WriteLogToFile($"AutoUpdate | 已下载: {(totalBytesRead / 1024.0 / 1024.0):F2} MB"); - progressCallback?.Invoke(0, $"已下载: {(totalBytesRead / 1024.0 / 1024.0):F2} MB"); - } - lastProgressUpdate = DateTime.Now; - downloadTimeoutTask = Task.Delay(TimeSpan.FromSeconds(60)); - } - } - return true; - }); - - if (await Task.WhenAny(readTask, downloadTimeoutTask) == downloadTimeoutTask) - { - LogHelper.WriteLogToFile($"AutoUpdate | 下载超时(60秒无数据传输)", LogHelper.LogType.Error); - return false; - } - - bool downloadCompleted = await readTask; - - if (downloadCompleted) - { - LogHelper.WriteLogToFile($"AutoUpdate | 下载完成: {(totalBytesRead / 1024.0 / 1024.0):F2} MB"); - } - } - } - - if (File.Exists(tempFilePath)) - { - if (File.Exists(destinationPath)) - { - File.Delete(destinationPath); - } - - File.Move(tempFilePath, destinationPath); - LogHelper.WriteLogToFile($"AutoUpdate | 文件保存到: {destinationPath}"); - return true; - } - - return false; - } - } - catch (HttpRequestException ex) - { - LogHelper.WriteLogToFile($"AutoUpdate | HTTP请求错误: {ex.Message}", LogHelper.LogType.Error); - } - catch (TaskCanceledException ex) - { - LogHelper.WriteLogToFile($"AutoUpdate | 下载超时: {ex.Message}", LogHelper.LogType.Error); - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"AutoUpdate | 下载文件时出错: {ex.Message}", LogHelper.LogType.Error); - if (ex.InnerException != null) - { - LogHelper.WriteLogToFile($"AutoUpdate | 内部异常: {ex.InnerException.Message}", LogHelper.LogType.Error); - } - } - - try - { - string tempFilePath = destinationPath + ".tmp"; - if (File.Exists(tempFilePath)) - { - File.Delete(tempFilePath); - } - } - catch { } - - return false; - } - } - else - { - // 其他Windows版本使用标准配置 - using (HttpClient client = new HttpClient()) - { - try - { - client.Timeout = TimeSpan.FromMinutes(5); - client.DefaultRequestHeaders.Add("User-Agent", "ICC-CE Auto Updater"); - - LogHelper.WriteLogToFile($"AutoUpdate | 开始下载: {fileUrl}"); - - string tempFilePath = destinationPath + ".tmp"; - - string directory = Path.GetDirectoryName(destinationPath); - if (!Directory.Exists(directory)) - { - Directory.CreateDirectory(directory); - } - - var downloadTask = client.GetAsync(fileUrl, HttpCompletionOption.ResponseHeadersRead); - var initialTimeoutTask = Task.Delay(RequestTimeout); - - var completedTask = await Task.WhenAny(downloadTask, initialTimeoutTask); - if (completedTask == initialTimeoutTask) - { - LogHelper.WriteLogToFile($"AutoUpdate | 初始连接超时", LogHelper.LogType.Error); - return false; - } - - HttpResponseMessage response = await downloadTask; - LogHelper.WriteLogToFile($"AutoUpdate | HTTP响应状态: {response.StatusCode}"); - response.EnsureSuccessStatusCode(); - - long? totalBytes = response.Content.Headers.ContentLength; - LogHelper.WriteLogToFile($"AutoUpdate | 文件大小: {(totalBytes.HasValue ? (totalBytes.Value / 1024.0 / 1024.0).ToString("F2") + " MB" : "未知")}"); - - using (var fileStream = new FileStream(tempFilePath, FileMode.Create, FileAccess.Write, FileShare.None)) - { - using (var downloadStream = await response.Content.ReadAsStreamAsync()) + resp.EnsureSuccessStatusCode(); + using (var fs = new FileStream(tempPath, FileMode.Create, FileAccess.Write, FileShare.None)) { + var stream = await resp.Content.ReadAsStreamAsync(); byte[] buffer = new byte[8192]; - long totalBytesRead = 0; - int bytesRead; - DateTime lastProgressUpdate = DateTime.Now; - - var downloadTimeoutTask = Task.Delay(TimeSpan.FromSeconds(60)); - var readTask = Task.Run(async () => { - while ((bytesRead = await downloadStream.ReadAsync(buffer, 0, buffer.Length)) > 0) - { - await fileStream.WriteAsync(buffer, 0, bytesRead); - totalBytesRead += bytesRead; - - if ((DateTime.Now - lastProgressUpdate).TotalSeconds >= 5) - { - if (totalBytes.HasValue) - { - double percentage = (double)totalBytesRead / totalBytes.Value * 100; - LogHelper.WriteLogToFile($"AutoUpdate | 下载进度: {percentage:F1}% ({(totalBytesRead / 1024.0 / 1024.0):F2} MB / {(totalBytes.Value / 1024.0 / 1024.0):F2} MB)"); - progressCallback?.Invoke(percentage, $"下载中: {percentage:F1}%"); - } - else - { - LogHelper.WriteLogToFile($"AutoUpdate | 已下载: {(totalBytesRead / 1024.0 / 1024.0):F2} MB"); - progressCallback?.Invoke(0, $"已下载: {(totalBytesRead / 1024.0 / 1024.0):F2} MB"); - } - lastProgressUpdate = DateTime.Now; - downloadTimeoutTask = Task.Delay(TimeSpan.FromSeconds(60)); - } - } - return true; - }); - - if (await Task.WhenAny(readTask, downloadTimeoutTask) == downloadTimeoutTask) + int read; + while ((read = await stream.ReadAsync(buffer, 0, buffer.Length, cts.Token)) > 0) { - LogHelper.WriteLogToFile($"AutoUpdate | 下载超时(60秒无数据传输)", LogHelper.LogType.Error); - return false; - } - - bool downloadCompleted = await readTask; - - if (downloadCompleted) - { - LogHelper.WriteLogToFile($"AutoUpdate | 下载完成: {(totalBytesRead / 1024.0 / 1024.0):F2} MB"); + await fs.WriteAsync(buffer, 0, read, cts.Token); + blockDownloaded[blockIndex] += read; + // 合并所有块进度 + long totalDownloaded = blockDownloaded.Sum(); + double percent = (double)totalDownloaded / totalSize * 100; + progressCallback?.Invoke(percent, $"多线程下载中: {percent:F1}%"); } } } - - if (File.Exists(tempFilePath)) - { - if (File.Exists(destinationPath)) - { - File.Delete(destinationPath); - } - - File.Move(tempFilePath, destinationPath); - LogHelper.WriteLogToFile($"AutoUpdate | 文件保存到: {destinationPath}"); - return true; - } - - return false; } - catch (HttpRequestException ex) + break; // 成功则退出重试 + } + catch (Exception ex) when (ex is HttpRequestException || ex is IOException) + { + retryCount++; + if (retryCount >= maxRetry) { - LogHelper.WriteLogToFile($"AutoUpdate | HTTP请求错误: {ex.Message}", LogHelper.LogType.Error); + LogHelper.WriteLogToFile($"AutoUpdate | 分块{blockIndex}下载失败,已重试{retryCount}次: {ex.Message}", LogHelper.LogType.Error); + progressCallback?.Invoke(0, $"分块{blockIndex}下载失败,已重试{retryCount}次: {ex.Message}"); + cts.Cancel(); + break; } - catch (TaskCanceledException ex) + else { - LogHelper.WriteLogToFile($"AutoUpdate | 下载超时: {ex.Message}", LogHelper.LogType.Error); + LogHelper.WriteLogToFile($"AutoUpdate | 分块{blockIndex}网络异常,{15 * retryCount}s后第{retryCount}次重试: {ex.Message}", LogHelper.LogType.Warning); + progressCallback?.Invoke(0, $"分块{blockIndex}网络异常,{15 * retryCount}s后第{retryCount}次重试..."); + await Task.Delay(15000); } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"AutoUpdate | 下载文件时出错: {ex.Message}", LogHelper.LogType.Error); - if (ex.InnerException != null) - { - LogHelper.WriteLogToFile($"AutoUpdate | 内部异常: {ex.InnerException.Message}", LogHelper.LogType.Error); - } - } - - try - { - string tempFilePath = destinationPath + ".tmp"; - if (File.Exists(tempFilePath)) - { - File.Delete(tempFilePath); - } - } - catch { } - - return false; } } - } - catch (HttpRequestException ex) + })); + } + await Task.WhenAll(tasks); + if (cts.IsCancellationRequested) + { + progressCallback?.Invoke(0, "多线程下载失败"); + // 清理分块文件 + for (int i = 0; i < threadCount; i++) { - retryCount++; - if (retryCount >= maxRetry) - { - LogHelper.WriteLogToFile($"AutoUpdate | 下载失败,已重试{retryCount}次: {ex.Message}", LogHelper.LogType.Error); - progressCallback?.Invoke(0, $"下载失败,已重试{retryCount}次: {ex.Message}"); - return false; - } - else - { - LogHelper.WriteLogToFile($"AutoUpdate | 网络异常,{15 * retryCount}s后第{retryCount}次重试: {ex.Message}", LogHelper.LogType.Warning); - progressCallback?.Invoke(0, $"网络异常,{15 * retryCount}s后第{retryCount}次重试..."); - await Task.Delay(15000); - } + string tempPath = destinationPath + $".part{i}"; + if (File.Exists(tempPath)) File.Delete(tempPath); } - catch (IOException ex) + return false; + } + // 3. 合并所有块 + using (var output = new FileStream(destinationPath, FileMode.Create, FileAccess.Write, FileShare.None)) + { + for (int i = 0; i < threadCount; i++) { - retryCount++; - if (retryCount >= maxRetry) + string tempPath = destinationPath + $".part{i}"; + using (var input = new FileStream(tempPath, FileMode.Open, FileAccess.Read)) { - LogHelper.WriteLogToFile($"AutoUpdate | IO异常,已重试{retryCount}次: {ex.Message}", LogHelper.LogType.Error); - progressCallback?.Invoke(0, $"IO异常,已重试{retryCount}次: {ex.Message}"); - return false; - } - else - { - LogHelper.WriteLogToFile($"AutoUpdate | IO异常,{15 * retryCount}s后第{retryCount}次重试: {ex.Message}", LogHelper.LogType.Warning); - progressCallback?.Invoke(0, $"IO异常,{15 * retryCount}s后第{retryCount}次重试..."); - await Task.Delay(15000); + await input.CopyToAsync(output); } + File.Delete(tempPath); } } - return false; + progressCallback?.Invoke(100, "多线程下载完成"); + return true; + } + + // 获取文件总大小 + private static async Task GetContentLength(string fileUrl) + { + try + { + using (var client = new HttpClient()) + { + var req = new HttpRequestMessage(HttpMethod.Head, fileUrl); + var resp = await client.SendAsync(req); + if (resp.IsSuccessStatusCode && resp.Content.Headers.ContentLength.HasValue) + return resp.Content.Headers.ContentLength.Value; + } + } + catch { } + return -1; } // 保存下载状态 diff --git a/Ink Canvas/Windows/HasNewUpdateWindow.xaml.cs b/Ink Canvas/Windows/HasNewUpdateWindow.xaml.cs index 67972f77..50a188da 100644 --- a/Ink Canvas/Windows/HasNewUpdateWindow.xaml.cs +++ b/Ink Canvas/Windows/HasNewUpdateWindow.xaml.cs @@ -156,6 +156,11 @@ namespace Ink_Canvas DownloadProgressText.Text = text; }); }); + if (downloadSuccess) + { + // 下载完成后自动安装 + await DownloadAndInstallVersion(NewVersion, null, CancellationToken.None); + } } catch (Exception ex) { @@ -321,114 +326,22 @@ namespace Ink_Canvas } } + // 多线程分块下载并自动安装 private async Task DownloadAndInstallVersion(string version, string downloadUrl, CancellationToken token) { - LogHelper.WriteLogToFile($"AutoUpdate | 开始下载版本: {version}, url: {downloadUrl}"); - string updatesFolderPath = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "AutoUpdate"); - if (!Directory.Exists(updatesFolderPath)) - Directory.CreateDirectory(updatesFolderPath); - string zipFilePath = Path.Combine(updatesFolderPath, $"InkCanvasForClass.CE.{version}.zip"); - string tmpFilePath = zipFilePath + ".tmp"; - int maxRetry = 3; - int retryCount = 0; - while (retryCount < maxRetry) + if (string.IsNullOrEmpty(downloadUrl)) { - long existingLength = 0; - if (File.Exists(tmpFilePath)) - existingLength = new FileInfo(tmpFilePath).Length; - try - { - using (var client = new System.Net.Http.HttpClient()) - { - client.Timeout = TimeSpan.FromMinutes(10); - client.DefaultRequestHeaders.Add("User-Agent", "ICC-CE Auto Updater"); - if (existingLength > 0) - client.DefaultRequestHeaders.Range = new System.Net.Http.Headers.RangeHeaderValue(existingLength, null); - using (var response = await client.GetAsync(downloadUrl, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, token)) - { - response.EnsureSuccessStatusCode(); - var totalBytes = response.Content.Headers.ContentLength.HasValue - ? response.Content.Headers.ContentLength.Value + existingLength - : -1L; - using (var stream = await response.Content.ReadAsStreamAsync()) - using (var fs = new FileStream(tmpFilePath, FileMode.Append, FileAccess.Write, FileShare.None)) - { - byte[] buffer = new byte[8192]; - long totalRead = existingLength; - int read; - var lastUpdate = DateTime.Now; - while ((read = await stream.ReadAsync(buffer, 0, buffer.Length, token)) > 0) - { - token.ThrowIfCancellationRequested(); - await fs.WriteAsync(buffer, 0, read, token); - totalRead += read; - if ((DateTime.Now - lastUpdate).TotalMilliseconds > 200) - { - int percent = totalBytes > 0 ? (int)(totalRead * 100 / totalBytes) : 0; - Dispatcher.Invoke(() => { - DownloadProgressBar.Value = percent; - DownloadProgressText.Text = totalBytes > 0 - ? $"已下载 {totalRead / 1024 / 1024.0:F2} MB / {totalBytes / 1024 / 1024.0:F2} MB ({percent}%)" - : $"已下载 {totalRead / 1024 / 1024.0:F2} MB"; - }); - lastUpdate = DateTime.Now; - } - } - Dispatcher.Invoke(() => { - DownloadProgressBar.Value = 100; - DownloadProgressText.Text = "下载完成,正在校验..."; - }); - await fs.FlushAsync(token); - } - if (File.Exists(zipFilePath)) File.Delete(zipFilePath); - File.Move(tmpFilePath, zipFilePath); - } - } - // 下载完成后,调用现有安装流程 - LogHelper.WriteLogToFile($"AutoUpdate | 开始安装版本: {version}"); - AutoUpdateHelper.InstallNewVersionApp(version, false); - App.IsAppExitByUser = true; - Application.Current.Dispatcher.Invoke(() => { - Application.Current.Shutdown(); - }); - return true; - } - catch (OperationCanceledException) - { - LogHelper.WriteLogToFile($"AutoUpdate | 用户取消下载", LogHelper.LogType.Info); - return false; - } - catch (Exception ex) when (ex is System.Net.Http.HttpRequestException || ex is IOException) - { - retryCount++; - if (retryCount >= maxRetry) - { - LogHelper.WriteLogToFile($"AutoUpdate | 下载失败,已重试{retryCount}次: {ex.Message}", LogHelper.LogType.Error); - Dispatcher.Invoke(() => { - DownloadProgressText.Text = $"下载失败,已重试{retryCount}次: {ex.Message}"; - }); - return false; - } - else - { - LogHelper.WriteLogToFile($"AutoUpdate | 网络异常,{15 * retryCount}s后第{retryCount}次重试: {ex.Message}", LogHelper.LogType.Warning); - Dispatcher.Invoke(() => { - DownloadProgressText.Text = $"网络异常,{15 * retryCount}s后第{retryCount}次重试..."; - }); - await Task.Delay(15000); - } - } - catch (Exception ex) - { - if (File.Exists(tmpFilePath)) { /* 不删除,便于断点续传 */ } - LogHelper.WriteLogToFile($"AutoUpdate | 下载或安装异常: {ex.Message}", LogHelper.LogType.Error); - Dispatcher.Invoke(() => { - DownloadProgressText.Text = $"下载异常: {ex.Message}"; - }); - return false; - } + // 自动更新场景下,downloadUrl为null,直接用主下载目录 + string updatesFolderPath = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "AutoUpdate"); + downloadUrl = Path.Combine(updatesFolderPath, $"InkCanvasForClass.CE.{version}.zip"); } - return false; + LogHelper.WriteLogToFile($"AutoUpdate | 开始安装版本: {version}"); + AutoUpdateHelper.InstallNewVersionApp(version, false); + App.IsAppExitByUser = true; + Application.Current.Dispatcher.Invoke(() => { + Application.Current.Shutdown(); + }); + return true; } } } diff --git a/Ink Canvas/Windows/HistoryRollbackWindow.xaml.cs b/Ink Canvas/Windows/HistoryRollbackWindow.xaml.cs index fae82a57..13f69c55 100644 --- a/Ink Canvas/Windows/HistoryRollbackWindow.xaml.cs +++ b/Ink Canvas/Windows/HistoryRollbackWindow.xaml.cs @@ -136,107 +136,47 @@ namespace Ink_Canvas if (!Directory.Exists(updatesFolderPath)) Directory.CreateDirectory(updatesFolderPath); string zipFilePath = Path.Combine(updatesFolderPath, $"InkCanvasForClass.CE.{version}.zip"); - string tmpFilePath = zipFilePath + ".tmp"; - int maxRetry = 3; - int retryCount = 0; - while (retryCount < maxRetry) + bool downloadSuccess = false; + try { - long existingLength = 0; - if (File.Exists(tmpFilePath)) - existingLength = new FileInfo(tmpFilePath).Length; - try - { - using (var client = new System.Net.Http.HttpClient()) + downloadSuccess = await AutoUpdateHelper.DownloadFile( + downloadUrl, + zipFilePath, + (percent, text) => { - client.Timeout = TimeSpan.FromMinutes(10); - client.DefaultRequestHeaders.Add("User-Agent", "ICC-CE Auto Updater"); - if (existingLength > 0) - client.DefaultRequestHeaders.Range = new System.Net.Http.Headers.RangeHeaderValue(existingLength, null); - using (var response = await client.GetAsync(downloadUrl, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, token)) - { - response.EnsureSuccessStatusCode(); - var totalBytes = response.Content.Headers.ContentLength.HasValue - ? response.Content.Headers.ContentLength.Value + existingLength - : -1L; - using (var stream = await response.Content.ReadAsStreamAsync()) - using (var fs = new FileStream(tmpFilePath, FileMode.Append, FileAccess.Write, FileShare.None)) - { - byte[] buffer = new byte[8192]; - long totalRead = existingLength; - int read; - var lastUpdate = DateTime.Now; - while ((read = await stream.ReadAsync(buffer, 0, buffer.Length, token)) > 0) - { - token.ThrowIfCancellationRequested(); - await fs.WriteAsync(buffer, 0, read, token); - totalRead += read; - if ((DateTime.Now - lastUpdate).TotalMilliseconds > 200) - { - int percent = totalBytes > 0 ? (int)(totalRead * 100 / totalBytes) : 0; - Dispatcher.Invoke(() => { - DownloadProgressBar.Value = percent; - DownloadProgressText.Text = totalBytes > 0 - ? $"已下载 {totalRead / 1024 / 1024.0:F2} MB / {totalBytes / 1024 / 1024.0:F2} MB ({percent}%)" - : $"已下载 {totalRead / 1024 / 1024.0:F2} MB"; - }); - lastUpdate = DateTime.Now; - } - } - Dispatcher.Invoke(() => { - DownloadProgressBar.Value = 100; - DownloadProgressText.Text = "下载完成,正在校验..."; - }); - await fs.FlushAsync(token); - } - if (File.Exists(zipFilePath)) File.Delete(zipFilePath); - File.Move(tmpFilePath, zipFilePath); - } + Dispatcher.Invoke(() => { + DownloadProgressBar.Value = percent; + DownloadProgressText.Text = text; + }); } - // 下载完成后,调用现有安装流程 - LogHelper.WriteLogToFile($"HistoryRollback | 开始安装版本: {version}"); - AutoUpdateHelper.InstallNewVersionApp(version, false); - App.IsAppExitByUser = true; - Application.Current.Dispatcher.Invoke(() => { - Application.Current.Shutdown(); - }); - return true; - } - catch (OperationCanceledException) + ); + if (!downloadSuccess) { - LogHelper.WriteLogToFile($"HistoryRollback | 用户取消下载", LogHelper.LogType.Info); - return false; - } - catch (Exception ex) when (ex is System.Net.Http.HttpRequestException || ex is IOException) - { - retryCount++; - if (retryCount >= maxRetry) - { - LogHelper.WriteLogToFile($"HistoryRollback | 下载失败,已重试{retryCount}次: {ex.Message}", LogHelper.LogType.Error); - Dispatcher.Invoke(() => { - DownloadProgressText.Text = $"下载失败,已重试{retryCount}次: {ex.Message}"; - }); - return false; - } - else - { - LogHelper.WriteLogToFile($"HistoryRollback | 网络异常,{15 * retryCount}s后第{retryCount}次重试: {ex.Message}", LogHelper.LogType.Warning); - Dispatcher.Invoke(() => { - DownloadProgressText.Text = $"网络异常,{15 * retryCount}s后第{retryCount}次重试..."; - }); - await Task.Delay(15000); - } - } - catch (Exception ex) - { - if (File.Exists(tmpFilePath)) { /* 不删除,便于断点续传 */ } - LogHelper.WriteLogToFile($"HistoryRollback | 下载或安装异常: {ex.Message}", LogHelper.LogType.Error); - Dispatcher.Invoke(() => { - DownloadProgressText.Text = $"下载异常: {ex.Message}"; - }); + LogHelper.WriteLogToFile($"HistoryRollback | 多线程下载失败"); return false; } + // 下载完成后,调用现有安装流程 + LogHelper.WriteLogToFile($"HistoryRollback | 开始安装版本: {version}"); + AutoUpdateHelper.InstallNewVersionApp(version, false); + App.IsAppExitByUser = true; + Application.Current.Dispatcher.Invoke(() => { + Application.Current.Shutdown(); + }); + return true; + } + catch (OperationCanceledException) + { + LogHelper.WriteLogToFile($"HistoryRollback | 用户取消下载", LogHelper.LogType.Info); + return false; + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"HistoryRollback | 下载或安装异常: {ex.Message}", LogHelper.LogType.Error); + Dispatcher.Invoke(() => { + DownloadProgressText.Text = $"下载异常: {ex.Message}"; + }); + return false; } - return false; } protected override void OnClosing(CancelEventArgs e)