377 lines
15 KiB
C#
377 lines
15 KiB
C#
using System;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Net.Http;
|
|
using System.Threading.Tasks;
|
|
using System.Reflection;
|
|
using System.Windows;
|
|
using System.Collections.ObjectModel;
|
|
using System.Linq;
|
|
using System.Windows.Controls;
|
|
using System.IO.Compression;
|
|
|
|
namespace Ink_Canvas.Helpers
|
|
{
|
|
internal class AutoUpdateHelper
|
|
{
|
|
public static async Task<string> CheckForUpdates(string proxy = null)
|
|
{
|
|
try
|
|
{
|
|
string localVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
|
|
LogHelper.WriteLogToFile($"AutoUpdate | Local version: {localVersion}");
|
|
|
|
string remoteAddress = proxy;
|
|
remoteAddress += "https://raw.githubusercontent.com/awesome-iwb/icc-ce/refs/heads/main/AutomaticUpdateVersionControl.txt";
|
|
string remoteVersion = await GetRemoteVersion(remoteAddress);
|
|
|
|
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.", 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<string> GetRemoteVersion(string fileUrl)
|
|
{
|
|
using (HttpClient client = new HttpClient())
|
|
{
|
|
try
|
|
{
|
|
// Set a reasonable timeout
|
|
client.Timeout = TimeSpan.FromSeconds(15);
|
|
|
|
LogHelper.WriteLogToFile($"AutoUpdate | Sending HTTP request to: {fileUrl}");
|
|
HttpResponseMessage response = await client.GetAsync(fileUrl);
|
|
|
|
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("<html") || content.Contains("<!DOCTYPE"))
|
|
{
|
|
LogHelper.WriteLogToFile($"AutoUpdate | Received HTML content instead of raw version number - trying to extract version");
|
|
// Try to extract version from GitHub page - look for text content in the file
|
|
int startPos = content.IndexOf("<table");
|
|
if (startPos > 0)
|
|
{
|
|
int endPos = content.IndexOf("</table>", 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(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Ink Canvas Annotation", "AutoUpdate");
|
|
private static string statusFilePath = null;
|
|
|
|
public static async Task<bool> DownloadSetupFileAndSaveStatus(string version, string proxy = "")
|
|
{
|
|
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;
|
|
}
|
|
|
|
string downloadUrl = $"{proxy}https://github.com/awesome-iwb/icc-ce/releases/download/{version}/InkCanvasForClass.CE.{version}.zip";
|
|
|
|
SaveDownloadStatus(false);
|
|
string zipFilePath = Path.Combine(updatesFolderPath, $"InkCanvasForClass.CE.{version}.zip");
|
|
await DownloadFile(downloadUrl, zipFilePath);
|
|
SaveDownloadStatus(true);
|
|
|
|
LogHelper.WriteLogToFile("AutoUpdate | Setup file successfully downloaded.");
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogHelper.WriteLogToFile($"AutoUpdate | Error downloading update: {ex.Message}", LogHelper.LogType.Error);
|
|
|
|
SaveDownloadStatus(false);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static async Task DownloadFile(string fileUrl, string destinationPath)
|
|
{
|
|
using (HttpClient client = new HttpClient())
|
|
{
|
|
try
|
|
{
|
|
HttpResponseMessage response = await client.GetAsync(fileUrl);
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
using (FileStream fileStream = File.Create(destinationPath))
|
|
{
|
|
await response.Content.CopyToAsync(fileStream);
|
|
fileStream.Close();
|
|
}
|
|
}
|
|
catch (HttpRequestException ex)
|
|
{
|
|
Console.WriteLine($"AutoUpdate | HTTP request error: {ex.Message}");
|
|
throw;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"AutoUpdate | Error: {ex.Message}");
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
|
|
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
|
|
{
|
|
string zipFilePath = Path.Combine(updatesFolderPath, $"InkCanvasForClass.CE.{version}.zip");
|
|
|
|
if (!File.Exists(zipFilePath))
|
|
{
|
|
LogHelper.WriteLogToFile($"AutoUpdate | ZIP file not found: {zipFilePath}", LogHelper.LogType.Error);
|
|
return;
|
|
}
|
|
|
|
// 创建临时解压目录
|
|
string extractPath = Path.Combine(updatesFolderPath, $"Extract_{version}");
|
|
if (Directory.Exists(extractPath))
|
|
{
|
|
Directory.Delete(extractPath, true);
|
|
}
|
|
Directory.CreateDirectory(extractPath);
|
|
|
|
// 解压ZIP文件
|
|
LogHelper.WriteLogToFile($"AutoUpdate | Extracting ZIP file to: {extractPath}");
|
|
ZipFile.ExtractToDirectory(zipFilePath, extractPath);
|
|
|
|
// 获取当前应用程序路径
|
|
string currentAppDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
|
LogHelper.WriteLogToFile($"AutoUpdate | Current application directory: {currentAppDir}");
|
|
|
|
// 复制解压的文件到应用程序目录
|
|
LogHelper.WriteLogToFile($"AutoUpdate | Copying files to application directory");
|
|
CopyDirectory(extractPath, currentAppDir);
|
|
|
|
// 清理临时文件
|
|
if (Directory.Exists(extractPath))
|
|
{
|
|
Directory.Delete(extractPath, true);
|
|
}
|
|
|
|
// 重启应用程序
|
|
LogHelper.WriteLogToFile($"AutoUpdate | Update completed, restarting application");
|
|
RestartApplication();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogHelper.WriteLogToFile($"AutoUpdate | Error installing update: {ex.Message}", LogHelper.LogType.Error);
|
|
}
|
|
}
|
|
|
|
private static void CopyDirectory(string sourceDir, string destinationDir)
|
|
{
|
|
// 创建目标目录(如果不存在)
|
|
Directory.CreateDirectory(destinationDir);
|
|
|
|
// 复制所有文件
|
|
foreach (string filePath in Directory.GetFiles(sourceDir))
|
|
{
|
|
string fileName = Path.GetFileName(filePath);
|
|
string destPath = Path.Combine(destinationDir, fileName);
|
|
try
|
|
{
|
|
// 如果目标文件存在,先删除
|
|
if (File.Exists(destPath))
|
|
{
|
|
File.Delete(destPath);
|
|
}
|
|
File.Copy(filePath, destPath);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogHelper.WriteLogToFile($"AutoUpdate | Error copying file {fileName}: {ex.Message}", LogHelper.LogType.Error);
|
|
}
|
|
}
|
|
|
|
// 递归复制所有子目录
|
|
foreach (string subDirPath in Directory.GetDirectories(sourceDir))
|
|
{
|
|
string subDirName = Path.GetFileName(subDirPath);
|
|
string destSubDir = Path.Combine(destinationDir, subDirName);
|
|
CopyDirectory(subDirPath, destSubDir);
|
|
}
|
|
}
|
|
|
|
private static void RestartApplication()
|
|
{
|
|
string appPath = Assembly.GetExecutingAssembly().Location;
|
|
Process.Start(appPath);
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
{
|
|
Application.Current.Shutdown();
|
|
});
|
|
}
|
|
|
|
private static void ExecuteCommandLine(string command)
|
|
{
|
|
try
|
|
{
|
|
ProcessStartInfo processStartInfo = new ProcessStartInfo
|
|
{
|
|
FileName = "cmd.exe",
|
|
Arguments = $"/c {command}",
|
|
RedirectStandardOutput = true,
|
|
RedirectStandardError = true,
|
|
UseShellExecute = false,
|
|
CreateNoWindow = true
|
|
};
|
|
|
|
using (Process process = new Process { StartInfo = processStartInfo })
|
|
{
|
|
process.Start();
|
|
Application.Current.Shutdown();
|
|
/*process.WaitForExit();
|
|
int exitCode = process.ExitCode;*/
|
|
}
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
public static void DeleteUpdatesFolder()
|
|
{
|
|
try
|
|
{
|
|
if (Directory.Exists(updatesFolderPath))
|
|
{
|
|
Directory.Delete(updatesFolderPath, true);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogHelper.WriteLogToFile($"AutoUpdate clearing| Error deleting updates folder: {ex.Message}", LogHelper.LogType.Error);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal class AutoUpdateWithSilenceTimeComboBox
|
|
{
|
|
public static ObservableCollection<string> Hours { get; set; } = new ObservableCollection<string>();
|
|
public static ObservableCollection<string> Minutes { get; set; } = new ObservableCollection<string>();
|
|
|
|
public static void InitializeAutoUpdateWithSilenceTimeComboBoxOptions(ComboBox startTimeComboBox, ComboBox endTimeComboBox)
|
|
{
|
|
for (int hour = 0; hour <= 23; ++hour)
|
|
{
|
|
Hours.Add(hour.ToString("00"));
|
|
}
|
|
for (int minute = 0; minute <= 59; minute += 20)
|
|
{
|
|
Minutes.Add(minute.ToString("00"));
|
|
}
|
|
startTimeComboBox.ItemsSource = Hours.SelectMany(h => Minutes.Select(m => $"{h}:{m}"));
|
|
endTimeComboBox.ItemsSource = Hours.SelectMany(h => Minutes.Select(m => $"{h}:{m}"));
|
|
}
|
|
|
|
public static bool CheckIsInSilencePeriod(string startTime, string endTime)
|
|
{
|
|
if (startTime == endTime) return true;
|
|
DateTime currentTime = DateTime.Now;
|
|
|
|
DateTime StartTime = DateTime.ParseExact(startTime, "HH:mm", null);
|
|
DateTime EndTime = DateTime.ParseExact(endTime, "HH:mm", null);
|
|
if (StartTime <= EndTime)
|
|
{ // 单日时间段
|
|
return currentTime >= StartTime && currentTime <= EndTime;
|
|
}
|
|
else
|
|
{ // 跨越两天的时间段
|
|
return currentTime >= StartTime || currentTime <= EndTime;
|
|
}
|
|
}
|
|
}
|
|
}
|