diff --git a/Ink Canvas/Helpers/AutoUpdateHelper.cs b/Ink Canvas/Helpers/AutoUpdateHelper.cs index 9cc250b1..acf21f04 100644 --- a/Ink Canvas/Helpers/AutoUpdateHelper.cs +++ b/Ink Canvas/Helpers/AutoUpdateHelper.cs @@ -19,617 +19,9 @@ namespace Ink_Canvas.Helpers { // 定义超时时间为10秒 private static readonly TimeSpan RequestTimeout = TimeSpan.FromSeconds(10); - - public static async Task CheckForUpdates(string proxy = null, UpdateChannel channel = UpdateChannel.Release) - { - try - { - string localVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); - LogHelper.WriteLogToFile($"AutoUpdate | Local version: {localVersion}"); - - string remoteAddress = proxy; - - // 根据通道选择URL - string primaryUrl, fallbackUrl; - - if (channel == UpdateChannel.Release) - { - // Release通道版本信息地址 - primaryUrl = "https://github.com/InkCanvasForClass/community/raw/refs/heads/main/AutomaticUpdateVersionControl.txt"; - fallbackUrl = "https://bgithub.xyz/InkCanvasForClass/community/raw/refs/heads/main/AutomaticUpdateVersionControl.txt"; - } - else - { - // Beta通道版本信息地址 - primaryUrl = "https://github.com/InkCanvasForClass/community-beta/raw/refs/heads/main/AutomaticUpdateVersionControl.txt"; - fallbackUrl = "https://bgithub.xyz/InkCanvasForClass/community-beta/raw/refs/heads/main/AutomaticUpdateVersionControl.txt"; - } - - LogHelper.WriteLogToFile($"AutoUpdate | Checking for updates on {channel} channel"); - - // 先尝试主地址 - remoteAddress += primaryUrl; - string remoteVersion = await GetRemoteVersion(remoteAddress); - - // 如果主地址失败,尝试备用地址 - if (remoteVersion == null) - { - LogHelper.WriteLogToFile($"AutoUpdate | Primary URL failed, trying fallback URL"); - remoteVersion = await GetRemoteVersion(proxy + fallbackUrl); - } - - if (remoteVersion != null) - { - LogHelper.WriteLogToFile($"AutoUpdate | Remote version: {remoteVersion}"); - Version local = new Version(localVersion); - Version remote = new Version(remoteVersion); - if (remote > local) - { - LogHelper.WriteLogToFile($"AutoUpdate | New version available: {remoteVersion}"); - return remoteVersion; - } - else - { - LogHelper.WriteLogToFile($"AutoUpdate | Current version is up to date"); - return null; - } - } - else - { - LogHelper.WriteLogToFile("AutoUpdate | Failed to retrieve remote version from both URLs.", LogHelper.LogType.Error); - return null; - } - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"AutoUpdate | Error in CheckForUpdates: {ex.Message}", LogHelper.LogType.Error); - return null; - } - } - - public static async Task GetRemoteVersion(string fileUrl) - { - using (HttpClient client = new HttpClient()) - { - try - { - // 设置超时时间为10秒 - client.Timeout = RequestTimeout; - - LogHelper.WriteLogToFile($"AutoUpdate | Sending HTTP request to: {fileUrl}"); - - // 使用带超时的Task.WhenAny来确保请求不会无限期等待 - var downloadTask = client.GetAsync(fileUrl); - var timeoutTask = Task.Delay(RequestTimeout); - - var completedTask = await Task.WhenAny(downloadTask, timeoutTask); - if (completedTask == timeoutTask) - { - LogHelper.WriteLogToFile($"AutoUpdate | Request timed out after {RequestTimeout.TotalSeconds} seconds", LogHelper.LogType.Error); - return null; - } - - // 请求完成,检查结果 - HttpResponseMessage response = await downloadTask; - - LogHelper.WriteLogToFile($"AutoUpdate | HTTP response status: {response.StatusCode}"); - response.EnsureSuccessStatusCode(); - - string content = await response.Content.ReadAsStringAsync(); - // Trim any whitespace, newlines, etc. - content = content.Trim(); - - // If the content contains HTML (likely the GitHub view page instead of raw content), - // try to extract the version number - if (content.Contains(" 0) - { - int endPos = content.IndexOf("", startPos); - if (endPos > startPos) - { - string tableContent = content.Substring(startPos, endPos - startPos); - // Look for the version number pattern (like 1.2.3 or 1.2.3.4) - var match = System.Text.RegularExpressions.Regex.Match(tableContent, @"(\d+\.\d+\.\d+(\.\d+)?)"); - if (match.Success) - { - content = match.Groups[1].Value; - LogHelper.WriteLogToFile($"AutoUpdate | Extracted version from HTML: {content}"); - } - else - { - LogHelper.WriteLogToFile($"AutoUpdate | Could not extract version from HTML content"); - return null; - } - } - } - } - - LogHelper.WriteLogToFile($"AutoUpdate | Response content: {content}"); - return content; - } - catch (HttpRequestException ex) - { - LogHelper.WriteLogToFile($"AutoUpdate | HTTP request error: {ex.Message}", LogHelper.LogType.Error); - } - catch (TaskCanceledException ex) - { - LogHelper.WriteLogToFile($"AutoUpdate | Request timed out: {ex.Message}", LogHelper.LogType.Error); - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"AutoUpdate | Error: {ex.Message}", LogHelper.LogType.Error); - } - - return null; - } - } - private static string updatesFolderPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "AutoUpdate"); private static string statusFilePath = null; - public static async Task DownloadSetupFileAndSaveStatus(string version, string proxy = "", UpdateChannel channel = UpdateChannel.Release) - { - try - { - statusFilePath = Path.Combine(updatesFolderPath, $"DownloadV{version}Status.txt"); - - if (File.Exists(statusFilePath) && File.ReadAllText(statusFilePath).Trim().ToLower() == "true") - { - LogHelper.WriteLogToFile("AutoUpdate | Setup file already downloaded."); - return true; - } - - // Ensure update directory exists - if (!Directory.Exists(updatesFolderPath)) - { - Directory.CreateDirectory(updatesFolderPath); - LogHelper.WriteLogToFile($"AutoUpdate | Created updates directory: {updatesFolderPath}"); - } - - // 根据通道选择下载地址 - string primaryUrl, fallbackUrl; - - if (channel == UpdateChannel.Release) - { - // Release通道下载地址 - primaryUrl = $"{proxy}https://github.com/InkCanvasForClass/community/releases/download/{version}/InkCanvasForClass.CE.{version}.zip"; - fallbackUrl = $"{proxy}https://bgithub.xyz/InkCanvasForClass/community/releases/download/{version}/InkCanvasForClass.CE.{version}.zip"; - } - else - { - // Beta通道下载地址 - primaryUrl = $"{proxy}https://github.com/InkCanvasForClass/community-beta/releases/download/{version}/InkCanvasForClass.CE.{version}.zip"; - fallbackUrl = $"{proxy}https://bgithub.xyz/InkCanvasForClass/community-beta/releases/download/{version}/InkCanvasForClass.CE.{version}.zip"; - } - - LogHelper.WriteLogToFile($"AutoUpdate | Primary download URL: {primaryUrl}"); - - SaveDownloadStatus(false); - string zipFilePath = Path.Combine(updatesFolderPath, $"InkCanvasForClass.CE.{version}.zip"); - LogHelper.WriteLogToFile($"AutoUpdate | Target file path: {zipFilePath}"); - - // 先尝试主地址下载 - bool downloadSuccess = await DownloadFile(primaryUrl, zipFilePath); - - // 如果主地址下载失败,尝试备用地址 - if (!downloadSuccess) - { - LogHelper.WriteLogToFile($"AutoUpdate | Primary download failed, trying fallback URL: {fallbackUrl}"); - downloadSuccess = await DownloadFile(fallbackUrl, zipFilePath); - } - - if (downloadSuccess) - { - SaveDownloadStatus(true); - LogHelper.WriteLogToFile("AutoUpdate | Setup file successfully downloaded."); - return true; - } - else - { - LogHelper.WriteLogToFile("AutoUpdate | Failed to download the update file from both URLs.", LogHelper.LogType.Error); - return false; - } - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"AutoUpdate | Error downloading update: {ex.Message}", LogHelper.LogType.Error); - if (ex.InnerException != null) - { - LogHelper.WriteLogToFile($"AutoUpdate | Inner exception: {ex.InnerException.Message}", LogHelper.LogType.Error); - } - - SaveDownloadStatus(false); - return false; - } - } - - private static async Task DownloadFile(string fileUrl, string destinationPath) - { - using (HttpClient client = new HttpClient()) - { - try - { - // Configure client - client.Timeout = TimeSpan.FromMinutes(5); // 下载文件需要更长的超时时间 - client.DefaultRequestHeaders.Add("User-Agent", "ICC-CE Auto Updater"); - - LogHelper.WriteLogToFile($"AutoUpdate | Downloading from: {fileUrl}"); - - // 创建临时文件路径 - string tempFilePath = destinationPath + ".tmp"; - - // 确保目标目录存在 - string directory = Path.GetDirectoryName(destinationPath); - if (!Directory.Exists(directory)) - { - Directory.CreateDirectory(directory); - } - - // 使用带超时的Task.WhenAny来确保请求不会无限期等待 - var downloadTask = client.GetAsync(fileUrl, HttpCompletionOption.ResponseHeadersRead); - var initialTimeoutTask = Task.Delay(RequestTimeout); // 使用全局定义的10秒超时 - - var completedTask = await Task.WhenAny(downloadTask, initialTimeoutTask); - if (completedTask == initialTimeoutTask) - { - LogHelper.WriteLogToFile($"AutoUpdate | Initial connection timed out after 30 seconds", LogHelper.LogType.Error); - return false; - } - - // 请求完成,检查结果 - HttpResponseMessage response = await downloadTask; - LogHelper.WriteLogToFile($"AutoUpdate | HTTP response status: {response.StatusCode}"); - response.EnsureSuccessStatusCode(); - - // 获取文件总大小 - long? totalBytes = response.Content.Headers.ContentLength; - LogHelper.WriteLogToFile($"AutoUpdate | File size: {(totalBytes.HasValue ? (totalBytes.Value / 1024.0 / 1024.0).ToString("F2") + " MB" : "Unknown")}"); - - // 创建临时文件流 - using (var fileStream = new FileStream(tempFilePath, FileMode.Create, FileAccess.Write, FileShare.None)) - { - // 获取下载流 - using (var downloadStream = await response.Content.ReadAsStreamAsync()) - { - byte[] buffer = new byte[8192]; // 8KB buffer - long totalBytesRead = 0; - int bytesRead; - DateTime lastProgressUpdate = DateTime.Now; - - // 设置下载超时 - 如果60秒内没有数据传输,则认为下载超时 - 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; - - // 每5秒更新一次进度 - if ((DateTime.Now - lastProgressUpdate).TotalSeconds >= 5) - { - if (totalBytes.HasValue) - { - double percentage = (double)totalBytesRead / totalBytes.Value * 100; - LogHelper.WriteLogToFile($"AutoUpdate | Download progress: {percentage:F1}% ({(totalBytesRead / 1024.0 / 1024.0):F2} MB / {(totalBytes.Value / 1024.0 / 1024.0):F2} MB)"); - } - else - { - LogHelper.WriteLogToFile($"AutoUpdate | Downloaded: {(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 | Download timed out after 60 seconds of inactivity", LogHelper.LogType.Error); - return false; - } - - // 确保下载任务完成 - bool downloadCompleted = await readTask; - - if (downloadCompleted) - { - LogHelper.WriteLogToFile($"AutoUpdate | Download completed: {(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 | File saved to: {destinationPath}"); - return true; - } - - return false; - } - catch (HttpRequestException ex) - { - LogHelper.WriteLogToFile($"AutoUpdate | HTTP request error: {ex.Message}", LogHelper.LogType.Error); - } - catch (TaskCanceledException ex) - { - LogHelper.WriteLogToFile($"AutoUpdate | Download timed out: {ex.Message}", LogHelper.LogType.Error); - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"AutoUpdate | Error downloading file: {ex.Message}", LogHelper.LogType.Error); - if (ex.InnerException != null) - { - LogHelper.WriteLogToFile($"AutoUpdate | Inner exception: {ex.InnerException.Message}", LogHelper.LogType.Error); - } - } - - // 清理临时文件 - try - { - string tempFilePath = destinationPath + ".tmp"; - if (File.Exists(tempFilePath)) - { - File.Delete(tempFilePath); - } - } - catch { } - - return false; - } - } - - private static void SaveDownloadStatus(bool isSuccess) - { - try - { - if (statusFilePath == null) return; - - string directory = Path.GetDirectoryName(statusFilePath); - if (!Directory.Exists(directory)) - { - Directory.CreateDirectory(directory); - } - - File.WriteAllText(statusFilePath, isSuccess.ToString()); - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"AutoUpdate | Error saving download status: {ex.Message}", LogHelper.LogType.Error); - } - } - - public static void InstallNewVersionApp(string version, bool isInSilence) - { - try - { - // 在更新前备份设置文件 - try - { - // 检查是否开启了自动备份 - if (MainWindow.Settings.Advanced.IsAutoBackupBeforeUpdate) - { - // 确保Backups目录存在 - string backupDir = Path.Combine(App.RootPath, "Backups"); - if (!Directory.Exists(backupDir)) - { - Directory.CreateDirectory(backupDir); - LogHelper.WriteLogToFile($"创建备份目录: {backupDir}", LogHelper.LogType.Info); - } - - // 创建备份文件名(使用当前日期时间和版本号) - string backupFileName = $"Settings_BeforeUpdate_v{version}_{DateTime.Now:yyyyMMdd_HHmmss}.json"; - string backupPath = Path.Combine(backupDir, backupFileName); - - // 序列化当前设置并保存到备份文件 - string settingsJson = Newtonsoft.Json.JsonConvert.SerializeObject(MainWindow.Settings, Newtonsoft.Json.Formatting.Indented); - File.WriteAllText(backupPath, settingsJson); - - LogHelper.WriteLogToFile($"更新前自动备份设置成功: {backupPath}", LogHelper.LogType.Info); - } - else - { - LogHelper.WriteLogToFile("更新前自动备份功能已禁用,跳过备份", LogHelper.LogType.Info); - } - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"更新前自动备份设置时出错: {ex.Message}", LogHelper.LogType.Error); - } - - string zipFilePath = Path.Combine(updatesFolderPath, $"InkCanvasForClass.CE.{version}.zip"); - LogHelper.WriteLogToFile($"AutoUpdate | Checking for ZIP file: {zipFilePath}"); - - if (!File.Exists(zipFilePath)) - { - LogHelper.WriteLogToFile($"AutoUpdate | ZIP file not found: {zipFilePath}", LogHelper.LogType.Error); - return; - } - - // Verify ZIP file size and validity - FileInfo fileInfo = new FileInfo(zipFilePath); - if (fileInfo.Length == 0) - { - LogHelper.WriteLogToFile($"AutoUpdate | ZIP file is empty, cannot continue", LogHelper.LogType.Error); - return; - } - LogHelper.WriteLogToFile($"AutoUpdate | ZIP file size: {fileInfo.Length} bytes"); - - // 获取当前应用程序路径和进程ID - string currentAppDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - int currentProcessId = Process.GetCurrentProcess().Id; - string appPath = Assembly.GetExecutingAssembly().Location; - - LogHelper.WriteLogToFile($"AutoUpdate | Current application directory: {currentAppDir}"); - LogHelper.WriteLogToFile($"AutoUpdate | Current process ID: {currentProcessId}"); - LogHelper.WriteLogToFile($"AutoUpdate | Silent update mode: {isInSilence}"); - - // 创建批处理文件来执行更新操作 - string batchFilePath = Path.Combine(Path.GetTempPath(), "UpdateICC_" + Guid.NewGuid().ToString().Substring(0, 8) + ".bat"); - LogHelper.WriteLogToFile($"AutoUpdate | Creating update batch file: {batchFilePath}"); - - // 构建批处理文件内容 - StringBuilder batchContent = new StringBuilder(); - batchContent.AppendLine("@echo off"); - - // 使窗口隐藏(使用VBS脚本运行隐藏窗口) - batchContent.AppendLine("echo Set objShell = CreateObject(\"WScript.Shell\") > \"%temp%\\hideme.vbs\""); - batchContent.AppendLine("echo objShell.Run \"cmd /c \"\"\" ^& WScript.Arguments(0) ^& \"\"\"\", 0, True >> \"%temp%\\hideme.vbs\""); - batchContent.AppendLine($"echo Wscript.Sleep 100 >> \"%temp%\\hideme.vbs\""); - - // 创建真正的更新批处理文件 - string updateBatPath = Path.Combine(Path.GetTempPath(), "ICCUpdate_" + Guid.NewGuid().ToString().Substring(0, 8) + ".bat"); - batchContent.AppendLine($"echo @echo off > \"{updateBatPath}\""); - - // 写入等待进程退出的代码到更新批处理文件 - batchContent.AppendLine($"echo set PROC_ID={currentProcessId} >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo :CHECK_PROCESS >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo tasklist /fi \"PID eq %PROC_ID%\" ^| find \"%PROC_ID%\" ^> nul >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo if %%ERRORLEVEL%% == 0 ( >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo timeout /t 1 /nobreak ^> nul >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo goto CHECK_PROCESS >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo ) >> \"{updateBatPath}\""); - - // 应用程序已关闭,开始更新操作 - batchContent.AppendLine($"echo echo Application closed, starting update process... >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo timeout /t 2 /nobreak ^> nul >> \"{updateBatPath}\""); - - // 创建临时解压目录 - string extractPath = Path.Combine(updatesFolderPath, $"Extract_{version}"); - batchContent.AppendLine($"echo echo Extracting update files... >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo if exist \"{extractPath}\" rd /s /q \"{extractPath}\" >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo mkdir \"{extractPath}\" >> \"{updateBatPath}\""); - - // PowerShell解压ZIP文件(因为批处理不直接支持ZIP解压) - batchContent.AppendLine($"echo powershell -command \"Expand-Archive -Path '{zipFilePath.Replace("'", "''")}' -DestinationPath '{extractPath.Replace("'", "''")}' -Force\" >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo if %%ERRORLEVEL%% neq 0 ( >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo goto ERROR_EXIT >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo ) >> \"{updateBatPath}\""); - - // 复制文件到应用程序目录 - batchContent.AppendLine($"echo echo Copying updated files to application directory... >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo xcopy /s /y /e \"{extractPath}\\*\" \"{currentAppDir}\\\" >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo if %%ERRORLEVEL%% neq 0 ( >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo goto ERROR_EXIT >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo ) >> \"{updateBatPath}\""); - - // 清理临时文件 - batchContent.AppendLine($"echo echo Cleaning up temporary files... >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo if exist \"{extractPath}\" rd /s /q \"{extractPath}\" >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo if exist \"{zipFilePath}\" del /f /q \"{zipFilePath}\" >> \"{updateBatPath}\""); - - // 启动更新后的应用程序 - batchContent.AppendLine($"echo echo Update completed successfully! >> \"{updateBatPath}\""); - - // 根据是否为静默更新模式决定是否自动启动应用程序 - if (isInSilence) - { - // 静默更新模式下,自动启动应用程序 - batchContent.AppendLine($"echo echo 自动启动应用程序... >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo start \"\" \"{appPath}\" >> \"{updateBatPath}\""); - } - else - { - // 非静默模式下,检查应用程序是否已经在运行 - batchContent.AppendLine($"echo :: 检查应用程序是否已经在运行 >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo tasklist /FI \"IMAGENAME eq Ink Canvas.exe\" | find /i \"Ink Canvas.exe\" > nul >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo if %%ERRORLEVEL%% neq 0 ( >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo echo 启动应用程序... >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo start \"\" \"{appPath}\" >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo ) else ( >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo echo 应用程序已经在运行,不再重复启动 >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo ) >> \"{updateBatPath}\""); - } - - batchContent.AppendLine($"echo exit /b 0 >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo goto EXIT >> \"{updateBatPath}\""); - - // 错误退出处理 - if (isInSilence) - { - // 静默模式下,不显示错误提示 - batchContent.AppendLine($"echo :ERROR_EXIT >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo echo Update failed! >> \"%temp%\\icc_update_error.log\" >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo exit /b 1 >> \"{updateBatPath}\""); - } - else - { - // 非静默模式下,显示错误提示 - batchContent.AppendLine($"echo :ERROR_EXIT >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo start \"\" cmd /c \"echo Update failed! ^& pause\" >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo exit /b 1 >> \"{updateBatPath}\""); - } - - // 删除批处理文件自身 - batchContent.AppendLine($"echo :EXIT >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo del \"{updateBatPath}\" >> \"{updateBatPath}\""); - batchContent.AppendLine($"echo exit >> \"{updateBatPath}\""); - - // 使用VBS脚本执行更新批处理文件(隐藏窗口) - batchContent.AppendLine($"wscript \"%temp%\\hideme.vbs\" \"{updateBatPath}\""); - batchContent.AppendLine("del \"%temp%\\hideme.vbs\""); - batchContent.AppendLine("exit"); - - // 写入批处理文件 - File.WriteAllText(batchFilePath, batchContent.ToString()); - LogHelper.WriteLogToFile($"AutoUpdate | Created update batch file"); - - // 启动批处理文件(隐藏窗口) - Process.Start(new ProcessStartInfo - { - FileName = batchFilePath, - CreateNoWindow = true, - UseShellExecute = true, - WindowStyle = ProcessWindowStyle.Hidden - }); - - LogHelper.WriteLogToFile($"AutoUpdate | Started update batch process with hidden window"); - - // 应用程序将由用户手动关闭或由MainWindow中的代码关闭 - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"AutoUpdate | Error preparing update installation: {ex.Message}", LogHelper.LogType.Error); - if (ex.InnerException != null) - { - LogHelper.WriteLogToFile($"AutoUpdate | Inner exception: {ex.InnerException.Message}", LogHelper.LogType.Error); - } - } - } - - private static async Task GetUrlDelay(string url) - { - try - { - using (var client = new System.Net.Http.HttpClient()) - { - client.Timeout = TimeSpan.FromSeconds(5); - var sw = System.Diagnostics.Stopwatch.StartNew(); - var resp = await client.SendAsync(new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Head, url)); - sw.Stop(); - if (resp.IsSuccessStatusCode) - return sw.ElapsedMilliseconds; - } - } - catch { } - return -1; - } - // 线路组结构体(包含版本、下载、日志地址) public class UpdateLineGroup { @@ -647,9 +39,9 @@ namespace Ink_Canvas.Helpers new UpdateLineGroup { GroupName = "GitHub主线", - VersionUrl = "https://github.com/InkCanvasForClass/community/raw/refs/heads/beta/AutomaticUpdateVersionControl.txt", + VersionUrl = "https://github.com/InkCanvasForClass/community/raw/refs/heads/main/AutomaticUpdateVersionControl.txt", DownloadUrlFormat = "https://github.com/InkCanvasForClass/community/releases/download/{0}/InkCanvasForClass.CE.{0}.zip", - LogUrl = "https://github.com/InkCanvasForClass/community/raw/refs/heads/beta/UpdateLog.md" + LogUrl = "https://github.com/InkCanvasForClass/community/raw/refs/heads/main/UpdateLog.md" }, new UpdateLineGroup { @@ -661,9 +53,9 @@ namespace Ink_Canvas.Helpers new UpdateLineGroup { GroupName = "kkgithub线路", - VersionUrl = "https://kkgithub.com/InkCanvasForClass/community/raw/refs/heads/beta/AutomaticUpdateVersionControl.txt", + VersionUrl = "https://kkgithub.com/InkCanvasForClass/community/raw/refs/heads/main/AutomaticUpdateVersionControl.txt", DownloadUrlFormat = "https://kkgithub.com/InkCanvasForClass/community/releases/download/{0}/InkCanvasForClass.CE.{0}.zip", - LogUrl = "https://kkgithub.com/InkCanvasForClass/community/raw/refs/heads/beta/UpdateLog.md" + LogUrl = "https://kkgithub.com/InkCanvasForClass/community/raw/refs/heads/main/UpdateLog.md" } } }, @@ -694,53 +86,172 @@ namespace Ink_Canvas.Helpers } }; - // 检测线路组延迟,只检测当前通道下的所有线路组,返回最快组 + // 检测URL延迟 + private static async Task GetUrlDelay(string url) + { + try + { + using (var client = new HttpClient()) + { + client.Timeout = TimeSpan.FromSeconds(5); + var sw = Stopwatch.StartNew(); + var resp = await client.SendAsync(new HttpRequestMessage(HttpMethod.Head, url)); + sw.Stop(); + if (resp.IsSuccessStatusCode) + return sw.ElapsedMilliseconds; + } + } + catch { } + return -1; + } + + // 检测线路组延迟,返回最快组 private static async Task GetFastestLineGroup(UpdateChannel channel) { var groups = ChannelLineGroups[channel]; long minDelay = long.MaxValue; UpdateLineGroup bestGroup = null; + + LogHelper.WriteLogToFile($"AutoUpdate | 开始检测通道 {channel} 下所有线路组延迟..."); + foreach (var group in groups) { + LogHelper.WriteLogToFile($"AutoUpdate | 检测线路组: {group.GroupName} ({group.VersionUrl})"); var delay = await GetUrlDelay(group.VersionUrl); - if (delay >= 0 && delay < minDelay) + if (delay >= 0) { - minDelay = delay; - bestGroup = group; + LogHelper.WriteLogToFile($"AutoUpdate | 线路组 {group.GroupName} 延迟: {delay}ms"); + if (delay < minDelay) + { + minDelay = delay; + bestGroup = group; + } + } + else + { + LogHelper.WriteLogToFile($"AutoUpdate | 线路组 {group.GroupName} 不可用", LogHelper.LogType.Warning); } } + + if (bestGroup != null) + { + LogHelper.WriteLogToFile($"AutoUpdate | 选择最快线路组: {bestGroup.GroupName} (延迟: {minDelay}ms)"); + } + else + { + LogHelper.WriteLogToFile("AutoUpdate | 所有线路组均不可用", LogHelper.LogType.Error); + } + return bestGroup; } - // 新的自动选择线路组的更新检测方法,返回远程版本号和所用线路组 - public static async Task<(string remoteVersion, UpdateLineGroup lineGroup)> CheckForUpdatesWithAutoLine(UpdateChannel channel = UpdateChannel.Release, bool alwaysGetRemote = false) + // 获取远程版本号 + private static async Task GetRemoteVersion(string fileUrl) + { + using (HttpClient client = new HttpClient()) + { + try + { + client.Timeout = RequestTimeout; + LogHelper.WriteLogToFile($"AutoUpdate | 发送HTTP请求到: {fileUrl}"); + + var downloadTask = client.GetAsync(fileUrl); + var timeoutTask = Task.Delay(RequestTimeout); + + var completedTask = await Task.WhenAny(downloadTask, timeoutTask); + if (completedTask == timeoutTask) + { + LogHelper.WriteLogToFile($"AutoUpdate | 请求超时 ({RequestTimeout.TotalSeconds}秒)", LogHelper.LogType.Error); + return null; + } + + HttpResponseMessage response = await downloadTask; + LogHelper.WriteLogToFile($"AutoUpdate | HTTP响应状态: {response.StatusCode}"); + response.EnsureSuccessStatusCode(); + + string content = await response.Content.ReadAsStringAsync(); + content = content.Trim(); + + // 如果内容包含HTML(可能是GitHub页面而不是原始内容),尝试提取版本号 + if (content.Contains(" 0) + { + int endPos = content.IndexOf("", startPos); + if (endPos > startPos) + { + string tableContent = content.Substring(startPos, endPos - startPos); + var match = System.Text.RegularExpressions.Regex.Match(tableContent, @"(\d+\.\d+\.\d+(\.\d+)?)"); + if (match.Success) + { + content = match.Groups[1].Value; + LogHelper.WriteLogToFile($"AutoUpdate | 从HTML提取版本: {content}"); + } + else + { + LogHelper.WriteLogToFile($"AutoUpdate | 无法从HTML内容提取版本"); + return null; + } + } + } + } + + LogHelper.WriteLogToFile($"AutoUpdate | 响应内容: {content}"); + return content; + } + 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); + } + + return null; + } + } + + // 主要的更新检测方法(优先检测延迟) + public static async Task<(string remoteVersion, UpdateLineGroup lineGroup)> CheckForUpdates(UpdateChannel channel = UpdateChannel.Release, bool alwaysGetRemote = false) { try { string localVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); - LogHelper.WriteLogToFile($"AutoUpdate | Local version: {localVersion}"); + LogHelper.WriteLogToFile($"AutoUpdate | 本地版本: {localVersion}"); LogHelper.WriteLogToFile($"AutoUpdate | 检测通道 {channel} 下最快线路组..."); + + // 优先检测延迟,选择最快线路组 var bestGroup = await GetFastestLineGroup(channel); if (bestGroup == null) { LogHelper.WriteLogToFile("AutoUpdate | 所有线路组均不可用", LogHelper.LogType.Error); return (null, null); } - LogHelper.WriteLogToFile($"AutoUpdate | 选择最快线路组: {bestGroup.GroupName} {bestGroup.VersionUrl}"); + + LogHelper.WriteLogToFile($"AutoUpdate | 使用最快线路组获取版本信息: {bestGroup.GroupName}"); string remoteVersion = await GetRemoteVersion(bestGroup.VersionUrl); + if (remoteVersion != null) { - LogHelper.WriteLogToFile($"AutoUpdate | Remote version: {remoteVersion}"); + LogHelper.WriteLogToFile($"AutoUpdate | 远程版本: {remoteVersion}"); Version local = new Version(localVersion); Version remote = new Version(remoteVersion); + if (remote > local || alwaysGetRemote) { - LogHelper.WriteLogToFile($"AutoUpdate | New version available or alwaysGetRemote: {remoteVersion}"); + LogHelper.WriteLogToFile($"AutoUpdate | 发现新版本或强制获取: {remoteVersion}"); return (remoteVersion, bestGroup); } else { - LogHelper.WriteLogToFile($"AutoUpdate | Current version is up to date"); + LogHelper.WriteLogToFile($"AutoUpdate | 当前版本已是最新"); return (null, bestGroup); } } @@ -752,75 +263,433 @@ namespace Ink_Canvas.Helpers } catch (Exception ex) { - LogHelper.WriteLogToFile($"AutoUpdate | Error in CheckForUpdatesWithAutoLine: {ex.Message}", LogHelper.LogType.Error); + LogHelper.WriteLogToFile($"AutoUpdate | CheckForUpdates错误: {ex.Message}", LogHelper.LogType.Error); return (null, null); } } // 使用指定线路组下载新版 - public static async Task DownloadSetupFileWithLineGroup(string version, UpdateLineGroup group) + public static async Task DownloadSetupFile(string version, UpdateLineGroup group) { try { + statusFilePath = Path.Combine(updatesFolderPath, $"DownloadV{version}Status.txt"); + + if (File.Exists(statusFilePath) && File.ReadAllText(statusFilePath).Trim().ToLower() == "true") + { + LogHelper.WriteLogToFile("AutoUpdate | 安装包已下载"); + return true; + } + + // 确保更新目录存在 + if (!Directory.Exists(updatesFolderPath)) + { + Directory.CreateDirectory(updatesFolderPath); + LogHelper.WriteLogToFile($"AutoUpdate | 创建更新目录: {updatesFolderPath}"); + } + string url = string.Format(group.DownloadUrlFormat, version); string zipFilePath = Path.Combine(updatesFolderPath, $"InkCanvasForClass.CE.{version}.zip"); - LogHelper.WriteLogToFile($"AutoUpdate | Downloading from: {url}"); - return await DownloadFile(url, zipFilePath); + + LogHelper.WriteLogToFile($"AutoUpdate | 从线路组 {group.GroupName} 下载: {url}"); + LogHelper.WriteLogToFile($"AutoUpdate | 目标文件路径: {zipFilePath}"); + + SaveDownloadStatus(false); + bool downloadSuccess = await DownloadFile(url, zipFilePath); + + if (downloadSuccess) + { + SaveDownloadStatus(true); + LogHelper.WriteLogToFile("AutoUpdate | 安装包下载成功"); + return true; + } + else + { + LogHelper.WriteLogToFile("AutoUpdate | 下载失败", LogHelper.LogType.Error); + return false; + } } catch (Exception ex) { - LogHelper.WriteLogToFile($"AutoUpdate | Error in DownloadSetupFileWithLineGroup: {ex.Message}", LogHelper.LogType.Error); + LogHelper.WriteLogToFile($"AutoUpdate | 下载更新时出错: {ex.Message}", LogHelper.LogType.Error); + if (ex.InnerException != null) + { + LogHelper.WriteLogToFile($"AutoUpdate | 内部异常: {ex.InnerException.Message}", LogHelper.LogType.Error); + } + + SaveDownloadStatus(false); return false; } } - // 使用指定线路组获取更新日志 - public static async Task GetUpdateLogWithLineGroup(UpdateLineGroup group) + // 下载文件的具体实现 + private static async Task DownloadFile(string fileUrl, string destinationPath) { - return await AutoUpdateHelper.GetRemoteContent(group.LogUrl); + 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)"); + } + else + { + LogHelper.WriteLogToFile($"AutoUpdate | 已下载: {(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; + } } - // 获取远程内容的通用方法(public 以便线路组方法调用) + // 保存下载状态 + private static void SaveDownloadStatus(bool isSuccess) + { + try + { + if (statusFilePath == null) return; + + string directory = Path.GetDirectoryName(statusFilePath); + if (!Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + } + + File.WriteAllText(statusFilePath, isSuccess.ToString()); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"AutoUpdate | 保存下载状态时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + // 安装新版本应用 + public static void InstallNewVersionApp(string version, bool isInSilence) + { + try + { + // 在更新前备份设置文件 + try + { + if (MainWindow.Settings.Advanced.IsAutoBackupBeforeUpdate) + { + string backupDir = Path.Combine(App.RootPath, "Backups"); + if (!Directory.Exists(backupDir)) + { + Directory.CreateDirectory(backupDir); + LogHelper.WriteLogToFile($"创建备份目录: {backupDir}", LogHelper.LogType.Info); + } + + string backupFileName = $"Settings_BeforeUpdate_v{version}_{DateTime.Now:yyyyMMdd_HHmmss}.json"; + string backupPath = Path.Combine(backupDir, backupFileName); + + string settingsJson = JsonConvert.SerializeObject(MainWindow.Settings, Formatting.Indented); + File.WriteAllText(backupPath, settingsJson); + + LogHelper.WriteLogToFile($"更新前自动备份设置成功: {backupPath}", LogHelper.LogType.Info); + } + else + { + LogHelper.WriteLogToFile("更新前自动备份功能已禁用,跳过备份", LogHelper.LogType.Info); + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"更新前自动备份设置时出错: {ex.Message}", LogHelper.LogType.Error); + } + + string zipFilePath = Path.Combine(updatesFolderPath, $"InkCanvasForClass.CE.{version}.zip"); + LogHelper.WriteLogToFile($"AutoUpdate | 检查ZIP文件: {zipFilePath}"); + + if (!File.Exists(zipFilePath)) + { + LogHelper.WriteLogToFile($"AutoUpdate | ZIP文件未找到: {zipFilePath}", LogHelper.LogType.Error); + return; + } + + FileInfo fileInfo = new FileInfo(zipFilePath); + if (fileInfo.Length == 0) + { + LogHelper.WriteLogToFile($"AutoUpdate | ZIP文件为空,无法继续", LogHelper.LogType.Error); + return; + } + LogHelper.WriteLogToFile($"AutoUpdate | ZIP文件大小: {fileInfo.Length} 字节"); + + string currentAppDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + int currentProcessId = Process.GetCurrentProcess().Id; + string appPath = Assembly.GetExecutingAssembly().Location; + + LogHelper.WriteLogToFile($"AutoUpdate | 当前应用程序目录: {currentAppDir}"); + LogHelper.WriteLogToFile($"AutoUpdate | 当前进程ID: {currentProcessId}"); + LogHelper.WriteLogToFile($"AutoUpdate | 静默更新模式: {isInSilence}"); + + string batchFilePath = Path.Combine(Path.GetTempPath(), "UpdateICC_" + Guid.NewGuid().ToString().Substring(0, 8) + ".bat"); + LogHelper.WriteLogToFile($"AutoUpdate | 创建更新批处理文件: {batchFilePath}"); + + StringBuilder batchContent = new StringBuilder(); + batchContent.AppendLine("@echo off"); + + batchContent.AppendLine("echo Set objShell = CreateObject(\"WScript.Shell\") > \"%temp%\\hideme.vbs\""); + batchContent.AppendLine("echo objShell.Run \"cmd /c \"\"\" ^& WScript.Arguments(0) ^& \"\"\"\", 0, True >> \"%temp%\\hideme.vbs\""); + batchContent.AppendLine($"echo Wscript.Sleep 100 >> \"%temp%\\hideme.vbs\""); + + string updateBatPath = Path.Combine(Path.GetTempPath(), "ICCUpdate_" + Guid.NewGuid().ToString().Substring(0, 8) + ".bat"); + batchContent.AppendLine($"echo @echo off > \"{updateBatPath}\""); + + batchContent.AppendLine($"echo set PROC_ID={currentProcessId} >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo :CHECK_PROCESS >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo tasklist /fi \"PID eq %PROC_ID%\" ^| find \"%PROC_ID%\" ^> nul >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo if %%ERRORLEVEL%% == 0 ( >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo timeout /t 1 /nobreak ^> nul >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo goto CHECK_PROCESS >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo ) >> \"{updateBatPath}\""); + + batchContent.AppendLine($"echo echo Application closed, starting update process... >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo timeout /t 2 /nobreak ^> nul >> \"{updateBatPath}\""); + + string extractPath = Path.Combine(updatesFolderPath, $"Extract_{version}"); + batchContent.AppendLine($"echo echo Extracting update files... >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo if exist \"{extractPath}\" rd /s /q \"{extractPath}\" >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo mkdir \"{extractPath}\" >> \"{updateBatPath}\""); + + batchContent.AppendLine($"echo powershell -command \"Expand-Archive -Path '{zipFilePath.Replace("'", "''")}' -DestinationPath '{extractPath.Replace("'", "''")}' -Force\" >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo if %%ERRORLEVEL%% neq 0 ( >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo goto ERROR_EXIT >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo ) >> \"{updateBatPath}\""); + + batchContent.AppendLine($"echo echo Copying updated files to application directory... >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo xcopy /s /y /e \"{extractPath}\\*\" \"{currentAppDir}\\\" >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo if %%ERRORLEVEL%% neq 0 ( >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo goto ERROR_EXIT >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo ) >> \"{updateBatPath}\""); + + batchContent.AppendLine($"echo echo Cleaning up temporary files... >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo if exist \"{extractPath}\" rd /s /q \"{extractPath}\" >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo if exist \"{zipFilePath}\" del /f /q \"{zipFilePath}\" >> \"{updateBatPath}\""); + + batchContent.AppendLine($"echo echo Update completed successfully! >> \"{updateBatPath}\""); + + if (isInSilence) + { + batchContent.AppendLine($"echo echo 自动启动应用程序... >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo start \"\" \"{appPath}\" >> \"{updateBatPath}\""); + } + else + { + batchContent.AppendLine($"echo :: 检查应用程序是否已经在运行 >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo tasklist /FI \"IMAGENAME eq Ink Canvas.exe\" | find /i \"Ink Canvas.exe\" > nul >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo if %%ERRORLEVEL%% neq 0 ( >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo echo 启动应用程序... >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo start \"\" \"{appPath}\" >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo ) else ( >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo echo 应用程序已经在运行,不再重复启动 >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo ) >> \"{updateBatPath}\""); + } + + batchContent.AppendLine($"echo exit /b 0 >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo goto EXIT >> \"{updateBatPath}\""); + + if (isInSilence) + { + batchContent.AppendLine($"echo :ERROR_EXIT >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo echo Update failed! >> \"%temp%\\icc_update_error.log\" >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo exit /b 1 >> \"{updateBatPath}\""); + } + else + { + batchContent.AppendLine($"echo :ERROR_EXIT >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo start \"\" cmd /c \"echo Update failed! ^& pause\" >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo exit /b 1 >> \"{updateBatPath}\""); + } + + batchContent.AppendLine($"echo :EXIT >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo del \"{updateBatPath}\" >> \"{updateBatPath}\""); + batchContent.AppendLine($"echo exit >> \"{updateBatPath}\""); + + batchContent.AppendLine($"wscript \"%temp%\\hideme.vbs\" \"{updateBatPath}\""); + batchContent.AppendLine("del \"%temp%\\hideme.vbs\""); + batchContent.AppendLine("exit"); + + File.WriteAllText(batchFilePath, batchContent.ToString()); + LogHelper.WriteLogToFile($"AutoUpdate | 创建更新批处理文件完成"); + + Process.Start(new ProcessStartInfo + { + FileName = batchFilePath, + CreateNoWindow = true, + UseShellExecute = true, + WindowStyle = ProcessWindowStyle.Hidden + }); + + LogHelper.WriteLogToFile($"AutoUpdate | 启动更新批处理进程(隐藏窗口)"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"AutoUpdate | 准备更新安装时出错: {ex.Message}", LogHelper.LogType.Error); + if (ex.InnerException != null) + { + LogHelper.WriteLogToFile($"AutoUpdate | 内部异常: {ex.InnerException.Message}", LogHelper.LogType.Error); + } + } + } + + // 获取远程内容的通用方法 public static async Task GetRemoteContent(string fileUrl) { using (HttpClient client = new HttpClient()) { try { - // 设置超时时间为10秒 client.Timeout = RequestTimeout; - LogHelper.WriteLogToFile($"AutoUpdate | Sending HTTP request to: {fileUrl}"); + LogHelper.WriteLogToFile($"AutoUpdate | 发送HTTP请求到: {fileUrl}"); var downloadTask = client.GetAsync(fileUrl); var timeoutTask = Task.Delay(RequestTimeout); var completedTask = await Task.WhenAny(downloadTask, timeoutTask); if (completedTask == timeoutTask) { - LogHelper.WriteLogToFile($"AutoUpdate | Request timed out after {RequestTimeout.TotalSeconds} seconds", LogHelper.LogType.Error); + LogHelper.WriteLogToFile($"AutoUpdate | 请求超时 ({RequestTimeout.TotalSeconds}秒)", LogHelper.LogType.Error); return null; } HttpResponseMessage response = await downloadTask; - LogHelper.WriteLogToFile($"AutoUpdate | HTTP response status: {response.StatusCode}"); + LogHelper.WriteLogToFile($"AutoUpdate | HTTP响应状态: {response.StatusCode}"); response.EnsureSuccessStatusCode(); string content = await response.Content.ReadAsStringAsync(); return content; } catch (HttpRequestException ex) { - LogHelper.WriteLogToFile($"AutoUpdate | HTTP request error: {ex.Message}", LogHelper.LogType.Error); + LogHelper.WriteLogToFile($"AutoUpdate | HTTP请求错误: {ex.Message}", LogHelper.LogType.Error); } catch (TaskCanceledException ex) { - LogHelper.WriteLogToFile($"AutoUpdate | Request timed out: {ex.Message}", LogHelper.LogType.Error); + LogHelper.WriteLogToFile($"AutoUpdate | 请求超时: {ex.Message}", LogHelper.LogType.Error); } catch (Exception ex) { - LogHelper.WriteLogToFile($"AutoUpdate | Error: {ex.Message}", LogHelper.LogType.Error); + LogHelper.WriteLogToFile($"AutoUpdate | 错误: {ex.Message}", LogHelper.LogType.Error); } return null; } } - // 兼容旧接口:获取更新日志(自动选择最快线路组) + // 使用指定线路组获取更新日志 + public static async Task GetUpdateLogWithLineGroup(UpdateLineGroup group) + { + return await GetRemoteContent(group.LogUrl); + } + + // 获取更新日志(自动选择最快线路组) public static async Task GetUpdateLog(UpdateChannel channel = UpdateChannel.Release) { var group = await GetFastestLineGroup(channel); @@ -828,14 +697,13 @@ namespace Ink_Canvas.Helpers return await GetUpdateLogWithLineGroup(group); } - // 兼容旧接口:删除更新文件夹 + // 删除更新文件夹 public static void DeleteUpdatesFolder() { try { if (Directory.Exists(updatesFolderPath)) { - // Try to delete all files first in case of locking issues foreach (string file in Directory.GetFiles(updatesFolderPath, "*", SearchOption.AllDirectories)) { try { File.Delete(file); } catch { } @@ -850,27 +718,31 @@ namespace Ink_Canvas.Helpers catch { } } - // 兼容旧接口:版本修复方法,强制下载并安装指定通道的最新版本 + // 版本修复方法,强制下载并安装指定通道的最新版本 public static async Task FixVersion(UpdateChannel channel = UpdateChannel.Release) { try { - LogHelper.WriteLogToFile($"AutoUpdate | Starting version fix for {channel} channel"); + LogHelper.WriteLogToFile($"AutoUpdate | 开始修复版本,通道: {channel}"); + // 获取远程版本号(自动选择最快线路组,始终下载远程版本) - var (remoteVersion, group) = await CheckForUpdatesWithAutoLine(channel, true); + var (remoteVersion, group) = await CheckForUpdates(channel, true); if (string.IsNullOrEmpty(remoteVersion) || group == null) { - LogHelper.WriteLogToFile("AutoUpdate | Failed to retrieve remote version for fixing", LogHelper.LogType.Error); + LogHelper.WriteLogToFile("AutoUpdate | 修复版本时获取远程版本失败", LogHelper.LogType.Error); return false; } - LogHelper.WriteLogToFile($"AutoUpdate | Remote version for fixing: {remoteVersion}"); + + LogHelper.WriteLogToFile($"AutoUpdate | 修复版本远程版本: {remoteVersion}"); + // 无论版本是否为最新,都下载远程版本 - bool downloadResult = await DownloadSetupFileWithLineGroup(remoteVersion, group); + bool downloadResult = await DownloadSetupFile(remoteVersion, group); if (!downloadResult) { - LogHelper.WriteLogToFile("AutoUpdate | Failed to download update for fixing", LogHelper.LogType.Error); + LogHelper.WriteLogToFile("AutoUpdate | 修复版本时下载更新失败", LogHelper.LogType.Error); return false; } + // 执行安装,非静默模式 InstallNewVersionApp(remoteVersion, false); App.IsAppExitByUser = true; @@ -881,7 +753,7 @@ namespace Ink_Canvas.Helpers } catch (Exception ex) { - LogHelper.WriteLogToFile($"AutoUpdate | Error in FixVersion: {ex.Message}", LogHelper.LogType.Error); + LogHelper.WriteLogToFile($"AutoUpdate | FixVersion错误: {ex.Message}", LogHelper.LogType.Error); return false; } } diff --git a/Ink Canvas/MainWindow.xaml.cs b/Ink Canvas/MainWindow.xaml.cs index eca67a9c..2f2e6cd2 100644 --- a/Ink Canvas/MainWindow.xaml.cs +++ b/Ink Canvas/MainWindow.xaml.cs @@ -32,6 +32,7 @@ namespace Ink_Canvas { private List whiteboardPages = new List(); private int currentPageIndex = 0; private System.Windows.Controls.Canvas currentCanvas = null; + private AutoUpdateHelper.UpdateLineGroup AvailableLatestLineGroup = null; #region Window Initialization @@ -426,7 +427,9 @@ namespace Ink_Canvas { private async void AutoUpdate() { // 使用当前选择的更新通道检查更新 - AvailableLatestVersion = await AutoUpdateHelper.CheckForUpdates(null, Settings.Startup.UpdateChannel); + var (remoteVersion, lineGroup) = await AutoUpdateHelper.CheckForUpdates(Settings.Startup.UpdateChannel); + AvailableLatestVersion = remoteVersion; + AvailableLatestLineGroup = lineGroup; // 声明下载状态变量,用于整个方法 bool isDownloadSuccessful = false; @@ -459,7 +462,14 @@ namespace Ink_Canvas { LogHelper.WriteLogToFile("AutoUpdate | Silent update enabled, downloading update automatically without notification"); // 静默下载更新,传递当前选择的更新通道 - isDownloadSuccessful = await AutoUpdateHelper.DownloadSetupFileAndSaveStatus(AvailableLatestVersion, "", Settings.Startup.UpdateChannel); + if (AvailableLatestLineGroup != null) + isDownloadSuccessful = await AutoUpdateHelper.DownloadSetupFile(AvailableLatestVersion, AvailableLatestLineGroup); + else + { + var (_, lineGroup2) = await AutoUpdateHelper.CheckForUpdates(Settings.Startup.UpdateChannel, true); + if (lineGroup2 != null) + isDownloadSuccessful = await AutoUpdateHelper.DownloadSetupFile(AvailableLatestVersion, lineGroup2); + } if (isDownloadSuccessful) { LogHelper.WriteLogToFile("AutoUpdate | Update downloaded successfully, will install when conditions are met"); @@ -509,7 +519,14 @@ namespace Ink_Canvas { MessageBox.Show("开始下载更新,请稍候...", "正在更新", MessageBoxButton.OK, MessageBoxImage.Information); // 下载更新文件,传递当前选择的更新通道 - isDownloadSuccessful = await AutoUpdateHelper.DownloadSetupFileAndSaveStatus(AvailableLatestVersion, "", Settings.Startup.UpdateChannel); + if (AvailableLatestLineGroup != null) + isDownloadSuccessful = await AutoUpdateHelper.DownloadSetupFile(AvailableLatestVersion, AvailableLatestLineGroup); + else + { + var (_, lineGroup2) = await AutoUpdateHelper.CheckForUpdates(Settings.Startup.UpdateChannel, true); + if (lineGroup2 != null) + isDownloadSuccessful = await AutoUpdateHelper.DownloadSetupFile(AvailableLatestVersion, lineGroup2); + } if (isDownloadSuccessful) { // 下载成功,提示用户准备安装 @@ -539,7 +556,14 @@ namespace Ink_Canvas { LogHelper.WriteLogToFile("AutoUpdate | User chose to update later"); // 不管设置如何,都进行下载 - isDownloadSuccessful = await AutoUpdateHelper.DownloadSetupFileAndSaveStatus(AvailableLatestVersion, "", Settings.Startup.UpdateChannel); + if (AvailableLatestLineGroup != null) + isDownloadSuccessful = await AutoUpdateHelper.DownloadSetupFile(AvailableLatestVersion, AvailableLatestLineGroup); + else + { + var (_, lineGroup2) = await AutoUpdateHelper.CheckForUpdates(Settings.Startup.UpdateChannel, true); + if (lineGroup2 != null) + isDownloadSuccessful = await AutoUpdateHelper.DownloadSetupFile(AvailableLatestVersion, lineGroup2); + } if (isDownloadSuccessful) { LogHelper.WriteLogToFile("AutoUpdate | Update downloaded successfully, will install when application closes"); diff --git a/Ink Canvas/MainWindow_cs/MW_Timer.cs b/Ink Canvas/MainWindow_cs/MW_Timer.cs index 9a8a07c7..5c7d4a8c 100644 --- a/Ink Canvas/MainWindow_cs/MW_Timer.cs +++ b/Ink Canvas/MainWindow_cs/MW_Timer.cs @@ -331,7 +331,15 @@ namespace Ink_Canvas { // 尝试下载更新文件 Task.Run(async () => { - bool isDownloadSuccessful = await AutoUpdateHelper.DownloadSetupFileAndSaveStatus(AvailableLatestVersion); + bool isDownloadSuccessful = false; + if (AvailableLatestLineGroup != null) + isDownloadSuccessful = await AutoUpdateHelper.DownloadSetupFile(AvailableLatestVersion, AvailableLatestLineGroup); + else + { + var (_, lineGroup2) = await AutoUpdateHelper.CheckForUpdates(Settings.Startup.UpdateChannel, true); + if (lineGroup2 != null) + isDownloadSuccessful = await AutoUpdateHelper.DownloadSetupFile(AvailableLatestVersion, lineGroup2); + } if (isDownloadSuccessful) { LogHelper.WriteLogToFile("AutoUpdate | Update downloaded successfully, will check again for installation"); // 重新启动计时器,下次检查时安装