improve:自动更新

This commit is contained in:
2025-07-22 18:25:04 +08:00
parent 86caac4a1d
commit 65d56297fd
3 changed files with 143 additions and 487 deletions
+91 -288
View File
@@ -10,6 +10,7 @@ using System.Linq;
using System.Windows.Controls; using System.Windows.Controls;
using System.Text; using System.Text;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
@@ -514,324 +515,126 @@ namespace Ink_Canvas.Helpers
} }
// 下载文件的具体实现 // 下载文件的具体实现
private static async Task<bool> DownloadFile(string fileUrl, string destinationPath, Action<double, string> progressCallback = null) public static async Task<bool> DownloadFile(string fileUrl, string destinationPath, Action<double, string> progressCallback = null)
{ {
LogHelper.WriteLogToFile($"AutoUpdate | 正在尝试下载: {fileUrl}"); LogHelper.WriteLogToFile($"AutoUpdate | 正在尝试多线程下载: {fileUrl}");
int maxRetry = 3; int maxRetry = 3;
int threadCount = 32; // 提升线程数至32
// 1. 获取文件总大小
long totalSize = await GetContentLength(fileUrl);
if (totalSize <= 0)
{
progressCallback?.Invoke(0, "无法获取文件大小,取消下载");
return false;
}
int blockSize = (int)Math.Ceiling((double)totalSize / threadCount);
long[] blockDownloaded = new long[threadCount];
var tasks = new List<Task>();
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 () =>
{
int retryCount = 0; int retryCount = 0;
while (retryCount < maxRetry) while (retryCount < maxRetry)
{ {
try try
{ {
// 检测是否为Windows 7 using (var client = new HttpClient())
var osVersion = Environment.OSVersion;
bool isWindows7 = osVersion.Version.Major == 6 && osVersion.Version.Minor == 1;
if (isWindows7)
{ {
// Windows 7使用特殊配置 var req = new HttpRequestMessage(HttpMethod.Get, fileUrl);
using (var handler = new HttpClientHandler()) req.Headers.Range = new System.Net.Http.Headers.RangeHeaderValue(start, end);
using (var resp = await client.SendAsync(req, HttpCompletionOption.ResponseHeadersRead, cts.Token))
{ {
try resp.EnsureSuccessStatusCode();
{ using (var fs = new FileStream(tempPath, FileMode.Create, FileAccess.Write, FileShare.None))
// 配置HttpClientHandler以支持Windows 7
handler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;
using (HttpClient client = new HttpClient(handler))
{
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())
{ {
var stream = await resp.Content.ReadAsStreamAsync();
byte[] buffer = new byte[8192]; byte[] buffer = new byte[8192];
long totalBytesRead = 0; int read;
int bytesRead; while ((read = await stream.ReadAsync(buffer, 0, buffer.Length, cts.Token)) > 0)
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); await fs.WriteAsync(buffer, 0, read, cts.Token);
totalBytesRead += bytesRead; blockDownloaded[blockIndex] += read;
// 合并所有块进度
if ((DateTime.Now - lastProgressUpdate).TotalSeconds >= 5) long totalDownloaded = blockDownloaded.Sum();
{ double percent = (double)totalDownloaded / totalSize * 100;
if (totalBytes.HasValue) progressCallback?.Invoke(percent, $"多线程下载中: {percent:F1}%");
{
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);
} }
break; // 成功则退出重试
File.Move(tempFilePath, destinationPath);
LogHelper.WriteLogToFile($"AutoUpdate | 文件保存到: {destinationPath}");
return true;
} }
catch (Exception ex) when (ex is HttpRequestException || ex is IOException)
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())
{
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;
}
}
}
catch (HttpRequestException ex)
{ {
retryCount++; retryCount++;
if (retryCount >= maxRetry) if (retryCount >= maxRetry)
{ {
LogHelper.WriteLogToFile($"AutoUpdate | 下载失败,已重试{retryCount}次: {ex.Message}", LogHelper.LogType.Error); LogHelper.WriteLogToFile($"AutoUpdate | 分块{blockIndex}下载失败,已重试{retryCount}次: {ex.Message}", LogHelper.LogType.Error);
progressCallback?.Invoke(0, $"下载失败,已重试{retryCount}次: {ex.Message}"); progressCallback?.Invoke(0, $"分块{blockIndex}下载失败,已重试{retryCount}次: {ex.Message}");
return false; cts.Cancel();
break;
} }
else else
{ {
LogHelper.WriteLogToFile($"AutoUpdate | 网络异常,{15 * retryCount}s后第{retryCount}次重试: {ex.Message}", LogHelper.LogType.Warning); LogHelper.WriteLogToFile($"AutoUpdate | 分块{blockIndex}网络异常,{15 * retryCount}s后第{retryCount}次重试: {ex.Message}", LogHelper.LogType.Warning);
progressCallback?.Invoke(0, $"网络异常,{15 * retryCount}s后第{retryCount}次重试..."); progressCallback?.Invoke(0, $"分块{blockIndex}网络异常,{15 * retryCount}s后第{retryCount}次重试...");
await Task.Delay(15000);
}
}
catch (IOException ex)
{
retryCount++;
if (retryCount >= maxRetry)
{
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 Task.Delay(15000);
} }
} }
} }
}));
}
await Task.WhenAll(tasks);
if (cts.IsCancellationRequested)
{
progressCallback?.Invoke(0, "多线程下载失败");
// 清理分块文件
for (int i = 0; i < threadCount; i++)
{
string tempPath = destinationPath + $".part{i}";
if (File.Exists(tempPath)) File.Delete(tempPath);
}
return false; return false;
} }
// 3. 合并所有块
using (var output = new FileStream(destinationPath, FileMode.Create, FileAccess.Write, FileShare.None))
{
for (int i = 0; i < threadCount; i++)
{
string tempPath = destinationPath + $".part{i}";
using (var input = new FileStream(tempPath, FileMode.Open, FileAccess.Read))
{
await input.CopyToAsync(output);
}
File.Delete(tempPath);
}
}
progressCallback?.Invoke(100, "多线程下载完成");
return true;
}
// 获取文件总大小
private static async Task<long> 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;
}
// 保存下载状态 // 保存下载状态
private static void SaveDownloadStatus(bool isSuccess) private static void SaveDownloadStatus(bool isSuccess)
+10 -97
View File
@@ -156,6 +156,11 @@ namespace Ink_Canvas
DownloadProgressText.Text = text; DownloadProgressText.Text = text;
}); });
}); });
if (downloadSuccess)
{
// 下载完成后自动安装
await DownloadAndInstallVersion(NewVersion, null, CancellationToken.None);
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -321,70 +326,15 @@ namespace Ink_Canvas
} }
} }
// 多线程分块下载并自动安装
private async Task<bool> DownloadAndInstallVersion(string version, string downloadUrl, CancellationToken token) private async Task<bool> DownloadAndInstallVersion(string version, string downloadUrl, CancellationToken token)
{ {
LogHelper.WriteLogToFile($"AutoUpdate | 开始下载版本: {version}, url: {downloadUrl}"); if (string.IsNullOrEmpty(downloadUrl))
{
// 自动更新场景下,downloadUrl为null,直接用主下载目录
string updatesFolderPath = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "AutoUpdate"); string updatesFolderPath = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "AutoUpdate");
if (!Directory.Exists(updatesFolderPath)) downloadUrl = Path.Combine(updatesFolderPath, $"InkCanvasForClass.CE.{version}.zip");
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)
{
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}"); LogHelper.WriteLogToFile($"AutoUpdate | 开始安装版本: {version}");
AutoUpdateHelper.InstallNewVersionApp(version, false); AutoUpdateHelper.InstallNewVersionApp(version, false);
App.IsAppExitByUser = true; App.IsAppExitByUser = true;
@@ -393,42 +343,5 @@ namespace Ink_Canvas
}); });
return true; 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;
}
}
return false;
}
} }
} }
@@ -136,61 +136,24 @@ namespace Ink_Canvas
if (!Directory.Exists(updatesFolderPath)) if (!Directory.Exists(updatesFolderPath))
Directory.CreateDirectory(updatesFolderPath); Directory.CreateDirectory(updatesFolderPath);
string zipFilePath = Path.Combine(updatesFolderPath, $"InkCanvasForClass.CE.{version}.zip"); string zipFilePath = Path.Combine(updatesFolderPath, $"InkCanvasForClass.CE.{version}.zip");
string tmpFilePath = zipFilePath + ".tmp"; bool downloadSuccess = false;
int maxRetry = 3;
int retryCount = 0;
while (retryCount < maxRetry)
{
long existingLength = 0;
if (File.Exists(tmpFilePath))
existingLength = new FileInfo(tmpFilePath).Length;
try 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(() => { Dispatcher.Invoke(() => {
DownloadProgressBar.Value = percent; DownloadProgressBar.Value = percent;
DownloadProgressText.Text = totalBytes > 0 DownloadProgressText.Text = text;
? $"已下载 {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);
} }
);
if (!downloadSuccess)
{
LogHelper.WriteLogToFile($"HistoryRollback | 多线程下载失败");
return false;
} }
// 下载完成后,调用现有安装流程 // 下载完成后,调用现有安装流程
LogHelper.WriteLogToFile($"HistoryRollback | 开始安装版本: {version}"); LogHelper.WriteLogToFile($"HistoryRollback | 开始安装版本: {version}");
@@ -206,29 +169,8 @@ namespace Ink_Canvas
LogHelper.WriteLogToFile($"HistoryRollback | 用户取消下载", LogHelper.LogType.Info); LogHelper.WriteLogToFile($"HistoryRollback | 用户取消下载", LogHelper.LogType.Info);
return false; 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) catch (Exception ex)
{ {
if (File.Exists(tmpFilePath)) { /* 不删除,便于断点续传 */ }
LogHelper.WriteLogToFile($"HistoryRollback | 下载或安装异常: {ex.Message}", LogHelper.LogType.Error); LogHelper.WriteLogToFile($"HistoryRollback | 下载或安装异常: {ex.Message}", LogHelper.LogType.Error);
Dispatcher.Invoke(() => { Dispatcher.Invoke(() => {
DownloadProgressText.Text = $"下载异常: {ex.Message}"; DownloadProgressText.Text = $"下载异常: {ex.Message}";
@@ -236,8 +178,6 @@ namespace Ink_Canvas
return false; return false;
} }
} }
return false;
}
protected override void OnClosing(CancelEventArgs e) protected override void OnClosing(CancelEventArgs e)
{ {