diff --git a/SPTInstaller/CustomControls/UpdateInfoCard.axaml b/SPTInstaller/CustomControls/UpdateInfoCard.axaml
deleted file mode 100644
index d9f0772..0000000
--- a/SPTInstaller/CustomControls/UpdateInfoCard.axaml
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/SPTInstaller/CustomControls/UpdateInfoCard.axaml.cs b/SPTInstaller/CustomControls/UpdateInfoCard.axaml.cs
deleted file mode 100644
index 95e79f6..0000000
--- a/SPTInstaller/CustomControls/UpdateInfoCard.axaml.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-using Avalonia;
-using Avalonia.Controls;
-using System.Windows.Input;
-
-namespace SPTInstaller.CustomControls;
-public partial class UpdateInfoCard : UserControl
-{
- public UpdateInfoCard()
- {
- InitializeComponent();
- }
-
- public bool ShowUpdateCard
- {
- get => GetValue(ShowUpdateCardProperty);
- set => SetValue(ShowUpdateCardProperty, value);
- }
- public static readonly StyledProperty ShowUpdateCardProperty =
- AvaloniaProperty.Register(nameof(ShowUpdateCard));
-
- public bool Updating
- {
- get => GetValue(UpdatingProperty);
- set => SetValue(UpdatingProperty, value);
- }
- public static readonly StyledProperty UpdatingProperty =
- AvaloniaProperty.Register(nameof(Updating));
-
- public bool UpdateAvailable
- {
- get => GetValue(UpdateAvailableProperty);
- set => SetValue(UpdateAvailableProperty, value);
- }
- public static readonly StyledProperty UpdateAvailableProperty =
- AvaloniaProperty.Register(nameof(UpdateAvailable));
-
- public bool IndeterminateProgress
- {
- get => GetValue(IndeterminateProgressProperty);
- set => SetValue(IndeterminateProgressProperty, value);
- }
- public static readonly StyledProperty IndeterminateProgressProperty =
- AvaloniaProperty.Register(nameof(IndeterminateProgress));
-
- public string InfoText
- {
- get => GetValue(InfoTextProperty);
- set => SetValue(InfoTextProperty, value);
- }
- public static readonly StyledProperty InfoTextProperty =
- AvaloniaProperty.Register(nameof(InfoText));
-
- public int DownloadProgress
- {
- get => GetValue(DownloadProgressProperty);
- set => SetValue(DownloadProgressProperty, value);
- }
- public static readonly StyledProperty DownloadProgressProperty =
- AvaloniaProperty.Register(nameof(DownloadProgress));
-
- public ICommand NotNowCommand
- {
- get => GetValue(NotNowCommandProperty);
- set => SetValue(NotNowCommandProperty, value);
- }
- public static readonly StyledProperty NotNowCommandProperty =
- AvaloniaProperty.Register(nameof(NotNowCommand));
-
- public ICommand UpdateInstallerCommand
- {
- get => GetValue(UpdateInstallerCommandProperty);
- set => SetValue(UpdateInstallerCommandProperty, value);
- }
- public static readonly StyledProperty UpdateInstallerCommandProperty =
- AvaloniaProperty.Register(nameof(UpdateInstallerCommand));
-}
diff --git a/SPTInstaller/Helpers/DownloadCacheHelper.cs b/SPTInstaller/Helpers/DownloadCacheHelper.cs
index b011b1a..7d8d933 100644
--- a/SPTInstaller/Helpers/DownloadCacheHelper.cs
+++ b/SPTInstaller/Helpers/DownloadCacheHelper.cs
@@ -8,11 +8,15 @@ namespace SPTInstaller.Helpers;
public static class DownloadCacheHelper
{
private static HttpClient _httpClient = new() { Timeout = TimeSpan.FromHours(1) };
-
- public static string CachePath = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "spt-installer/cache");
+
+ public static string CachePath = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
+ "spt-installer/cache");
+
public static string ReleaseMirrorUrl = "https://spt-releases.modd.in/release.json";
public static string PatchMirrorUrl = "https://slugma.waffle-lord.net/mirrors.json";
-
+ public static string InstallerUrl = "https://ligma.waffle-lord.net/SPTInstaller.exe";
+ public static string InstallerInfoUrl = "https://ligma.waffle-lord.net/installer.json";
+
public static string GetCacheSizeText()
{
if (!Directory.Exists(CachePath))
@@ -21,24 +25,24 @@ public static class DownloadCacheHelper
Log.Information(message);
return message;
}
-
+
var cacheDir = new DirectoryInfo(CachePath);
-
+
var cacheSize = DirectorySizeHelper.GetSizeOfDirectory(cacheDir);
-
+
if (cacheSize == -1)
{
var message = "An error occurred while getting the cache size :(";
Log.Error(message);
return message;
}
-
+
if (cacheSize == 0)
return "Empty";
-
+
return DirectorySizeHelper.SizeSuffix(cacheSize);
}
-
+
///
/// Check if a file in the cache already exists
///
@@ -46,42 +50,42 @@ public static class DownloadCacheHelper
/// The expected hash of the file in the cache
/// The file found in the cache; null if no file is found
/// True if the file is in the cache and its hash matches the expected hash, otherwise false
- public static bool CheckCache(string fileName, string expectedHash, out FileInfo cachedFile)
+ public static bool CheckCache(string fileName, string expectedHash, out FileInfo cachedFile)
=> CheckCache(new FileInfo(Path.Join(CachePath, fileName)), expectedHash, out cachedFile);
-
+
private static bool CheckCache(FileInfo cacheFile, string expectedHash, out FileInfo fileInCache)
{
fileInCache = cacheFile;
-
+
try
{
cacheFile.Refresh();
Directory.CreateDirectory(CachePath);
-
+
if (!cacheFile.Exists || expectedHash == null)
{
Log.Information($"{cacheFile.Name} {(cacheFile.Exists ? "is in cache" : "NOT in cache")}");
Log.Information($"Expected hash: {(expectedHash == null ? "not provided" : expectedHash)}");
return false;
}
-
+
if (FileHashHelper.CheckHash(cacheFile, expectedHash))
{
fileInCache = cacheFile;
Log.Information("Hashes MATCH");
return true;
}
-
+
Log.Warning("Hashes DO NOT MATCH");
return false;
}
- catch(Exception ex)
+ catch (Exception ex)
{
Log.Error(ex, "Something went wrong during hashing");
return false;
}
}
-
+
///
/// Download a file to the cache folder
///
@@ -90,28 +94,29 @@ public static class DownloadCacheHelper
/// A provider for progress updates
/// A object of the cached file
/// If the file exists, it is deleted before downloading
- public static async Task DownloadFileAsync(string outputFileName, string targetLink, IProgress progress)
+ public static async Task DownloadFileAsync(string outputFileName, string targetLink,
+ IProgress progress)
{
Directory.CreateDirectory(CachePath);
var outputFile = new FileInfo(Path.Join(CachePath, outputFileName));
-
+
try
{
if (outputFile.Exists)
outputFile.Delete();
-
+
// Use the provided extension method
using (var file = new FileStream(outputFile.FullName, FileMode.Create, FileAccess.Write, FileShare.None))
await _httpClient.DownloadDataAsync(targetLink, file, progress);
-
+
outputFile.Refresh();
-
+
if (!outputFile.Exists)
{
Log.Error("Failed to download file from url: {name} :: {url}", outputFileName, targetLink);
return null;
}
-
+
return outputFile;
}
catch (Exception ex)
@@ -120,7 +125,7 @@ public static class DownloadCacheHelper
return null;
}
}
-
+
///
/// Download a file to the cache folder
///
@@ -132,36 +137,36 @@ public static class DownloadCacheHelper
{
Directory.CreateDirectory(CachePath);
var outputFile = new FileInfo(Path.Join(CachePath, outputFileName));
-
+
try
{
if (outputFile.Exists)
outputFile.Delete();
-
+
using var patcherFileStream = outputFile.Open(FileMode.Create);
{
await downloadStream.CopyToAsync(patcherFileStream);
}
-
+
patcherFileStream.Close();
outputFile.Refresh();
-
+
if (!outputFile.Exists)
{
Log.Error("Failed to download file from stream: {name}", outputFileName);
return null;
}
-
+
return outputFile;
}
- catch(Exception ex)
+ catch (Exception ex)
{
Log.Error(ex, "Failed to download file from stream: {fileName}", outputFileName);
return null;
}
}
-
+
///
/// Get the file from cache or download it
///
@@ -171,13 +176,14 @@ public static class DownloadCacheHelper
/// The expected hash of the cached file
/// A object of the cached file
/// Use if you don't have an expected cache file hash
- public static async Task GetOrDownloadFileAsync(string fileName, string targetLink, IProgress progress, string expectedHash)
+ public static async Task GetOrDownloadFileAsync(string fileName, string targetLink,
+ IProgress progress, string expectedHash)
{
try
{
if (CheckCache(fileName, expectedHash, out var cacheFile))
return cacheFile;
-
+
return await DownloadFileAsync(fileName, targetLink, progress);
}
catch (Exception ex)
@@ -186,7 +192,7 @@ public static class DownloadCacheHelper
return null;
}
}
-
+
///
/// Get the file from cache or download it
///
@@ -195,13 +201,14 @@ public static class DownloadCacheHelper
/// The expected hash of the cached file
/// A object of the cached file
/// Use if you don't have an expected cache file hash
- public static async Task GetOrDownloadFileAsync(string fileName, Stream fileDownloadStream, string expectedHash)
+ public static async Task GetOrDownloadFileAsync(string fileName, Stream fileDownloadStream,
+ string expectedHash)
{
try
{
if (CheckCache(fileName, expectedHash, out var cacheFile))
return cacheFile;
-
+
return await DownloadFileAsync(fileName, fileDownloadStream);
}
catch (Exception ex)
diff --git a/SPTInstaller/Models/InstallerInfo.cs b/SPTInstaller/Models/InstallerInfo.cs
new file mode 100644
index 0000000..2ff5002
--- /dev/null
+++ b/SPTInstaller/Models/InstallerInfo.cs
@@ -0,0 +1,7 @@
+namespace SPTInstaller.Models;
+
+public class InstallerInfo
+{
+ public string LatestVersion { get; set; }
+ public string ChangeLog { get; set; }
+}
\ No newline at end of file
diff --git a/SPTInstaller/Models/InstallerUpdateInfo.cs b/SPTInstaller/Models/InstallerUpdateInfo.cs
index 952b8c4..2c7106c 100644
--- a/SPTInstaller/Models/InstallerUpdateInfo.cs
+++ b/SPTInstaller/Models/InstallerUpdateInfo.cs
@@ -3,105 +3,118 @@ using Serilog;
using SPTInstaller.Helpers;
using System.Diagnostics;
using System.Threading.Tasks;
+using Newtonsoft.Json;
namespace SPTInstaller.Models;
+
public class InstallerUpdateInfo : ReactiveObject
{
private Version? _newVersion;
-
- public string NewInstallerUrl = "";
-
+
+ public string ChangeLog = "";
+
private string _updateInfoText = "";
+
public string UpdateInfoText
{
get => _updateInfoText;
set => this.RaiseAndSetIfChanged(ref _updateInfoText, value);
}
-
+
private bool _show = false;
+
public bool Show
{
get => _show;
set => this.RaiseAndSetIfChanged(ref _show, value);
}
-
+
private bool _updating = false;
+
public bool Updating
{
get => _updating;
set => this.RaiseAndSetIfChanged(ref _updating, value);
}
-
+
private bool _updateAvailable = false;
+
public bool UpdateAvailable
{
get => _updateAvailable;
set => this.RaiseAndSetIfChanged(ref _updateAvailable, value);
}
-
+
private bool _checkingForUpdates = false;
+
public bool CheckingForUpdates
{
get => _checkingForUpdates;
set => this.RaiseAndSetIfChanged(ref _checkingForUpdates, value);
}
-
+
private int _downloadProgress;
+
public int DownloadProgress
{
get => _downloadProgress;
set => this.RaiseAndSetIfChanged(ref _downloadProgress, value);
}
-
+
public async Task UpdateInstaller()
{
Updating = true;
UpdateAvailable = false;
var updater = new FileInfo(Path.Join(DownloadCacheHelper.CachePath, "update.ps1"));
-
+
if (!FileHelper.StreamAssemblyResourceOut("update.ps1", updater.FullName))
{
Log.Fatal("Failed to prepare update file");
return;
}
-
-
+
+
if (!updater.Exists)
{
UpdateInfoText = "Failed to get updater from resources :(";
return;
}
-
+
var newInstallerPath = await DownloadNewInstaller();
-
- if(string.IsNullOrWhiteSpace(newInstallerPath))
+
+ if (string.IsNullOrWhiteSpace(newInstallerPath))
return;
-
+
Process.Start(new ProcessStartInfo
{
FileName = "powershell.exe",
- ArgumentList = { "-ExecutionPolicy", "Bypass", "-File", $"{updater.FullName}", $"{newInstallerPath}", $"{Path.Join(Environment.CurrentDirectory, "SPTInstaller.exe")}" }
+ ArgumentList =
+ {
+ "-ExecutionPolicy", "Bypass", "-File", $"{updater.FullName}", $"{newInstallerPath}",
+ $"{Path.Join(Environment.CurrentDirectory, "SPTInstaller.exe")}"
+ }
});
}
-
+
private async Task DownloadNewInstaller()
{
UpdateInfoText = $"Downloading installer v{_newVersion}";
-
+
var progress = new Progress(x => DownloadProgress = (int)x);
-
- var file = await DownloadCacheHelper.DownloadFileAsync("SPTInstller.exe", NewInstallerUrl, progress);
-
+
+ var file = await DownloadCacheHelper.DownloadFileAsync("SPTInstaller.exe", DownloadCacheHelper.InstallerUrl,
+ progress);
+
if (file == null || !file.Exists)
{
UpdateInfoText = "Failed to download new installer :(";
return "";
}
-
+
return file.FullName;
}
-
+
private void EndCheck(string infoText, bool updateAvailable, bool log = true)
{
if (log)
@@ -114,58 +127,58 @@ public class InstallerUpdateInfo : ReactiveObject
CheckingForUpdates = false;
UpdateAvailable = updateAvailable;
}
-
- // public async Task CheckForUpdates(Version? currentVersion)
- // {
- // if (currentVersion == null)
- // return;
- //
- // UpdateInfoText = "Checking for installer updates";
- // Show = true;
- // CheckingForUpdates = true;
- //
- // try
- // {
- // var repo = new RepositoryApi(Configuration.Default);
- //
- // var releases = await repo.RepoListReleasesAsync("CWX", "SPT-AKI-Installer");
- //
- // if (releases == null || releases.Count == 0)
- // {
- // EndCheck("No releases available", false);
- // return;
- // }
- //
- // var latest = releases.FindAll(x => !x.Prerelease)[0];
- //
- // if (latest == null)
- // {
- // EndCheck("could not get latest release", false);
- // return;
- // }
- //
- // var latestVersion = new Version(latest.TagName);
- //
- // if (latestVersion == null || latestVersion <= currentVersion)
- // {
- // EndCheck("No updates available", false);
- // return;
- // }
- //
- // _newVersion = latestVersion;
- //
- // NewInstallerUrl = latest.Assets[0].BrowserDownloadUrl;
- //
- // EndCheck($"Update available: v{latestVersion}", true);
- //
- // return;
- // }
- // catch (Exception ex)
- // {
- // EndCheck(ex.Message, false, false);
- // Log.Error(ex, "Failed to check for updates");
- // }
- //
- // return;
- // }
-}
+
+ public async Task CheckForUpdates(Version? currentVersion)
+ {
+ if (currentVersion == null)
+ return;
+
+ UpdateInfoText = "Checking for installer updates";
+ Show = true;
+ CheckingForUpdates = true;
+
+ try
+ {
+ var installerInfoFile =
+ await DownloadCacheHelper.DownloadFileAsync("installer.json", DownloadCacheHelper.InstallerInfoUrl,
+ null);
+
+ if (installerInfoFile == null)
+ {
+ EndCheck("Failed to download installer info", false);
+ return;
+ }
+
+ var installerInfo =
+ JsonConvert.DeserializeObject(File.ReadAllText(installerInfoFile.FullName));
+
+ if (installerInfo == null)
+ {
+ EndCheck("Failed to parse installer info json", false);
+ return;
+ }
+
+ var latestVersion = new Version(installerInfo.LatestVersion);
+
+ if (latestVersion <= currentVersion)
+ {
+ EndCheck("No updates available", false);
+ return;
+ }
+
+ _newVersion = latestVersion;
+ ChangeLog = installerInfo.ChangeLog;
+
+ EndCheck($"Update available: v{latestVersion}", true);
+
+ return;
+ }
+ catch (Exception ex)
+ {
+ EndCheck(ex.Message, false, false);
+ Log.Error(ex, "Failed to check for updates");
+ }
+
+ return;
+ }
+}
\ No newline at end of file