Don't block the UI so much during install

This commit is contained in:
Timothy Baldridge 2022-05-16 23:26:59 -06:00
parent 28c0224af5
commit 83cf5a3436
6 changed files with 77 additions and 49 deletions

View File

@ -7,6 +7,7 @@ using System.Reactive.Subjects;
using System.Timers;
using DynamicData;
using DynamicData.Kernel;
using Microsoft.Extensions.Logging;
using ReactiveUI;
using Wabbajack.RateLimiter;
@ -14,7 +15,7 @@ namespace Wabbajack.Models;
public class ResourceMonitor : IDisposable
{
private readonly TimeSpan PollInterval = TimeSpan.FromMilliseconds(1000);
private readonly TimeSpan PollInterval = TimeSpan.FromMilliseconds(250);
private readonly IResource[] _resources;
private readonly Timer _timer;
@ -27,13 +28,15 @@ public class ResourceMonitor : IDisposable
private readonly SourceCache<CPUDisplayVM, ulong> _tasks = new(x => x.ID);
public readonly ReadOnlyObservableCollection<CPUDisplayVM> _tasksFiltered;
private readonly CompositeDisposable _compositeDisposable;
private readonly ILogger<ResourceMonitor> _logger;
public ReadOnlyObservableCollection<CPUDisplayVM> Tasks => _tasksFiltered;
public ResourceMonitor(IEnumerable<IResource> resources)
public ResourceMonitor(ILogger<ResourceMonitor> logger, IEnumerable<IResource> resources)
{
_logger = logger;
_compositeDisposable = new CompositeDisposable();
_resources = resources.ToArray();
_prev = _resources.Select(x => (x.Name, (long)0)).ToArray();
@ -42,6 +45,7 @@ public class ResourceMonitor : IDisposable
.DisposeWith(_compositeDisposable);
_tasks.Connect()
.Filter(t => t.IsWorking)
.Bind(out _tasksFiltered)
.Subscribe()
.DisposeWith(_compositeDisposable);
@ -61,6 +65,7 @@ public class ResourceMonitor : IDisposable
var used = new HashSet<ulong>();
foreach (var resource in _resources)
{
_logger.LogInformation("Resource {Name}: {Jobs}", resource.Name, resource.Jobs.Count());
foreach (var job in resource.Jobs)
{
used.Add(job.ID);
@ -71,6 +76,7 @@ public class ResourceMonitor : IDisposable
var t = tsk.Value;
t.Msg = job.Description;
t.ProgressPercent = job.Size == 0 ? Percent.Zero : Percent.FactoryPutInRange(job.Current, (long)job.Size);
t.IsWorking = job.Current > 0;
}
// Create
@ -81,7 +87,8 @@ public class ResourceMonitor : IDisposable
ID = job.ID,
StartTime = DateTime.Now,
Msg = job.Description,
ProgressPercent = job.Size == 0 ? Percent.Zero : Percent.FactoryPutInRange(job.Current, (long) job.Size)
ProgressPercent = job.Size == 0 ? Percent.Zero : Percent.FactoryPutInRange(job.Current, (long) job.Size),
IsWorking = job.Current > 0,
};
l.AddOrUpdate(vm);
}

View File

@ -272,57 +272,61 @@ public class InstallerVM : BackNavigatingVM, IBackNavigatingVM, ICpuStatusVM
private async Task BeginInstall()
{
InstallState = InstallState.Installing;
var postfix = (await ModListLocation.TargetPath.ToString().Hash()).ToHex();
await _settingsManager.Save(InstallSettingsPrefix + postfix, new SavedInstallSettings
await Task.Run(async () =>
{
ModListLocation = ModListLocation.TargetPath,
InstallLocation = Installer.Location.TargetPath,
DownloadLoadction = Installer.DownloadLocation.TargetPath,
Metadata = ModlistMetadata
});
try
{
var installer = StandardInstaller.Create(_serviceProvider, new InstallerConfiguration
InstallState = InstallState.Installing;
var postfix = (await ModListLocation.TargetPath.ToString().Hash()).ToHex();
await _settingsManager.Save(InstallSettingsPrefix + postfix, new SavedInstallSettings
{
Game = ModList.GameType,
Downloads = Installer.DownloadLocation.TargetPath,
Install = Installer.Location.TargetPath,
ModList = ModList,
ModlistArchive = ModListLocation.TargetPath,
SystemParameters = _parametersConstructor.Create(),
GameFolder = _gameLocator.GameLocation(ModList.GameType)
ModListLocation = ModListLocation.TargetPath,
InstallLocation = Installer.Location.TargetPath,
DownloadLoadction = Installer.DownloadLocation.TargetPath,
Metadata = ModlistMetadata
});
installer.OnStatusUpdate = update =>
try
{
StatusText = update.StatusText;
StatusProgress = update.StepsProgress;
var installer = StandardInstaller.Create(_serviceProvider, new InstallerConfiguration
{
Game = ModList.GameType,
Downloads = Installer.DownloadLocation.TargetPath,
Install = Installer.Location.TargetPath,
ModList = ModList,
ModlistArchive = ModListLocation.TargetPath,
SystemParameters = _parametersConstructor.Create(),
GameFolder = _gameLocator.GameLocation(ModList.GameType)
});
TaskBarUpdate.Send(update.StatusText, TaskbarItemProgressState.Indeterminate, update.StepsProgress.Value);
};
if (!await installer.Begin(CancellationToken.None))
installer.OnStatusUpdate = update =>
{
StatusText = update.StatusText;
StatusProgress = update.StepsProgress;
TaskBarUpdate.Send(update.StatusText, TaskbarItemProgressState.Indeterminate,
update.StepsProgress.Value);
};
if (!await installer.Begin(CancellationToken.None))
{
TaskBarUpdate.Send($"Error during install of {ModList.Name}", TaskbarItemProgressState.Error);
InstallState = InstallState.Failure;
StatusText = $"Error during install of {ModList.Name}";
StatusProgress = Percent.Zero;
}
else
{
TaskBarUpdate.Send($"Finished install of {ModList.Name}", TaskbarItemProgressState.Normal);
InstallState = InstallState.Success;
}
}
catch (Exception ex)
{
TaskBarUpdate.Send($"Error during install of {ModList.Name}", TaskbarItemProgressState.Error);
InstallState = InstallState.Failure;
StatusText = $"Error during install of {ModList.Name}";
StatusProgress = Percent.Zero;
}
else
{
TaskBarUpdate.Send($"Finished install of {ModList.Name}", TaskbarItemProgressState.Normal);
InstallState = InstallState.Success;
}
}
catch (Exception ex)
{
TaskBarUpdate.Send($"Error during install of {ModList.Name}", TaskbarItemProgressState.Error);
InstallState = InstallState.Failure;
StatusText = $"Error during install of {ModList.Name}";
StatusProgress = Percent.Zero;
}
});
}

View File

@ -47,9 +47,12 @@ namespace Wabbajack
MessageBus.Current.Listen<TaskBarUpdate>()
.Subscribe(u =>
{
TaskbarItemInfo.Description = u.Description;
TaskbarItemInfo.ProgressValue = u.ProgressValue;
TaskbarItemInfo.ProgressState = u.State;
Dispatcher.Invoke(() =>
{
TaskbarItemInfo.Description = u.Description;
TaskbarItemInfo.ProgressValue = u.ProgressValue;
TaskbarItemInfo.ProgressState = u.State;
});
});
MessageBus.Current.Listen<OpenBrowserTab>()

View File

@ -62,14 +62,18 @@ public abstract class AInstaller<T>
private readonly Stopwatch _updateStopWatch = new();
public Action<StatusUpdate>? OnStatusUpdate;
private readonly IResource<IInstaller> _limiter;
public AInstaller(ILogger<T> logger, InstallerConfiguration config, IGameLocator gameLocator,
FileExtractor.FileExtractor extractor,
DTOSerializer jsonSerializer, Context vfs, FileHashCache fileHashCache,
DownloadDispatcher downloadDispatcher,
ParallelOptions parallelOptions, Client wjClient)
ParallelOptions parallelOptions,
IResource<IInstaller> limiter,
Client wjClient)
{
_limiter = limiter;
_manager = new TemporaryFileManager(config.Install.Combine("__temp__"));
ExtractedModlistFolder = _manager.CreateFolder();
_configuration = config;
@ -210,9 +214,12 @@ public abstract class AInstaller<T>
if (grouped.Count == 0) return;
await _vfs.Extract(grouped.Keys.ToHashSet(), async (vf, sf) =>
{
foreach (var directive in grouped[vf])
var directives = grouped[vf];
using var job = await _limiter.Begin($"Installing files from {vf.Name}", directives.Sum(f => f.VF.Size), token);
foreach (var directive in directives)
{
var file = directive.Directive;
UpdateProgress(file.Size);
@ -260,6 +267,8 @@ public abstract class AInstaller<T>
default:
throw new Exception($"No handler for {directive}");
}
await job.Report((int)directive.VF.Size, token);
}
}, token);
}

View File

@ -26,6 +26,7 @@ using Wabbajack.Installer.Utilities;
using Wabbajack.Networking.WabbajackClientApi;
using Wabbajack.Paths;
using Wabbajack.Paths.IO;
using Wabbajack.RateLimiter;
using Wabbajack.VFS;
namespace Wabbajack.Installer;
@ -38,9 +39,9 @@ public class StandardInstaller : AInstaller<StandardInstaller>
InstallerConfiguration config,
IGameLocator gameLocator, FileExtractor.FileExtractor extractor,
DTOSerializer jsonSerializer, Context vfs, FileHashCache fileHashCache,
DownloadDispatcher downloadDispatcher, ParallelOptions parallelOptions, Client wjClient) :
DownloadDispatcher downloadDispatcher, ParallelOptions parallelOptions, IResource<IInstaller> limiter, Client wjClient) :
base(logger, config, gameLocator, extractor, jsonSerializer, vfs, fileHashCache, downloadDispatcher,
parallelOptions, wjClient)
parallelOptions, limiter, wjClient)
{
MaxSteps = 14;
}
@ -56,6 +57,7 @@ public class StandardInstaller : AInstaller<StandardInstaller>
provider.GetRequiredService<FileHashCache>(),
provider.GetRequiredService<DownloadDispatcher>(),
provider.GetRequiredService<ParallelOptions>(),
provider.GetRequiredService<IResource<IInstaller>>(),
provider.GetRequiredService<Client>());
}

View File

@ -96,6 +96,9 @@ public static class ServiceExtensions
service.AddAllSingleton<IResource, IResource<ACompiler>>(s =>
new Resource<ACompiler>("Compiler", GetSettings(s, "Compiler")));
service.AddAllSingleton<IResource, IResource<IInstaller>>(s =>
new Resource<IInstaller>("Installer", GetSettings(s, "Installer")));
service.AddSingleton<LoggingRateLimiterReporter>();