diff --git a/Ink Canvas/Helpers/AutoUpdateHelper.cs b/Ink Canvas/Helpers/AutoUpdateHelper.cs index 72e4c559..544b5d76 100644 --- a/Ink Canvas/Helpers/AutoUpdateHelper.cs +++ b/Ink Canvas/Helpers/AutoUpdateHelper.cs @@ -1050,8 +1050,19 @@ namespace Ink_Canvas.Helpers } // 依次尝试每个线路组 + CancellationToken groupLoopToken; + lock (_activeDownloadLock) + { + groupLoopToken = _activeDownloadCts?.Token ?? CancellationToken.None; + } foreach (var group in groups) { + if (groupLoopToken.IsCancellationRequested) + { + LogHelper.WriteLogToFile("AutoUpdate | 用户已取消,停止尝试后续线路组"); + break; + } + string url = string.Format(group.DownloadUrlFormat, version); url = AppendX64SuffixBeforeZipExtension(url); // 智教联盟需要先获取真实下载地址 @@ -1077,6 +1088,12 @@ namespace Ink_Canvas.Helpers bool downloadSuccess = await DownloadFile(url, zipFilePath, progressCallback); + if (groupLoopToken.IsCancellationRequested) + { + LogHelper.WriteLogToFile("AutoUpdate | 用户已取消,停止尝试后续线路组"); + break; + } + if (downloadSuccess) { SaveDownloadStatus(true); @@ -1294,8 +1311,20 @@ namespace Ink_Canvas.Helpers success = true; LogHelper.WriteLogToFile($"AutoUpdate | 分块{block.Index}下载成功"); } - catch (Exception ex) when (ex is HttpRequestException || ex is IOException || ex is TaskCanceledException) + catch (Exception ex) when (ex is HttpRequestException || ex is IOException || ex is TaskCanceledException || ex is OperationCanceledException) { + // 用户主动取消:不再重试 + if (externalToken.IsCancellationRequested) + { + LogHelper.WriteLogToFile($"AutoUpdate | 分块{block.Index}下载已被用户取消", LogHelper.LogType.Warning); + if (File.Exists(tempPath)) + { + try { File.Delete(tempPath); } catch { } + } + cts.Cancel(); + return; + } + LogHelper.WriteLogToFile($"AutoUpdate | 分块{block.Index}下载失败,第{retry + 1}次: {ex.Message}", LogHelper.LogType.Warning); progressCallback?.Invoke(0, $"分块{block.Index}下载失败,第{retry + 1}次: {ex.Message}"); @@ -1306,7 +1335,8 @@ namespace Ink_Canvas.Helpers } // 增加重试间隔,避免频繁重试 - await Task.Delay(2000 * (retry + 1)); + try { await Task.Delay(2000 * (retry + 1), externalToken); } + catch (OperationCanceledException) { cts.Cancel(); return; } } } if (success) diff --git a/Ink Canvas/Windows/SettingsViews/Pages/UpdatePage.xaml.cs b/Ink Canvas/Windows/SettingsViews/Pages/UpdatePage.xaml.cs index c88ddb86..19f40ebc 100644 --- a/Ink Canvas/Windows/SettingsViews/Pages/UpdatePage.xaml.cs +++ b/Ink Canvas/Windows/SettingsViews/Pages/UpdatePage.xaml.cs @@ -467,26 +467,36 @@ namespace Ink_Canvas.Windows.SettingsViews.Pages { ChangelogViewer.Markdown = "正在加载更新日志..."; - // 优先尝试从 GitHub API 获取最新 Release 的 body + // 优先尝试从 GitHub API 获取最新 Release 的 body(带超时,失败则回退到镜像) try { - var releases = await AutoUpdateHelper.GetAllGithubReleases(SettingsManager.Settings.Startup.UpdateChannel); - var latest = releases? - .OrderByDescending(r => ParseVersionForSort(r.version)) - .Select(r => (Tuple)Tuple.Create(r.version, r.downloadUrl, r.releaseNotes)) - .FirstOrDefault(); - if (latest != null && !string.IsNullOrWhiteSpace(latest.Item3)) + var apiTask = AutoUpdateHelper.GetAllGithubReleases(SettingsManager.Settings.Startup.UpdateChannel); + var completed = await System.Threading.Tasks.Task.WhenAny(apiTask, System.Threading.Tasks.Task.Delay(TimeSpan.FromSeconds(8))); + if (completed == apiTask) { - ChangelogViewer.Markdown = latest.Item3; - return; + var releases = await apiTask; + var latest = releases? + .OrderByDescending(r => ParseVersionForSort(r.version)) + .Select(r => (Tuple)Tuple.Create(r.version, r.downloadUrl, r.releaseNotes)) + .FirstOrDefault(); + if (latest != null && !string.IsNullOrWhiteSpace(latest.Item3)) + { + ChangelogViewer.Markdown = latest.Item3; + return; + } + LogHelper.WriteLogToFile("UpdatePage | GitHub API 未返回可用的更新日志,回退到镜像", LogHelper.LogType.Warning); + } + else + { + LogHelper.WriteLogToFile("UpdatePage | GitHub API 获取更新日志超时,回退到镜像", LogHelper.LogType.Warning); } } catch (Exception ex) { - LogHelper.WriteLogToFile($"UpdatePage | GitHub API 获取更新日志失败,回退到镜像源: {ex.Message}", LogHelper.LogType.Warning); + LogHelper.WriteLogToFile($"UpdatePage | GitHub API 获取更新日志失败,回退到镜像: {ex.Message}", LogHelper.LogType.Warning); } - // 回退到镜像源 + // 回退到镜像源 UpdateLog.md string md = await AutoUpdateHelper.GetUpdateLog(SettingsManager.Settings.Startup.UpdateChannel); ChangelogViewer.Markdown = string.IsNullOrEmpty(md) ? "暂无更新日志。" : md; }