improve:自动更新

This commit is contained in:
2025-07-22 18:08:22 +08:00
parent d382ac4fa2
commit 86caac4a1d
3 changed files with 472 additions and 288 deletions
+41 -1
View File
@@ -517,10 +517,15 @@ namespace Ink_Canvas.Helpers
private static async Task<bool> DownloadFile(string fileUrl, string destinationPath, Action<double, string> progressCallback = null) private 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 retryCount = 0;
while (retryCount < maxRetry)
{
try
{
// 检测是否为Windows 7 // 检测是否为Windows 7
var osVersion = Environment.OSVersion; var osVersion = Environment.OSVersion;
bool isWindows7 = osVersion.Version.Major == 6 && osVersion.Version.Minor == 1; bool isWindows7 = osVersion.Version.Major == 6 && osVersion.Version.Minor == 1;
if (isWindows7) if (isWindows7)
{ {
// Windows 7使用特殊配置 // Windows 7使用特殊配置
@@ -792,6 +797,41 @@ namespace Ink_Canvas.Helpers
} }
} }
} }
catch (HttpRequestException ex)
{
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);
}
}
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);
}
}
}
return false;
}
// 保存下载状态 // 保存下载状态
private static void SaveDownloadStatus(bool isSuccess) private static void SaveDownloadStatus(bool isSuccess)
@@ -9,6 +9,7 @@ using System.Windows.Interop;
using System.Windows.Media; using System.Windows.Media;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.IO; using System.IO;
using System.Threading;
namespace Ink_Canvas namespace Ink_Canvas
{ {
@@ -319,5 +320,115 @@ namespace Ink_Canvas
} }
} }
} }
private async Task<bool> 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)
{
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;
}
}
return false;
}
} }
} }
@@ -137,6 +137,10 @@ namespace Ink_Canvas
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"; string tmpFilePath = zipFilePath + ".tmp";
int maxRetry = 3;
int retryCount = 0;
while (retryCount < maxRetry)
{
long existingLength = 0; long existingLength = 0;
if (File.Exists(tmpFilePath)) if (File.Exists(tmpFilePath))
existingLength = new FileInfo(tmpFilePath).Length; existingLength = new FileInfo(tmpFilePath).Length;
@@ -169,15 +173,19 @@ namespace Ink_Canvas
if ((DateTime.Now - lastUpdate).TotalMilliseconds > 200) if ((DateTime.Now - lastUpdate).TotalMilliseconds > 200)
{ {
int percent = totalBytes > 0 ? (int)(totalRead * 100 / totalBytes) : 0; int percent = totalBytes > 0 ? (int)(totalRead * 100 / totalBytes) : 0;
Dispatcher.Invoke(() => {
DownloadProgressBar.Value = percent; DownloadProgressBar.Value = percent;
DownloadProgressText.Text = totalBytes > 0 DownloadProgressText.Text = totalBytes > 0
? $"已下载 {totalRead / 1024 / 1024.0:F2} MB / {totalBytes / 1024 / 1024.0:F2} MB ({percent}%)" ? $"已下载 {totalRead / 1024 / 1024.0:F2} MB / {totalBytes / 1024 / 1024.0:F2} MB ({percent}%)"
: $"已下载 {totalRead / 1024 / 1024.0:F2} MB"; : $"已下载 {totalRead / 1024 / 1024.0:F2} MB";
});
lastUpdate = DateTime.Now; lastUpdate = DateTime.Now;
} }
} }
Dispatcher.Invoke(() => {
DownloadProgressBar.Value = 100; DownloadProgressBar.Value = 100;
DownloadProgressText.Text = "下载完成,正在校验..."; DownloadProgressText.Text = "下载完成,正在校验...";
});
await fs.FlushAsync(token); await fs.FlushAsync(token);
} }
if (File.Exists(zipFilePath)) File.Delete(zipFilePath); if (File.Exists(zipFilePath)) File.Delete(zipFilePath);
@@ -198,13 +206,38 @@ 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)) { /* 不删除,便于断点续传 */ } if (File.Exists(tmpFilePath)) { /* 不删除,便于断点续传 */ }
LogHelper.WriteLogToFile($"HistoryRollback | 下载或安装异常: {ex.Message}", LogHelper.LogType.Error); LogHelper.WriteLogToFile($"HistoryRollback | 下载或安装异常: {ex.Message}", LogHelper.LogType.Error);
Dispatcher.Invoke(() => {
DownloadProgressText.Text = $"下载异常: {ex.Message}";
});
return false; return false;
} }
} }
return false;
}
protected override void OnClosing(CancelEventArgs e) protected override void OnClosing(CancelEventArgs e)
{ {