Add global using directives and free space pre-check

Global System and System.IO usages have been replaced with global usings in GlobalUsings.cs for improved code readability. Alongside, a FreeSpacePreCheck has been added in FreeSpacePreCheck.cs to ensure enough drive space is available before installation. This check was initially taking place in InitializationTask.cs which has been removed for better separation of concerns. The PreCheckViewModel visibility is now dependent on the success status of PreChecks, enhancing user experience.
This commit is contained in:
Philipp Heenemann 2023-07-12 08:32:57 +02:00
parent 68e50cf5e5
commit d3767a0344
8 changed files with 90 additions and 97 deletions

View File

@ -0,0 +1,3 @@
// Global using directives
global using System;
global using System.IO;

View File

@ -1,46 +1,29 @@
using System;
using System.IO;
using System.Linq;
using System.Linq;
using Serilog;
using SPTInstaller.Models;
namespace SPTInstaller.Helpers
namespace SPTInstaller.Helpers;
public static class DirectorySizeHelper
{
public static class DirectorySizeHelper
public static bool CheckAvailableSize(string eftSourceDirPath, string installTargetDirPath)
{
public static Result CheckAvailableSize(string eftSourceDirPath, string installTargetDirPath)
try
{
try
{
var eftSourceDirectoryInfo = new DirectoryInfo(eftSourceDirPath);
var installTargetDirectoryInfo = new DirectoryInfo(installTargetDirPath);
var eftSourceDirectoryInfo = new DirectoryInfo(eftSourceDirPath);
var installTargetDirectoryInfo = new DirectoryInfo(installTargetDirPath);
var eftSourceDirSize = GetSizeOfDirectory(eftSourceDirectoryInfo);
var availableSize = DriveInfo.GetDrives().FirstOrDefault(d => d.Name == installTargetDirectoryInfo.Root.Name)?.AvailableFreeSpace ?? 0;
var eftSourceDirSize = GetSizeOfDirectory(eftSourceDirectoryInfo);
var availableSize = DriveInfo.GetDrives().FirstOrDefault(d => d.Name == installTargetDirectoryInfo.Root.Name)?.AvailableFreeSpace ?? 0;
if (eftSourceDirSize > availableSize)
{
return Result.FromError($"Not enough space on drive {installTargetDirectoryInfo.Root.Name}.\n\nRequired: {FormatFileSize(eftSourceDirSize)}\nAvailable: {FormatFileSize(availableSize)}");
}
return Result.FromSuccess();
}
catch (Exception ex)
{
Log.Error(ex, "Error while checking available size");
return Result.FromError(ex.Message);
}
return eftSourceDirSize < availableSize;
}
private static long GetSizeOfDirectory(DirectoryInfo sourceDir) => sourceDir.EnumerateFiles("*", SearchOption.AllDirectories).Sum(fi => fi.Length);
private static string FormatFileSize(long bytes)
catch (Exception ex)
{
const int unit = 1024;
var exp = (int)(Math.Log(bytes) / Math.Log(unit));
Log.Error(ex, "Error while checking available size");
return $"{bytes / Math.Pow(unit, exp):F2} {"KMGTPE"[exp - 1]}B";
return false;
}
}
private static long GetSizeOfDirectory(DirectoryInfo sourceDir) => sourceDir.EnumerateFiles("*", SearchOption.AllDirectories).Sum(fi => fi.Length);
}

View File

@ -2,7 +2,6 @@
using SPTInstaller.Interfaces;
using SPTInstaller.Models;
using System.Threading.Tasks;
using SPTInstaller.Helpers;
namespace SPTInstaller.Installer_Tasks
{
@ -28,12 +27,6 @@ namespace SPTInstaller.Installer_Tasks
SetStatus(null, $"Installed EFT Game Path: {FileHelper.GetRedactedPath(_data.OriginalGamePath)}");
var directorySizeCheckResult = DirectorySizeHelper.CheckAvailableSize(_data.OriginalGamePath, _data.TargetInstallPath);
if (!directorySizeCheckResult.Succeeded)
{
return Result.FromError(directorySizeCheckResult.Message);
}
var result = PreCheckHelper.DetectOriginalGameVersion(_data.OriginalGamePath);
if (!result.Succeeded)

View File

@ -0,0 +1,25 @@
using System.Threading.Tasks;
using SPTInstaller.Helpers;
using SPTInstaller.Models;
namespace SPTInstaller.Installer_Tasks.PreChecks;
public class FreeSpacePreCheck : PreCheckBase
{
private readonly InternalData _internalData;
public FreeSpacePreCheck(InternalData internalData) : base("Free Space", true)
{
_internalData = internalData;
}
public override async Task<bool> CheckOperation()
{
if (_internalData.OriginalGamePath is null || _internalData.TargetInstallPath is null)
{
return false;
}
return DirectorySizeHelper.CheckAvailableSize(_internalData.OriginalGamePath, _internalData.TargetInstallPath);
}
}

View File

@ -8,12 +8,12 @@ namespace SPTInstaller.Models
/// <summary>
/// The folder to install SPT into
/// </summary>
public string TargetInstallPath { get; set; }
public string? TargetInstallPath { get; set; }
/// <summary>
/// The orginal EFT game path
/// </summary>
public string OriginalGamePath { get; set; }
public string? OriginalGamePath { get; set; }
/// <summary>
/// The original EFT game version

View File

@ -9,8 +9,6 @@ using SPTInstaller.Installer_Tasks;
using SPTInstaller.Installer_Tasks.PreChecks;
using SPTInstaller.Interfaces;
using SPTInstaller.Models;
using System;
using System.IO;
using System.Linq;
using System.Reflection;
@ -35,8 +33,9 @@ namespace SPTInstaller
ServiceHelper.Register<InternalData>();
ServiceHelper.Register<PreCheckBase, NetFramework472PreCheck>();
ServiceHelper.Register<PreCheckBase, NetCore6PreCheck>();
ServiceHelper.Register<PreCheckBase, FreeSpacePreCheck>();
#if !TEST
string logPath = Path.Join(Environment.CurrentDirectory, "spt-aki-installer_.log");
var logPath = Path.Join(Environment.CurrentDirectory, "spt-aki-installer_.log");
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()

View File

@ -1,59 +1,48 @@
using ReactiveUI;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Windows.Input;
using ReactiveUI;
using SPTInstaller.Aki.Helper;
using SPTInstaller.Controllers;
using SPTInstaller.Helpers;
using SPTInstaller.Models;
using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Windows.Input;
namespace SPTInstaller.ViewModels
namespace SPTInstaller.ViewModels;
public class PreChecksViewModel : ViewModelBase
{
public class PreChecksViewModel : ViewModelBase
private string _installPath;
public ObservableCollection<PreCheckBase> PreChecks { get; set; } = new(ServiceHelper.GetAll<PreCheckBase>());
public ICommand StartInstallCommand { get; set; }
public bool PreCheckSucceeded { get; set; }
public string InstallPath
{
private string _InstallPath;
public string InstallPath
get => _installPath;
set => this.RaiseAndSetIfChanged(ref _installPath, value);
}
public PreChecksViewModel(IScreen host) : base(host)
{
var data = ServiceHelper.Get<InternalData?>();
var installer = ServiceHelper.Get<InstallController?>();
if (data == null || installer == null)
{
get => _InstallPath;
set => this.RaiseAndSetIfChanged(ref _InstallPath, value);
NavigateTo(new MessageViewModel(HostScreen, Result.FromError("Failed to get required service for prechecks")));
return;
}
ObservableCollection<PreCheckBase> PreChecks { get; set; }
= new ObservableCollection<PreCheckBase>(ServiceHelper.GetAll<PreCheckBase>());
data.OriginalGamePath = PreCheckHelper.DetectOriginalGamePath();
data.TargetInstallPath = Environment.CurrentDirectory;
InstallPath = data.TargetInstallPath;
ICommand StartInstallCommand { get; set; }
StartInstallCommand = ReactiveCommand.Create(() => NavigateTo(new InstallViewModel(HostScreen)));
public PreChecksViewModel(IScreen host) : base(host)
Task.Run(async () =>
{
var data = ServiceHelper.Get<InternalData>();
var installer = ServiceHelper.Get<InstallController>();
if(data == null || installer == null)
{
NavigateTo(new MessageViewModel(HostScreen, Result.FromError("Failed to get required service for prechecks")));
return;
}
data.TargetInstallPath = Environment.CurrentDirectory;
InstallPath = data.TargetInstallPath;
StartInstallCommand = ReactiveCommand.Create(() =>
{
NavigateTo(new InstallViewModel(HostScreen));
});
Task.Run(async () =>
{
var result = await installer.RunPreChecks();
if(!result.Succeeded)
{
//if a required precheck fails, abort to message view
NavigateTo(new MessageViewModel(HostScreen ,result));
}
});
}
var result = await installer.RunPreChecks();
PreCheckSucceeded = result.Succeeded;
});
}
}

View File

@ -23,6 +23,7 @@
Margin="10"
FontSize="15" FontWeight="SemiBold"
Classes="yellow"
IsVisible="{Binding PreCheckSucceeded}"
Command="{Binding StartInstallCommand}"
/>