Merge pull request 'imp/7z-compression' (#57) from waffle.lord/SPT-AKI-Installer:imp/7z-compression into master

Reviewed-on: CWX/SPT-AKI-Installer#57
This commit is contained in:
IsWaffle 2024-03-23 18:21:33 +00:00
commit defe7053d3
12 changed files with 92 additions and 70 deletions

View File

@ -1,5 +1,4 @@
using Serilog; using Serilog;
using SharpCompress;
using SPTInstaller.CustomControls; using SPTInstaller.CustomControls;
using SPTInstaller.Interfaces; using SPTInstaller.Interfaces;
using SPTInstaller.Models; using SPTInstaller.Models;
@ -23,10 +22,15 @@ public class InstallController
_tasks = tasks; _tasks = tasks;
_preChecks = preChecks; _preChecks = preChecks;
_preChecks.ForEach(x => x.ReeevaluationRequested += (s, e) => foreach (var check in _preChecks)
{ {
if (s is IPreCheck preCheck) check.ReeevaluationRequested += (s, _) =>
{ {
if (s is not IPreCheck preCheck)
{
return;
}
Log.Information($"{preCheck.Name}: requested re-evaluation"); Log.Information($"{preCheck.Name}: requested re-evaluation");
if (_installRunning) if (_installRunning)
@ -36,8 +40,8 @@ public class InstallController
} }
RecheckRequested?.Invoke(this, null); RecheckRequested?.Invoke(this, null);
};
} }
});
} }
public async Task<IResult> RunPreChecks() public async Task<IResult> RunPreChecks()
@ -45,7 +49,10 @@ public class InstallController
Log.Information("-<>--<>- Running PreChecks -<>--<>-"); Log.Information("-<>--<>- Running PreChecks -<>--<>-");
var requiredResults = new List<IResult>(); var requiredResults = new List<IResult>();
_preChecks.ForEach(x => x.State = StatusSpinner.SpinnerState.Pending); foreach (var check in _preChecks)
{
check.State = StatusSpinner.SpinnerState.Pending;
}
foreach (var check in _preChecks) foreach (var check in _preChecks)
{ {

View File

@ -126,7 +126,9 @@ public static class FileHelper
} }
} }
public static void StreamAssemblyResourceOut(string resourceName, string outputFilePath) public static bool StreamAssemblyResourceOut(string resourceName, string outputFilePath)
{
try
{ {
var assembly = Assembly.GetExecutingAssembly(); var assembly = Assembly.GetExecutingAssembly();
@ -149,6 +151,15 @@ public static class FileHelper
{ {
s.CopyTo(fs); s.CopyTo(fs);
} }
outputFile.Refresh();
return outputFile.Exists;
}
catch (Exception ex)
{
Log.Fatal(ex, $"Failed to stream resource out: {resourceName}");
return false;
}
} }
private enum PathCheckType private enum PathCheckType

View File

@ -1,46 +1,34 @@
using System.Linq; using SevenZip;
using SharpCompress.Archives;
using SharpCompress.Archives.Zip;
using SharpCompress.Common;
using SPTInstaller.Models; using SPTInstaller.Models;
namespace SPTInstaller.Helpers; namespace SPTInstaller.Helpers;
public static class ZipHelper public static class ZipHelper
{ {
public static Result Decompress(FileInfo ArchivePath, DirectoryInfo OutputFolderPath, IProgress<double> progress = null) public static Result Decompress(FileInfo archiveFile, DirectoryInfo outputDirectory, IProgress<double> progress = null)
{ {
try try
{ {
OutputFolderPath.Refresh(); using var archiveStream = archiveFile.OpenRead();
if (!OutputFolderPath.Exists) OutputFolderPath.Create(); var dllPath = Path.Join(DownloadCacheHelper.CachePath, "7z.dll");
using var archive = ZipArchive.Open(ArchivePath); SevenZipBase.SetLibraryPath(dllPath);
var totalEntries = archive.Entries.Where(entry => !entry.IsDirectory);
var processedEntries = 0;
foreach (var entry in totalEntries) var extractor = new SevenZipExtractor(archiveStream);
extractor.Extracting += (_, args) =>
{ {
entry.WriteToDirectory(OutputFolderPath.FullName, new ExtractionOptions() progress.Report(args.PercentDone);
};
extractor.ExtractArchive(outputDirectory.FullName);
outputDirectory.Refresh();
if (!outputDirectory.Exists)
{ {
ExtractFullPath = true, return Result.FromError($"Failed to extract files: {archiveFile.Name}");
Overwrite = true
});
processedEntries++;
if (progress != null)
{
progress.Report(Math.Floor(((double)processedEntries / totalEntries.Count()) * 100));
}
}
OutputFolderPath.Refresh();
if (!OutputFolderPath.Exists)
{
return Result.FromError($"Failed to extract files: {ArchivePath.Name}");
} }
return Result.FromSuccess(); return Result.FromSuccess();

View File

@ -35,7 +35,9 @@ public class DownloadTask : InstallerTaskBase
var mirrorsList = JsonConvert.DeserializeObject<List<DownloadMirror>>(File.ReadAllText(file.FullName)); var mirrorsList = JsonConvert.DeserializeObject<List<DownloadMirror>>(File.ReadAllText(file.FullName));
if (mirrorsList == null) if (mirrorsList == null)
{
return Result.FromError("Failed to deserialize mirrors list"); return Result.FromError("Failed to deserialize mirrors list");
}
foreach (var mirror in mirrorsList) foreach (var mirror in mirrorsList)
{ {
@ -59,7 +61,7 @@ public class DownloadTask : InstallerTaskBase
{ {
SetStatus("Downloading Patcher", "Verifying cached patcher ...", progressStyle: ProgressStyle.Indeterminate); SetStatus("Downloading Patcher", "Verifying cached patcher ...", progressStyle: ProgressStyle.Indeterminate);
if (DownloadCacheHelper.CheckCache("patcher.zip", _expectedPatcherHash, out var cacheFile)) if (DownloadCacheHelper.CheckCache("patcher", _expectedPatcherHash, out var cacheFile))
{ {
_data.PatcherZipInfo = cacheFile; _data.PatcherZipInfo = cacheFile;
Log.Information("Using cached file {fileName} - Hash: {hash}", _data.PatcherZipInfo.Name, _expectedPatcherHash); Log.Information("Using cached file {fileName} - Hash: {hash}", _data.PatcherZipInfo.Name, _expectedPatcherHash);
@ -106,7 +108,7 @@ public class DownloadTask : InstallerTaskBase
SetStatus("Downloading SPT-AKI", _data.AkiReleaseDownloadLink, 0); SetStatus("Downloading SPT-AKI", _data.AkiReleaseDownloadLink, 0);
_data.AkiZipInfo = await DownloadCacheHelper.GetOrDownloadFileAsync("sptaki.zip", _data.AkiReleaseDownloadLink, progress, _data.AkiReleaseHash); _data.AkiZipInfo = await DownloadCacheHelper.GetOrDownloadFileAsync("sptaki", _data.AkiReleaseDownloadLink, progress, _data.AkiReleaseHash);
if (_data.AkiZipInfo == null) if (_data.AkiZipInfo == null)
{ {

View File

@ -7,18 +7,18 @@ using SPTInstaller.Helpers;
namespace SPTInstaller.Installer_Tasks.PreChecks; namespace SPTInstaller.Installer_Tasks.PreChecks;
public class NetCore6PreCheck : PreCheckBase public class Net8PreCheck : PreCheckBase
{ {
public NetCore6PreCheck() : base(".Net Core 6 Desktop Runtime", true) public Net8PreCheck() : base(".Net 8 Desktop Runtime", true)
{ {
} }
public override async Task<PreCheckResult> CheckOperation() public override async Task<PreCheckResult> CheckOperation()
{ {
var minRequiredVersion = new Version("6.0.0"); var minRequiredVersion = new Version("8.0.0");
string[] output; string[] output;
var failedButtonText = "Download .Net Core 6 Desktop Runtime"; var failedButtonText = "Download .Net 8 Desktop Runtime";
var failedButtonAction = () => var failedButtonAction = () =>
{ {
@ -27,7 +27,7 @@ public class NetCore6PreCheck : PreCheckBase
FileName = "cmd.exe", FileName = "cmd.exe",
UseShellExecute = true, UseShellExecute = true,
WindowStyle = ProcessWindowStyle.Hidden, WindowStyle = ProcessWindowStyle.Hidden,
ArgumentList = { "/C", "start", "https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-desktop-6.0.4-windows-x64-installer" } ArgumentList = { "/C", "start", "https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-desktop-8.0.2-windows-x64-installer" }
}); });
}; };
@ -37,7 +37,7 @@ public class NetCore6PreCheck : PreCheckBase
if (!result.Succeeded) if (!result.Succeeded)
{ {
return PreCheckResult.FromError(result.Message + "\n\nYou most likely don't have .net 6 installed", failedButtonText, failedButtonAction); return PreCheckResult.FromError(result.Message + "\n\nYou most likely don't have .net 8 installed", failedButtonText, failedButtonAction);
} }
output = result.StdOut.Split("\r\n"); output = result.StdOut.Split("\r\n");
@ -63,12 +63,12 @@ public class NetCore6PreCheck : PreCheckBase
if (foundVersion >= minRequiredVersion) if (foundVersion >= minRequiredVersion)
{ {
return PreCheckResult.FromSuccess($".Net Core {minRequiredVersion} Desktop Runtime or higher is installed.\n\nInstalled Version: {foundVersion}"); return PreCheckResult.FromSuccess($".Net {minRequiredVersion} Desktop Runtime or higher is installed.\n\nInstalled Version: {foundVersion}");
} }
highestFoundVersion = foundVersion > highestFoundVersion ? foundVersion : highestFoundVersion; highestFoundVersion = foundVersion > highestFoundVersion ? foundVersion : highestFoundVersion;
} }
return PreCheckResult.FromError($".Net Core Desktop Runtime version {minRequiredVersion} or higher is required.\n\nHighest Version Found: {(highestFoundVersion > new Version("0.0.0") ? highestFoundVersion : "Not Found")}\n\nThis is required to play SPT, but you can install it later if and shouldn't affect the SPT install process.", failedButtonText, failedButtonAction); return PreCheckResult.FromError($".Net Desktop Runtime version {minRequiredVersion} or higher is required.\n\nHighest Version Found: {(highestFoundVersion > new Version("0.0.0") ? highestFoundVersion : "Not Found")}\n\nThis is required to play SPT", failedButtonText, failedButtonAction);
} }
} }

View File

@ -28,6 +28,13 @@ public class SetupClientTask : InstallerTaskBase
if (_data.PatchNeeded) if (_data.PatchNeeded)
{ {
SetStatus("Preparing 7z", "", null, ProgressStyle.Indeterminate);
if (!FileHelper.StreamAssemblyResourceOut("7z.dll", Path.Join(DownloadCacheHelper.CachePath, "7z.dll")))
{
return Result.FromError("Failed to prepare 7z");
}
// extract patcher files // extract patcher files
SetStatus("Extrating Patcher", "", 0); SetStatus("Extrating Patcher", "", 0);

View File

@ -61,7 +61,12 @@ public class InstallerUpdateInfo : ReactiveObject
UpdateAvailable = false; UpdateAvailable = false;
var updater = new FileInfo(Path.Join(DownloadCacheHelper.CachePath, "update.ps1")); var updater = new FileInfo(Path.Join(DownloadCacheHelper.CachePath, "update.ps1"));
FileHelper.StreamAssemblyResourceOut("update.ps1", updater.FullName);
if (!FileHelper.StreamAssemblyResourceOut("update.ps1", updater.FullName))
{
Log.Fatal("Failed to prepare update file");
return;
}
if (!updater.Exists) if (!updater.Exists)

View File

@ -10,7 +10,7 @@ public class HttpMirrorDownloader : MirrorDownloaderBase
public override async Task<FileInfo?> Download(IProgress<double> progress) public override async Task<FileInfo?> Download(IProgress<double> progress)
{ {
var file = await DownloadCacheHelper.DownloadFileAsync("patcher.zip", MirrorInfo.Link, progress); var file = await DownloadCacheHelper.DownloadFileAsync("patcher", MirrorInfo.Link, progress);
if (file == null) if (file == null)
return null; return null;

View File

@ -23,7 +23,7 @@ public class MegaMirrorDownloader : MirrorDownloaderBase
{ {
using var megaDownloadStream = await megaClient.DownloadAsync(new Uri(MirrorInfo.Link), progress); using var megaDownloadStream = await megaClient.DownloadAsync(new Uri(MirrorInfo.Link), progress);
var file = await DownloadCacheHelper.DownloadFileAsync("patcher.zip", megaDownloadStream); var file = await DownloadCacheHelper.DownloadFileAsync("patcher", megaDownloadStream);
if (file == null) if (file == null)
return null; return null;

View File

@ -44,7 +44,7 @@ internal class Program
#if !TEST #if !TEST
ServiceHelper.Register<PreCheckBase, NetFramework472PreCheck>(); ServiceHelper.Register<PreCheckBase, NetFramework472PreCheck>();
ServiceHelper.Register<PreCheckBase, NetCore6PreCheck>(); ServiceHelper.Register<PreCheckBase, Net8PreCheck>();
ServiceHelper.Register<PreCheckBase, FreeSpacePreCheck>(); ServiceHelper.Register<PreCheckBase, FreeSpacePreCheck>();
ServiceHelper.Register<PreCheckBase, EftLauncherPreCheck>(); ServiceHelper.Register<PreCheckBase, EftLauncherPreCheck>();

Binary file not shown.

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract> <IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport> <BuiltInComInteropSupport>true</BuiltInComInteropSupport>
@ -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.33</AssemblyVersion> <AssemblyVersion>2.42</AssemblyVersion>
<FileVersion>2.33</FileVersion> <FileVersion>2.42</FileVersion>
<Company>SPT-AKI</Company> <Company>SPT-AKI</Company>
</PropertyGroup> </PropertyGroup>
@ -23,6 +23,8 @@
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Resources\update.ps1" /> <EmbeddedResource Include="Resources\update.ps1" />
<None Remove="Resources\7z.dll" />
<EmbeddedResource Include="Resources\7z.dll" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -42,7 +44,7 @@
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="SerilogTraceListener" Version="3.2.0" /> <PackageReference Include="SerilogTraceListener" Version="3.2.0" />
<PackageReference Include="SharpCompress" Version="0.34.0" /> <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>