Compare commits

..

No commits in common. "1e78942572de7af50a0316c2c7abec3d755fc3bb" and "058c086c51e0ca95817cd80f2ae5af894ef8d49b" have entirely different histories.

17 changed files with 144 additions and 149 deletions

View File

@ -10,8 +10,6 @@ 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 ReleaseMirrorUrl = "https://spt-releases.modd.in/release.json";
public static string PatchMirrorUrl = "https://slugma.waffle-lord.net/mirrors.json";
public static string GetCacheSizeText()
{

View File

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

View File

@ -23,13 +23,29 @@ public class DownloadTask : InstallerTaskBase
private async Task<IResult> BuildMirrorList()
{
foreach (var mirror in _data.PatchInfo.Mirrors)
var progress = new Progress<double>((d) => { SetStatus("Downloading Mirror List", "", (int)Math.Floor(d), ProgressStyle.Shown);});
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;
switch (mirror.Link)
{
case { } l when l.StartsWith("https://mega"):
case string l when l.StartsWith("https://mega"):
_mirrors.Add(new MegaMirrorDownloader(mirror));
break;
default:

View File

@ -1,10 +1,11 @@
using SPTInstaller.Interfaces;
using Gitea.Api;
using Gitea.Client;
using SPTInstaller.Interfaces;
using SPTInstaller.Models;
using System.Threading.Tasks;
using SPTInstaller.Helpers;
using Newtonsoft.Json;
using SPTInstaller.Models.Mirrors;
using SPTInstaller.Models.ReleaseInfo;
using SPTInstaller.Models.Releases;
namespace SPTInstaller.Installer_Tasks;
@ -21,10 +22,12 @@ public class ReleaseCheckTask : InstallerTaskBase
{
try
{
var repo = new RepositoryApi(Configuration.Default);
SetStatus("Checking SPT Releases", "", null, ProgressStyle.Indeterminate);
var progress = new Progress<double>((d) => { SetStatus(null, null, (int)Math.Floor(d)); });
var akiReleaseInfoFile = await DownloadCacheHelper.DownloadFileAsync("release.json", DownloadCacheHelper.ReleaseMirrorUrl, progress);
var akiReleaseInfoFile = await DownloadCacheHelper.DownloadFileAsync("release.json", "https://spt-releases.modd.in/release.json", progress);
if (akiReleaseInfoFile == null)
{
return Result.FromError("Failed to download release metadata");
@ -34,42 +37,34 @@ public class ReleaseCheckTask : InstallerTaskBase
SetStatus("Checking for Patches", "", null, ProgressStyle.Indeterminate);
var akiPatchMirrorsFile =
await DownloadCacheHelper.DownloadFileAsync("mirrors.json", DownloadCacheHelper.PatchMirrorUrl,
progress);
var patchRepoReleases = await repo.RepoListReleasesAsync("SPT-AKI", "Downgrade-Patches");
if (akiPatchMirrorsFile == null)
{
return Result.FromError("Failed to download patch mirror data");
}
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");
}
var comparePatchToAki = patchRepoReleases?.Find(x => x.Name.Contains(_data.OriginalGameVersion) && x.Name.Contains(akiReleaseInfo.ClientVersion));
_data.PatcherMirrorsLink = comparePatchToAki?.Assets[0].BrowserDownloadUrl;
_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;
int IntAkiVersion = int.Parse(akiReleaseInfo.ClientVersion);
int IntGameVersion = int.Parse(_data.OriginalGameVersion);
bool patchNeedCheck = false;
if (intGameVersion < intAkiVersion)
if (IntGameVersion > IntAkiVersion)
{
patchNeedCheck = true;
}
if (IntGameVersion < IntAkiVersion)
{
return Result.FromError("Your client is outdated. Please update EFT");
}
if (intGameVersion == intAkiVersion)
if (IntGameVersion == IntAkiVersion)
{
patchNeedCheck = false;
}
if ((intGameVersion != patchMirrorInfo.SourceClientVersion || intAkiVersion != patchMirrorInfo.TargetClientVersion) && patchNeedCheck)
if (comparePatchToAki == null && patchNeedCheck)
{
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;
public interface IMirrorDownloader
{
public PatchInfoMirror MirrorInfo { get; }
public DownloadMirror MirrorInfo { get; }
public Task<FileInfo?> Download(IProgress<double> progress);
}

View File

@ -1,4 +1,6 @@
using ReactiveUI;
using Gitea.Api;
using Gitea.Client;
using ReactiveUI;
using Serilog;
using SPTInstaller.Helpers;
using System.Diagnostics;
@ -115,57 +117,57 @@ public class InstallerUpdateInfo : ReactiveObject
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 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;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,10 +0,0 @@
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,10 +0,0 @@
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

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

View File

@ -1,4 +1,5 @@
using Avalonia;
using Gitea.Client;
using ReactiveUI;
using Serilog;
using System.Globalization;
@ -20,6 +21,8 @@ public class MainWindowViewModel : ReactiveObject, IActivatableViewModel, IScree
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--"}";
Log.Information($"========= {Title} Started =========");

View File

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