Skip to content

Commit 7897938

Browse files
committed
添加 GitHub 更新服务以检查和下载最新版本
1 parent e1ffe5c commit 7897938

File tree

5 files changed

+230
-15
lines changed

5 files changed

+230
-15
lines changed

Core.Window/SearchItemTool.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,12 @@ public void OpenFile(SearchViewItem? searchViewItem, params object[] inputValues
128128
}
129129
}
130130

131+
public void OpenFile(string path)
132+
{
133+
Log.Debug("打开指定内容" + path);
134+
Shell32.ShellExecute(IntPtr.Zero, "open", path, "", "",
135+
ShowWindowCommand.SW_NORMAL);
136+
}
131137

132138
public void IgnoreItem(SearchViewItem? item)
133139
{

KitopiaAvalonia/Assets/图标.svg

Lines changed: 49 additions & 0 deletions
Loading

KitopiaAvalonia/Program.cs

Lines changed: 98 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
using System;
2+
using System.Diagnostics;
23
using System.Diagnostics.CodeAnalysis;
34
using System.IO;
45
using System.Linq;
56
using System.Net;
7+
using System.Net.Http;
68
using System.Threading.Tasks;
79
using Avalonia;
810
using Avalonia.Controls;
11+
using Avalonia.Controls.Notifications;
912
using Avalonia.Media;
1013
using Avalonia.Media.Imaging;
1114
using Avalonia.Threading;
@@ -16,6 +19,7 @@
1619
using Core.Services.MQTT;
1720
using Core.Services.Onnx;
1821
using Core.Services.Plugin;
22+
using Core.Utils;
1923
using Core.ViewModel.Main;
2024
using Core.ViewModel.Pages;
2125
using Core.ViewModel.Pages.customScenario;
@@ -165,6 +169,7 @@ private static IServiceProvider ConfigureServices()
165169

166170

167171
services.AddSingleton<SettingPage>(e => new SettingPage());
172+
services.AddSingleton<GitHubUpdateService>();
168173

169174
return services.BuildServiceProvider();
170175
}
@@ -181,28 +186,107 @@ private static void CheckAndDeleteLogFiles()
181186
var currentDate = DateTime.Today;
182187

183188
// 获取目录下的所有日志文件,按照最后修改时间排序
184-
var logFiles = Directory.EnumerateFiles(logDirectory)
185-
.Select(f => new FileInfo(f))
186-
.OrderByDescending(f => f.LastWriteTime);
187-
188-
// 遍历每个日志文件
189-
foreach (var logFile in logFiles)
190-
// 计算日志文件的最后修改时间和当前日期的差值
191-
// 如果差值大于要保留的时间范围,就删除该日志文件
192-
if (currentDate - logFile.LastWriteTime > timeSpan)
189+
try
190+
{
191+
var logFiles = Directory.EnumerateFiles(logDirectory)
192+
.Select(f => new FileInfo(f))
193+
.OrderByDescending(f => f.LastWriteTime);
194+
195+
// 遍历每个日志文件
196+
foreach (var logFile in logFiles)
197+
// 计算日志文件的最后修改时间和当前日期的差值
198+
// 如果差值大于要保留的时间范围,就删除该日志文件
199+
if (currentDate - logFile.LastWriteTime > timeSpan)
200+
{
201+
Log.Debug($"删除日志文件:{logFile.FullName}");
202+
logFile.Delete();
203+
}
204+
}
205+
catch (Exception e)
206+
{
207+
// ignored
208+
}
209+
}
210+
211+
private static async Task CheckUpdates()
212+
{
213+
var gitHubUpdateService = ServiceManager.Services.GetService<GitHubUpdateService>();
214+
var (hasUpdate, latestVersion, downloadUrl, releaseNotes) = await gitHubUpdateService!.CheckForUpdatesAsync();
215+
if (hasUpdate && !string.IsNullOrEmpty(downloadUrl))
216+
{
217+
Log.Information($"发现新版本:{latestVersion}");
218+
var dialog = new DialogContent()
193219
{
194-
Log.Debug($"删除日志文件:{logFile.FullName}");
195-
logFile.Delete();
196-
}
220+
Title = $"Kitopia更新 - 发现新版本 {latestVersion}",
221+
Content = $"发现新版本 {latestVersion},是否前往下载?\n\n更新内容:\n{releaseNotes ?? "无更新说明"}",
222+
PrimaryButtonText = "下载并更新",
223+
SecondaryButtonText = "取消",
224+
PrimaryAction = async () =>
225+
{
226+
try
227+
{
228+
var toastService = ServiceManager.Services.GetService<IToastService>();
229+
var tempPath = Path.Combine(Path.GetTempPath(), $"Kitopia_{latestVersion}_Installer.exe");
230+
231+
using var client = new HttpClient();
232+
using var response = await client.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead);
233+
response.EnsureSuccessStatusCode();
234+
235+
var totalBytes = response.Content.Headers.ContentLength ?? -1L;
236+
var canReportProgress = totalBytes != -1;
237+
238+
await using var contentStream = await response.Content.ReadAsStreamAsync();
239+
var fileStream = new FileStream(tempPath, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true);
240+
241+
var buffer = new byte[8192];
242+
long totalRead = 0;
243+
int bytesRead;
244+
var lastProgress = -1;
245+
246+
toastService!.Show("更新", "开始下载更新...");
247+
248+
while ((bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
249+
{
250+
await fileStream.WriteAsync(buffer, 0, bytesRead);
251+
totalRead += bytesRead;
252+
253+
if (canReportProgress)
254+
{
255+
var progress = (int)((double)totalRead / totalBytes * 100);
256+
if (progress > lastProgress && progress % 10 == 0) // Report every 10%
257+
{
258+
lastProgress = progress;
259+
toastService.Show("更新", $"下载进度: {progress}%");
260+
}
261+
}
262+
}
263+
await fileStream.DisposeAsync();
264+
toastService.Show("更新", "下载完成,正在启动安装程序...");
265+
await Task.Delay(1000);
266+
// Close application and start installer
267+
ServiceManager.Services.GetService<ISearchItemTool>()!.OpenFile(tempPath);
268+
await Task.Delay(2000);
269+
Environment.Exit(0);
270+
}
271+
catch (Exception ex)
272+
{
273+
Log.Error(ex, "更新失败");
274+
ServiceManager.Services.GetService<IToastService>()!.Show("更新失败", $"下载出错: {ex.Message}", NotificationType.Error);
275+
}
276+
}
277+
};
278+
await ((IContentDialog)ServiceManager.Services!.GetService(typeof(IContentDialog))!).ShowDialogAsync(null,
279+
dialog);
280+
}
197281
}
198282

199283
public static void OnStartup(string[] arg)
200284
{
201285
Log.Information("启动");
202286
ServiceManager.Services = ConfigureServices();
203287

204-
//CheckAndDeleteLogFiles();
205-
288+
CheckAndDeleteLogFiles();
289+
Task.Run(CheckUpdates);
206290
MqttManager.Init().GetAwaiter().GetResult();
207291
Log.Information("MQTT初始化完成");
208292
HotKeyManager.Init();
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
using System;
2+
using System.Linq;
3+
using System.Net.Http;
4+
using System.Net.Http.Headers;
5+
using System.Reflection;
6+
using System.Threading.Tasks;
7+
using Newtonsoft.Json.Linq;
8+
using Serilog;
9+
10+
namespace KitopiaAvalonia.Services
11+
{
12+
public class GitHubUpdateService
13+
{
14+
private const string Owner = "Maklith";
15+
private const string Repo = "kitopia";
16+
private const string UserAgent = "KitopiaUpdateChecker";
17+
18+
public async Task<(bool hasUpdate, string? latestVersion, string? downloadUrl, string? releaseNotes)> CheckForUpdatesAsync()
19+
{
20+
try
21+
{
22+
using var client = new HttpClient();
23+
client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue(UserAgent, "1.0"));
24+
25+
var url = $"https://update.kitopia.top/repos/{Owner}/{Repo}/releases";
26+
var response = await client.GetAsync(url);
27+
28+
if (!response.IsSuccessStatusCode)
29+
{
30+
Log.Warning($"Failed to check for updates. Status code: {response.StatusCode}");
31+
return (false, null, null, null);
32+
}
33+
34+
var json = await response.Content.ReadAsStringAsync();
35+
var releases = JArray.Parse(json);
36+
var release = releases.Count > 0 ? releases[0] : null;
37+
38+
if (release == null)
39+
{
40+
return (false, null, null, null);
41+
}
42+
43+
var tagName = release["tag_name"]?.ToString();
44+
if (string.IsNullOrEmpty(tagName))
45+
{
46+
return (false, null, null, null);
47+
}
48+
49+
// Remove 'v' prefix if present
50+
var cleanTagName = tagName.TrimStart('v');
51+
52+
var currentVersion = Assembly.GetExecutingAssembly().GetName().Version;
53+
54+
// If current version is not set (e.g. 0.0.0.0), assume dev build and skip update check or handle differently
55+
// For now, we proceed with standard comparison.
56+
57+
if (Version.TryParse(cleanTagName, out var latestVersion))
58+
{
59+
if (latestVersion== currentVersion)
60+
{
61+
var htmlUrl = ((JArray)release["assets"]).FirstOrDefault(e=>e["name"].ToString()==$"Kitopia{cleanTagName}_Installer.exe")?["browser_download_url"]?.ToString();
62+
var body = release["body"]?.ToString();
63+
htmlUrl = htmlUrl.Replace("https://github.com/Maklith","https://update.kitopia.top/Maklith");
64+
return (true, tagName, htmlUrl, body);
65+
}
66+
}
67+
}
68+
catch (Exception ex)
69+
{
70+
Log.Error(ex, "Error checking for updates");
71+
}
72+
73+
return (false, null, null, null);
74+
}
75+
}
76+
}

PluginCore

0 commit comments

Comments
 (0)