diff --git a/Mlaumcherb.Client.Avalonia/Config.cs b/Mlaumcherb.Client.Avalonia/Config.cs
index bc1e5e3..7f5b03d 100644
--- a/Mlaumcherb.Client.Avalonia/Config.cs
+++ b/Mlaumcherb.Client.Avalonia/Config.cs
@@ -1,5 +1,6 @@
using Mlaumcherb.Client.Avalonia.зримое;
using Mlaumcherb.Client.Avalonia.классы;
+using Mlaumcherb.Client.Avalonia.сеть.Update;
using Mlaumcherb.Client.Avalonia.холопы;
namespace Mlaumcherb.Client.Avalonia;
@@ -25,6 +26,13 @@ public record Config
new() { name = "Тимериховое", url = "https://timerix.ddns.net/minecraft/catalog.json" },
new() { name = "Mojang", url = "https://piston-meta.mojang.com/mc/game/version_manifest_v2.json" },
];
+
+ public UpdateHelper.GiteaConfig gitea { get; set; } = new UpdateHelper.GiteaConfig
+ {
+ serverUrl = "https://timerix.ddns.net:3322",
+ user = "Timerix",
+ repo = "mlaumcherb",
+ };
[JsonIgnore] private static IOPath _filePath = "млаумчерб.json";
diff --git a/Mlaumcherb.Client.Avalonia/Mlaumcherb.Client.Avalonia.csproj b/Mlaumcherb.Client.Avalonia/Mlaumcherb.Client.Avalonia.csproj
index 4dd3ad2..979ef3f 100644
--- a/Mlaumcherb.Client.Avalonia/Mlaumcherb.Client.Avalonia.csproj
+++ b/Mlaumcherb.Client.Avalonia/Mlaumcherb.Client.Avalonia.csproj
@@ -1,5 +1,6 @@
+ 1.1.0
Exe
WinExe
net8.0
@@ -34,5 +35,9 @@
+
+
+
+
diff --git a/Mlaumcherb.Client.Avalonia/зримое/LauncherApp.axaml.cs b/Mlaumcherb.Client.Avalonia/зримое/LauncherApp.axaml.cs
index 655c4c4..2a1f31b 100644
--- a/Mlaumcherb.Client.Avalonia/зримое/LauncherApp.axaml.cs
+++ b/Mlaumcherb.Client.Avalonia/зримое/LauncherApp.axaml.cs
@@ -2,6 +2,9 @@ using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Mlaumcherb.Client.Avalonia.классы;
+using Mlaumcherb.Client.Avalonia.сеть;
+using Mlaumcherb.Client.Avalonia.сеть.Update;
+using Mlaumcherb.Client.Avalonia.холопы;
namespace Mlaumcherb.Client.Avalonia.зримое;
@@ -17,6 +20,8 @@ public class LauncherApp : Application
Config = Config.LoadFromFile();
Logger.DebugLogEnabled = Config.debug;
AvaloniaXamlLoader.Load(this);
+
+ Update();
// some file required by forge installer
if (!File.Exists("launcher_profiles.json"))
@@ -27,6 +32,27 @@ public class LauncherApp : Application
InstalledVersionCatalog = InstalledVersionCatalog.Load();
}
+ private async void Update()
+ {
+ try
+ {
+ Logger.LogInfo(nameof(LauncherApp), "checking for updates...");
+ var upd = new UpdateHelper(Config.gitea);
+ upd.DeleteBackupFiles();
+ if (await upd.IsUpdateAvailable())
+ {
+ Logger.LogInfo(nameof(LauncherApp), "downloading update...");
+ await upd.UpdateSelf();
+ Logger.LogInfo(nameof(LauncherApp), "restarting...");
+ upd.RestartSelf();
+ }
+ }
+ catch (Exception e)
+ {
+ ErrorHelper.ShowMessageBox(nameof(LauncherApp), e);
+ }
+ }
+
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
diff --git a/Mlaumcherb.Client.Avalonia/зримое/MainWindow.axaml b/Mlaumcherb.Client.Avalonia/зримое/MainWindow.axaml
index b2619b8..8aee368 100644
--- a/Mlaumcherb.Client.Avalonia/зримое/MainWindow.axaml
+++ b/Mlaumcherb.Client.Avalonia/зримое/MainWindow.axaml
@@ -178,6 +178,7 @@
+
assets { get; set; } = new();
+
+ public class Asset
+ {
+ [JsonRequired] public int id { get; set; }
+ [JsonRequired] public string name { get; set; } = "";
+ [JsonRequired] public int size { get; set; }
+ [JsonRequired] public DateTime created_at { get; set; }
+ [JsonRequired] public string browser_download_url { get; set; } = "";
+
+ public async Task Download(IOPath localPath)
+ {
+ await NetworkHelper.DownloadFile(browser_download_url, localPath);
+ }
+ }
+
+ public Asset? FindAssetByName(string name) =>
+ assets.FirstOrDefault(a => a.name == name);
+}
+
+public class GiteaClient(string ServerUrl)
+{
+ public async Task GetLatestRelease(string user, string repo)
+ {
+ string url = $"{ServerUrl}//api/v1/repos/{user}/{repo}/releases/latest";
+ return await NetworkHelper.DownloadStringAndDeserialize(url);
+ }
+}
\ No newline at end of file
diff --git a/Mlaumcherb.Client.Avalonia/сеть/Update/UpdateHelper.cs b/Mlaumcherb.Client.Avalonia/сеть/Update/UpdateHelper.cs
new file mode 100644
index 0000000..6278a98
--- /dev/null
+++ b/Mlaumcherb.Client.Avalonia/сеть/Update/UpdateHelper.cs
@@ -0,0 +1,74 @@
+using System.Diagnostics;
+using System.Reflection;
+
+namespace Mlaumcherb.Client.Avalonia.сеть.Update;
+
+public class UpdateHelper
+{
+ private readonly string _executableName = "млаумчерб.exe";
+ private readonly IOPath executablePathActual;
+ private readonly IOPath executablePathOld;
+ private readonly IOPath executablePathNew;
+
+
+ public class GiteaConfig
+ {
+ [JsonRequired] public required string serverUrl { get; set; }
+ [JsonRequired] public required string user { get; set; }
+ [JsonRequired] public required string repo { get; set; }
+ }
+
+ private GiteaConfig _giteaConfig;
+
+ public UpdateHelper(GiteaConfig giteaConfig)
+ {
+ _giteaConfig = giteaConfig;
+ executablePathActual = _executableName;
+ executablePathOld = _executableName + ".old";
+ executablePathNew = _executableName + ".new";
+ Gitea = new GiteaClient(giteaConfig.serverUrl);
+ }
+
+ public GiteaClient Gitea { get; }
+
+ public void DeleteBackupFiles()
+ {
+ if(File.Exists(executablePathOld))
+ File.Delete(executablePathOld);
+ }
+
+ public async Task IsUpdateAvailable()
+ {
+ var latest = await Gitea.GetLatestRelease(_giteaConfig.user, _giteaConfig.repo);
+ if (!Version.TryParse(latest.tag_name, out var latestVersion))
+ throw new Exception($"Can't parse version of latest release: {latest.tag_name}");
+
+ Version? currentVersion = Assembly.GetExecutingAssembly().GetName().Version;
+ if(currentVersion is null)
+ throw new Exception($"Can't get current version from {Assembly.GetExecutingAssembly().GetName()}");
+
+ return currentVersion < latestVersion;
+ }
+
+ public async Task UpdateSelf()
+ {
+ if(File.Exists(executablePathNew))
+ File.Delete(executablePathNew);
+
+ var latest = await Gitea.GetLatestRelease(_giteaConfig.user, _giteaConfig.repo);
+ var asset = latest.FindAssetByName(_executableName);
+ if(asset == null)
+ throw new Exception($"Can't find updated executable on gitea: {_executableName}");
+ await asset.Download(executablePathNew);
+
+ File.Move(executablePathActual, executablePathOld, true);
+ File.Move(executablePathNew, executablePathActual, true);
+ }
+
+ public void RestartSelf()
+ {
+ Process.Start(executablePathActual.ToString());
+ Thread.Sleep(500);
+ Environment.Exit(0);
+ }
+}
\ No newline at end of file