Compare commits

...

4 Commits

Author SHA1 Message Date
1e78942572 Merge pull request 'updated the things' (#78) from waffle.lord/SPT-AKI-Installer:impl/r2 into master
Reviewed-on: CWX/SPT-AKI-Installer#78
2024-04-27 18:55:30 +00:00
d840da2f47 updated the things
it might even work
2024-04-27 14:51:54 -04:00
1c595fc239 Merge pull request 'Switch the precheck to use the release.json method of version fetching' (#77) from DrakiaXYZ/SPT-AKI-Installer:fix-release-fetch into master
Reviewed-on: CWX/SPT-AKI-Installer#77
2024-04-26 16:55:44 +00:00
DrakiaXYZ
ac95894967 Switch the precheck to use the release.json method of version fetching
- Removes another hit to the Gitea API
- Renamed 'Models/Releases' to 'Models/ReleaseInfo' to avoid a .gitignore hit, this adds the missing files
- Moved the definition for the release.json URL to DownloadCacheHelper for now
2024-04-26 09:52:41 -07:00
17 changed files with 149 additions and 144 deletions

View File

@ -10,6 +10,8 @@ public static class DownloadCacheHelper
private static HttpClient _httpClient = new() { Timeout = TimeSpan.FromHours(1) }; 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 GetCacheSizeText() public static string GetCacheSizeText()
{ {

View File

@ -1,24 +1,22 @@
using System.Linq; using System.Linq;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text.RegularExpressions;
using Gitea.Model;
using Serilog; using Serilog;
namespace SPTInstaller.Helpers; namespace SPTInstaller.Helpers;
public static class FileHashHelper public static class FileHashHelper
{ {
public static string? GetGiteaReleaseHash(Release release) // public static string? GetGiteaReleaseHash(Release release)
{ // {
var regex = Regex.Match(release.Body, @"Release Hash: (?<hash>\S+)"); // var regex = Regex.Match(release.Body, @"Release Hash: (?<hash>\S+)");
//
if (regex.Success) // if (regex.Success)
{ // {
return regex.Groups["hash"].Value; // return regex.Groups["hash"].Value;
} // }
//
return null; // return null;
} // }
public static bool CheckHash(FileInfo file, string expectedHash) public static bool CheckHash(FileInfo file, string expectedHash)
{ {

View File

@ -23,29 +23,13 @@ public class DownloadTask : InstallerTaskBase
private async Task<IResult> BuildMirrorList() private async Task<IResult> BuildMirrorList()
{ {
var progress = new Progress<double>((d) => { SetStatus("Downloading Mirror List", "", (int)Math.Floor(d), ProgressStyle.Shown);}); foreach (var mirror in _data.PatchInfo.Mirrors)
var file = await DownloadCacheHelper.DownloadFileAsync("mirrors.json", _data.PatcherMirrorsLink, progress);
if (file == null)
{
return Result.FromError("Failed to download mirror list");
}
var mirrorsList = JsonConvert.DeserializeObject<List<DownloadMirror>>(File.ReadAllText(file.FullName));
if (mirrorsList == null)
{
return Result.FromError("Failed to deserialize mirrors list");
}
foreach (var mirror in mirrorsList)
{ {
_expectedPatcherHash = mirror.Hash; _expectedPatcherHash = mirror.Hash;
switch (mirror.Link) switch (mirror.Link)
{ {
case string l when l.StartsWith("https://mega"): case { } l when l.StartsWith("https://mega"):
_mirrors.Add(new MegaMirrorDownloader(mirror)); _mirrors.Add(new MegaMirrorDownloader(mirror));
break; break;
default: default:

View File

@ -1,11 +1,10 @@
using Gitea.Api; using SPTInstaller.Interfaces;
using Gitea.Client;
using SPTInstaller.Interfaces;
using SPTInstaller.Models; using SPTInstaller.Models;
using System.Threading.Tasks; using System.Threading.Tasks;
using SPTInstaller.Helpers; using SPTInstaller.Helpers;
using Newtonsoft.Json; using Newtonsoft.Json;
using SPTInstaller.Models.Releases; using SPTInstaller.Models.Mirrors;
using SPTInstaller.Models.ReleaseInfo;
namespace SPTInstaller.Installer_Tasks; namespace SPTInstaller.Installer_Tasks;
@ -22,12 +21,10 @@ public class ReleaseCheckTask : InstallerTaskBase
{ {
try try
{ {
var repo = new RepositoryApi(Configuration.Default);
SetStatus("Checking SPT Releases", "", null, ProgressStyle.Indeterminate); SetStatus("Checking SPT Releases", "", null, ProgressStyle.Indeterminate);
var progress = new Progress<double>((d) => { SetStatus(null, null, (int)Math.Floor(d)); }); var progress = new Progress<double>((d) => { SetStatus(null, null, (int)Math.Floor(d)); });
var akiReleaseInfoFile = await DownloadCacheHelper.DownloadFileAsync("release.json", "https://spt-releases.modd.in/release.json", progress); var akiReleaseInfoFile = await DownloadCacheHelper.DownloadFileAsync("release.json", DownloadCacheHelper.ReleaseMirrorUrl, progress);
if (akiReleaseInfoFile == null) if (akiReleaseInfoFile == null)
{ {
return Result.FromError("Failed to download release metadata"); return Result.FromError("Failed to download release metadata");
@ -37,34 +34,42 @@ public class ReleaseCheckTask : InstallerTaskBase
SetStatus("Checking for Patches", "", null, ProgressStyle.Indeterminate); SetStatus("Checking for Patches", "", null, ProgressStyle.Indeterminate);
var patchRepoReleases = await repo.RepoListReleasesAsync("SPT-AKI", "Downgrade-Patches"); var akiPatchMirrorsFile =
await DownloadCacheHelper.DownloadFileAsync("mirrors.json", DownloadCacheHelper.PatchMirrorUrl,
progress);
var comparePatchToAki = patchRepoReleases?.Find(x => x.Name.Contains(_data.OriginalGameVersion) && x.Name.Contains(akiReleaseInfo.ClientVersion)); if (akiPatchMirrorsFile == null)
_data.PatcherMirrorsLink = comparePatchToAki?.Assets[0].BrowserDownloadUrl;
_data.ReleaseInfo = akiReleaseInfo;
int IntAkiVersion = int.Parse(akiReleaseInfo.ClientVersion);
int IntGameVersion = int.Parse(_data.OriginalGameVersion);
bool patchNeedCheck = false;
if (IntGameVersion > IntAkiVersion)
{ {
patchNeedCheck = true; return Result.FromError("Failed to download patch mirror data");
} }
if (IntGameVersion < IntAkiVersion) var patchMirrorInfo = JsonConvert.DeserializeObject<PatchInfo>(File.ReadAllText(akiPatchMirrorsFile.FullName));
if (akiReleaseInfo == null || patchMirrorInfo == null)
{
return Result.FromError("An error occurred while deserializing aki or patch data");
}
_data.ReleaseInfo = akiReleaseInfo;
_data.PatchInfo = patchMirrorInfo;
int intAkiVersion = int.Parse(akiReleaseInfo.ClientVersion);
int intGameVersion = int.Parse(_data.OriginalGameVersion);
// note: it's possible the game version could be lower than the aki version and still need a patch if the major version numbers change
// : it's probably a low chance though
bool patchNeedCheck = intGameVersion > intAkiVersion;
if (intGameVersion < intAkiVersion)
{ {
return Result.FromError("Your client is outdated. Please update EFT"); return Result.FromError("Your client is outdated. Please update EFT");
} }
if (IntGameVersion == IntAkiVersion) if (intGameVersion == intAkiVersion)
{ {
patchNeedCheck = false; patchNeedCheck = false;
} }
if (comparePatchToAki == null && patchNeedCheck) if ((intGameVersion != patchMirrorInfo.SourceClientVersion || intAkiVersion != patchMirrorInfo.TargetClientVersion) && patchNeedCheck)
{ {
return Result.FromError("No patcher available for your version.\nA patcher is usually created within 24 hours of an EFT update."); return Result.FromError("No patcher available for your version.\nA patcher is usually created within 24 hours of an EFT update.");
} }

View File

@ -4,6 +4,6 @@ using System.Threading.Tasks;
namespace SPTInstaller.Interfaces; namespace SPTInstaller.Interfaces;
public interface IMirrorDownloader public interface IMirrorDownloader
{ {
public DownloadMirror MirrorInfo { get; } public PatchInfoMirror MirrorInfo { get; }
public Task<FileInfo?> Download(IProgress<double> progress); public Task<FileInfo?> Download(IProgress<double> progress);
} }

View File

@ -1,6 +1,4 @@
using Gitea.Api; using ReactiveUI;
using Gitea.Client;
using ReactiveUI;
using Serilog; using Serilog;
using SPTInstaller.Helpers; using SPTInstaller.Helpers;
using System.Diagnostics; using System.Diagnostics;
@ -117,57 +115,57 @@ public class InstallerUpdateInfo : ReactiveObject
UpdateAvailable = updateAvailable; UpdateAvailable = updateAvailable;
} }
public async Task CheckForUpdates(Version? currentVersion) // public async Task CheckForUpdates(Version? currentVersion)
{ // {
if (currentVersion == null) // if (currentVersion == null)
return; // return;
//
UpdateInfoText = "Checking for installer updates"; // UpdateInfoText = "Checking for installer updates";
Show = true; // Show = true;
CheckingForUpdates = true; // CheckingForUpdates = true;
//
try // try
{ // {
var repo = new RepositoryApi(Configuration.Default); // var repo = new RepositoryApi(Configuration.Default);
//
var releases = await repo.RepoListReleasesAsync("CWX", "SPT-AKI-Installer"); // var releases = await repo.RepoListReleasesAsync("CWX", "SPT-AKI-Installer");
//
if (releases == null || releases.Count == 0) // if (releases == null || releases.Count == 0)
{ // {
EndCheck("No releases available", false); // EndCheck("No releases available", false);
return; // return;
} // }
//
var latest = releases.FindAll(x => !x.Prerelease)[0]; // var latest = releases.FindAll(x => !x.Prerelease)[0];
//
if (latest == null) // if (latest == null)
{ // {
EndCheck("could not get latest release", false); // EndCheck("could not get latest release", false);
return; // return;
} // }
//
var latestVersion = new Version(latest.TagName); // var latestVersion = new Version(latest.TagName);
//
if (latestVersion == null || latestVersion <= currentVersion) // if (latestVersion == null || latestVersion <= currentVersion)
{ // {
EndCheck("No updates available", false); // EndCheck("No updates available", false);
return; // return;
} // }
//
_newVersion = latestVersion; // _newVersion = latestVersion;
//
NewInstallerUrl = latest.Assets[0].BrowserDownloadUrl; // NewInstallerUrl = latest.Assets[0].BrowserDownloadUrl;
//
EndCheck($"Update available: v{latestVersion}", true); // EndCheck($"Update available: v{latestVersion}", true);
//
return; // return;
} // }
catch (Exception ex) // catch (Exception ex)
{ // {
EndCheck(ex.Message, false, false); // EndCheck(ex.Message, false, false);
Log.Error(ex, "Failed to check for updates"); // Log.Error(ex, "Failed to check for updates");
} // }
//
return; // return;
} // }
} }

View File

@ -1,4 +1,5 @@
using SPTInstaller.Models.Releases; using SPTInstaller.Models.Mirrors;
using SPTInstaller.Models.ReleaseInfo;
namespace SPTInstaller.Models; namespace SPTInstaller.Models;
@ -32,12 +33,14 @@ public class InternalData
/// <summary> /// <summary>
/// The release information from release.json /// The release information from release.json
/// </summary> /// </summary>
public ReleaseInfo ReleaseInfo { get; set; } public ReleaseInfo.ReleaseInfo ReleaseInfo { get; set; }
public PatchInfo PatchInfo { get; set; }
/// <summary> /// <summary>
/// The release download link for the patcher mirror list /// The release download link for the patcher mirror list
/// </summary> /// </summary>
public string PatcherMirrorsLink { get; set; } // public string PatcherMirrorsLink { get; set; }
/// <summary> /// <summary>
/// Whether or not a patch is needed to downgrade the client files /// Whether or not a patch is needed to downgrade the client files

View File

@ -4,7 +4,7 @@ using System.Threading.Tasks;
namespace SPTInstaller.Models.Mirrors.Downloaders; namespace SPTInstaller.Models.Mirrors.Downloaders;
public class HttpMirrorDownloader : MirrorDownloaderBase public class HttpMirrorDownloader : MirrorDownloaderBase
{ {
public HttpMirrorDownloader(DownloadMirror mirror) : base(mirror) public HttpMirrorDownloader(PatchInfoMirror mirror) : base(mirror)
{ {
} }

View File

@ -6,7 +6,7 @@ using Serilog;
namespace SPTInstaller.Models.Mirrors.Downloaders; namespace SPTInstaller.Models.Mirrors.Downloaders;
public class MegaMirrorDownloader : MirrorDownloaderBase public class MegaMirrorDownloader : MirrorDownloaderBase
{ {
public MegaMirrorDownloader(DownloadMirror mirrorInfo) : base(mirrorInfo) public MegaMirrorDownloader(PatchInfoMirror mirrorInfo) : base(mirrorInfo)
{ {
} }

View File

@ -4,9 +4,9 @@ using System.Threading.Tasks;
namespace SPTInstaller.Models.Mirrors.Downloaders; namespace SPTInstaller.Models.Mirrors.Downloaders;
public abstract class MirrorDownloaderBase : IMirrorDownloader public abstract class MirrorDownloaderBase : IMirrorDownloader
{ {
public DownloadMirror MirrorInfo { get; private set; } public PatchInfoMirror MirrorInfo { get; private set; }
public abstract Task<FileInfo?> Download(IProgress<double> progress); public abstract Task<FileInfo?> Download(IProgress<double> progress);
public MirrorDownloaderBase(DownloadMirror mirrorInfo) public MirrorDownloaderBase(PatchInfoMirror mirrorInfo)
{ {
MirrorInfo = mirrorInfo; MirrorInfo = mirrorInfo;
} }

View File

@ -0,0 +1,10 @@
using System.Collections.Generic;
namespace SPTInstaller.Models.Mirrors;
public class PatchInfo
{
public int SourceClientVersion { get; set; }
public int TargetClientVersion { get; set; }
public List<PatchInfoMirror> Mirrors { get; set; }
}

View File

@ -1,6 +1,6 @@
namespace SPTInstaller.Models.Mirrors; namespace SPTInstaller.Models.Mirrors;
public class DownloadMirror public class PatchInfoMirror
{ {
public string Link { get; set; } public string Link { get; set; }
public string Hash { get; set; } public string Hash { get; set; }

View File

@ -0,0 +1,10 @@
using System.Collections.Generic;
namespace SPTInstaller.Models.ReleaseInfo;
public class ReleaseInfo
{
public string AkiVersion { get; set; }
public string ClientVersion { get; set; }
public List<ReleaseInfoMirror> Mirrors { get; set; }
}

View File

@ -0,0 +1,6 @@
namespace SPTInstaller.Models.ReleaseInfo;
public class ReleaseInfoMirror
{
public string DownloadUrl { get; set; }
public string Hash { get; set; }
}

View File

@ -9,8 +9,8 @@
<PackageIcon>icon.ico</PackageIcon> <PackageIcon>icon.ico</PackageIcon>
<ApplicationIcon>Assets\icon.ico</ApplicationIcon> <ApplicationIcon>Assets\icon.ico</ApplicationIcon>
<Configurations>Debug;Release;TEST</Configurations> <Configurations>Debug;Release;TEST</Configurations>
<AssemblyVersion>2.59</AssemblyVersion> <AssemblyVersion>2.61</AssemblyVersion>
<FileVersion>2.59</FileVersion> <FileVersion>2.61</FileVersion>
<Company>SPT-AKI</Company> <Company>SPT-AKI</Company>
</PropertyGroup> </PropertyGroup>
@ -47,10 +47,4 @@
<PackageReference Include="Squid-Box.SevenZipSharp" Version="1.6.1.23" /> <PackageReference Include="Squid-Box.SevenZipSharp" Version="1.6.1.23" />
<PackageReference Include="System.Reactive" Version="6.0.0" /> <PackageReference Include="System.Reactive" Version="6.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Reference Include="Gitea">
<HintPath>Z:\dev_stuff\EftPatchHelper\EftPatchHelper\EftPatchHelper\Resources\Gitea.dll</HintPath>
</Reference>
</ItemGroup>
</Project> </Project>

View File

@ -1,5 +1,4 @@
using Avalonia; using Avalonia;
using Gitea.Client;
using ReactiveUI; using ReactiveUI;
using Serilog; using Serilog;
using System.Globalization; using System.Globalization;
@ -21,8 +20,6 @@ public class MainWindowViewModel : ReactiveObject, IActivatableViewModel, IScree
public MainWindowViewModel(bool debugging) public MainWindowViewModel(bool debugging)
{ {
Configuration.Default.BasePath = "https://dev.sp-tarkov.com/api/v1";
Title = $"{(debugging ? "-debug-" : "")} SPT Installer {"v" + Assembly.GetExecutingAssembly().GetName()?.Version?.ToString() ?? "--unknown version--"}"; Title = $"{(debugging ? "-debug-" : "")} SPT Installer {"v" + Assembly.GetExecutingAssembly().GetName()?.Version?.ToString() ?? "--unknown version--"}";
Log.Information($"========= {Title} Started ========="); Log.Information($"========= {Title} Started =========");

View File

@ -5,8 +5,7 @@ using System.Threading.Tasks;
using System.Windows.Input; using System.Windows.Input;
using Avalonia.Threading; using Avalonia.Threading;
using DialogHostAvalonia; using DialogHostAvalonia;
using Gitea.Api; using Newtonsoft.Json;
using Gitea.Client;
using ReactiveUI; using ReactiveUI;
using Serilog; using Serilog;
using SPTInstaller.Controllers; using SPTInstaller.Controllers;
@ -14,6 +13,7 @@ using SPTInstaller.CustomControls;
using SPTInstaller.CustomControls.Dialogs; using SPTInstaller.CustomControls.Dialogs;
using SPTInstaller.Helpers; using SPTInstaller.Helpers;
using SPTInstaller.Models; using SPTInstaller.Models;
using SPTInstaller.Models.ReleaseInfo;
namespace SPTInstaller.ViewModels; namespace SPTInstaller.ViewModels;
@ -262,32 +262,30 @@ public class PreChecksViewModel : ViewModelBase
var result = await installer.RunPreChecks(); var result = await installer.RunPreChecks();
// check for updates // check for updates
await UpdateInfo.CheckForUpdates(Assembly.GetExecutingAssembly().GetName()?.Version); //await UpdateInfo.CheckForUpdates(Assembly.GetExecutingAssembly().GetName()?.Version);
// get latest spt version // get latest spt version
InstallButtonText = "Getting latest release ..."; InstallButtonText = "Getting latest release ...";
InstallButtonCheckState = StatusSpinner.SpinnerState.Running; InstallButtonCheckState = StatusSpinner.SpinnerState.Running;
var repo = new RepositoryApi(Configuration.Default); var progress = new Progress<double>((d) => { });
var akiRepoReleases = await repo.RepoListReleasesAsync("SPT-AKI", "Stable-releases"); var akiReleaseInfoFile = await DownloadCacheHelper.DownloadFileAsync("release.json", DownloadCacheHelper.ReleaseMirrorUrl, progress);
if (akiReleaseInfoFile == null)
if (akiRepoReleases == null || akiRepoReleases.Count == 0)
{ {
InstallButtonText = "Could not get SPT releases from repo"; InstallButtonText = "Could not get SPT release metadata";
InstallButtonCheckState = StatusSpinner.SpinnerState.Error; InstallButtonCheckState = StatusSpinner.SpinnerState.Error;
return; return;
} }
var latestAkiRelease = akiRepoReleases.FindAll(x => !x.Prerelease)[0]; var akiReleaseInfo = JsonConvert.DeserializeObject<ReleaseInfo>(File.ReadAllText(akiReleaseInfoFile.FullName));
if (akiReleaseInfo == null)
if (latestAkiRelease == null)
{ {
InstallButtonText = "Could not find the latest SPT release"; InstallButtonText = "Could not parse latest SPT release";
InstallButtonCheckState = StatusSpinner.SpinnerState.Error; InstallButtonCheckState = StatusSpinner.SpinnerState.Error;
return; return;
} }
InstallButtonText = $"Start Install: SPT v{latestAkiRelease.TagName}"; InstallButtonText = $"Start Install: SPT v{akiReleaseInfo.AkiVersion}";
InstallButtonCheckState = StatusSpinner.SpinnerState.OK; InstallButtonCheckState = StatusSpinner.SpinnerState.OK;
AllowDetailsButton = true; AllowDetailsButton = true;