diff --git a/Wabbajack.App.Wpf/Models/LoggerProvider.cs b/Wabbajack.App.Wpf/Models/LoggerProvider.cs index d2fc7a4a..dd8b5ec3 100644 --- a/Wabbajack.App.Wpf/Models/LoggerProvider.cs +++ b/Wabbajack.App.Wpf/Models/LoggerProvider.cs @@ -38,7 +38,9 @@ public class LoggerProvider : ILoggerProvider _disposables = new CompositeDisposable(); - Messages.Subscribe(m => _messageLog.AddOrUpdate(m)) + Messages + .ObserveOnGuiThread() + .Subscribe(m => _messageLog.AddOrUpdate(m)) .DisposeWith(_disposables); Messages.Subscribe(m => LogToFile(m)) diff --git a/Wabbajack.App.Wpf/Models/ResourceMonitor.cs b/Wabbajack.App.Wpf/Models/ResourceMonitor.cs index 5c3e5d09..b71ea529 100644 --- a/Wabbajack.App.Wpf/Models/ResourceMonitor.cs +++ b/Wabbajack.App.Wpf/Models/ResourceMonitor.cs @@ -7,12 +7,15 @@ using System.Reactive.Subjects; using System.Timers; using DynamicData; using DynamicData.Kernel; +using ReactiveUI; using Wabbajack.RateLimiter; namespace Wabbajack.Models; public class ResourceMonitor : IDisposable { + private readonly TimeSpan PollInterval = TimeSpan.FromMilliseconds(1000); + private readonly IResource[] _resources; private readonly Timer _timer; @@ -33,30 +36,26 @@ public class ResourceMonitor : IDisposable { _compositeDisposable = new CompositeDisposable(); _resources = resources.ToArray(); - _timer = new Timer(); - _timer.Interval = 250; - _timer.Elapsed += Elapsed; - _timer.Enabled = true; - - _timer.DisposeWith(_compositeDisposable); - _prev = _resources.Select(x => (x.Name, (long)0)).ToArray(); - + + RxApp.MainThreadScheduler.ScheduleRecurringAction(PollInterval, Elapsed) + .DisposeWith(_compositeDisposable); + _tasks.Connect() .Bind(out _tasksFiltered) .Subscribe() .DisposeWith(_compositeDisposable); } - private void Elapsed(object? sender, ElapsedEventArgs e) + private void Elapsed() { var current = _resources.Select(x => (x.Name, x.StatusReport.Transferred)).ToArray(); var diff = _prev.Zip(current) - .Select(t => (t.First.Name, (long)((t.Second.Transferred - t.First.Throughput) / (_timer.Interval / 1000.0)))) + .Select(t => (t.First.Name, (long)((t.Second.Transferred - t.First.Throughput) / PollInterval.TotalSeconds))) .ToArray(); _prev = current; _updates.OnNext(diff); - + _tasks.Edit(l => { var used = new HashSet(); @@ -71,7 +70,7 @@ public class ResourceMonitor : IDisposable { var t = tsk.Value; t.Msg = job.Description; - t.ProgressPercent = Percent.FactoryPutInRange(job.Current, (long)job.Size); + t.ProgressPercent = job.Size == 0 ? Percent.Zero : Percent.FactoryPutInRange(job.Current, (long)job.Size); } // Create @@ -82,7 +81,7 @@ public class ResourceMonitor : IDisposable ID = job.ID, StartTime = DateTime.Now, Msg = job.Description, - ProgressPercent = Percent.FactoryPutInRange(job.Current, (long) job.Size) + ProgressPercent = job.Size == 0 ? Percent.Zero : Percent.FactoryPutInRange(job.Current, (long) job.Size) }; l.AddOrUpdate(vm); } diff --git a/Wabbajack.App.Wpf/View Models/Compilers/CompilerVM.cs b/Wabbajack.App.Wpf/View Models/Compilers/CompilerVM.cs index 37b89368..038a1b6b 100644 --- a/Wabbajack.App.Wpf/View Models/Compilers/CompilerVM.cs +++ b/Wabbajack.App.Wpf/View Models/Compilers/CompilerVM.cs @@ -29,6 +29,7 @@ using Wabbajack.DTOs; using Wabbajack.DTOs.Interventions; using Wabbajack.DTOs.JsonConverters; using Wabbajack.Installer; +using Wabbajack.Models; using Wabbajack.Networking.WabbajackClientApi; using Wabbajack.Paths; using Wabbajack.Paths.IO; @@ -46,12 +47,14 @@ namespace Wabbajack Completed, Errored } - public class CompilerVM : BackNavigatingVM + public class CompilerVM : BackNavigatingVM, ICpuStatusVM { private const string LastSavedCompilerSettings = "last-saved-compiler-settings"; private readonly DTOSerializer _dtos; private readonly SettingsManager _settingsManager; - private readonly ServiceProvider _serviceProvider; + private readonly IServiceProvider _serviceProvider; + private readonly ILogger _logger; + private readonly ResourceMonitor _resourceMonitor; [Reactive] public CompilerState State { get; set; } @@ -91,13 +94,19 @@ namespace Wabbajack public ReactiveCommand ExecuteCommand { get; } + + public LoggerProvider LoggerProvider { get; } + public ReadOnlyObservableCollection StatusList => _resourceMonitor.Tasks; public CompilerVM(ILogger logger, DTOSerializer dtos, SettingsManager settingsManager, - ServiceProvider serviceProvider) : base(logger) + IServiceProvider serviceProvider, LoggerProvider loggerProvider, ResourceMonitor resourceMonitor) : base(logger) { + _logger = logger; _dtos = dtos; _settingsManager = settingsManager; _serviceProvider = serviceProvider; + LoggerProvider = loggerProvider; + _resourceMonitor = resourceMonitor; BackCommand = ReactiveCommand.CreateFromTask(async () => @@ -216,46 +225,52 @@ namespace Wabbajack private async Task StartCompilation() { - try + var tsk = Task.Run(async () => { - State = CompilerState.Compiling; - var mo2Settings = new MO2CompilerSettings + try { - ModListName = ModListName, - ModListAuthor = Author, - ModlistReadme = Readme, - Source = Source, - Downloads = DownloadLocation.TargetPath, - OutputFile = OutputLocation.TargetPath, - Profile = SelectedProfile, - OtherProfiles = OtherProfiles, - AlwaysEnabled = AlwaysEnabled - }; + State = CompilerState.Compiling; - var compiler = new MO2Compiler(_serviceProvider.GetRequiredService>(), - _serviceProvider.GetRequiredService(), - _serviceProvider.GetRequiredService(), - _serviceProvider.GetRequiredService(), - _serviceProvider.GetRequiredService(), - mo2Settings, - _serviceProvider.GetRequiredService(), - _serviceProvider.GetRequiredService(), - _serviceProvider.GetRequiredService(), - _serviceProvider.GetRequiredService(), - _serviceProvider.GetRequiredService(), - _serviceProvider.GetRequiredService>(), - _serviceProvider.GetRequiredService()); - - await compiler.Begin(CancellationToken.None); + var mo2Settings = new MO2CompilerSettings + { + Game = BaseGame, + ModListName = ModListName, + ModListAuthor = Author, + ModlistReadme = Readme, + Source = Source, + Downloads = DownloadLocation.TargetPath, + OutputFile = OutputLocation.TargetPath, + Profile = SelectedProfile, + OtherProfiles = OtherProfiles, + AlwaysEnabled = AlwaysEnabled + }; - State = CompilerState.Completed; - } - catch (Exception ex) - { - State = CompilerState.Errored; - } + var compiler = new MO2Compiler(_serviceProvider.GetRequiredService>(), + _serviceProvider.GetRequiredService(), + _serviceProvider.GetRequiredService(), + _serviceProvider.GetRequiredService(), + _serviceProvider.GetRequiredService(), + mo2Settings, + _serviceProvider.GetRequiredService(), + _serviceProvider.GetRequiredService(), + _serviceProvider.GetRequiredService(), + _serviceProvider.GetRequiredService(), + _serviceProvider.GetRequiredService(), + _serviceProvider.GetRequiredService>(), + _serviceProvider.GetRequiredService()); + await compiler.Begin(CancellationToken.None); + State = CompilerState.Completed; + } + catch (Exception ex) + { + State = CompilerState.Errored; + _logger.LogInformation(ex, "Failed Compilation : {Message}", ex.Message); + } + }); + + await tsk; } private async Task SaveSettingsFile() diff --git a/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs b/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs index 55892f80..c6fcc54d 100644 --- a/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs +++ b/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs @@ -2,40 +2,28 @@ using System.Collections.ObjectModel; using ReactiveUI; using System.Reactive.Disposables; -using System.Reactive.Linq; using System.Windows.Media.Imaging; using ReactiveUI.Fody.Helpers; -using System.Windows.Media; using DynamicData; -using DynamicData.Binding; using System.Reactive; -using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Shell; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.WindowsAPICodePack.Dialogs; -using Microsoft.WindowsAPICodePack.Shell; using Wabbajack.Common; using Wabbajack.Downloaders.GameFile; using Wabbajack.DTOs; using Wabbajack.DTOs.JsonConverters; -using Wabbajack.Extensions; using Wabbajack.Hashing.xxHash64; using Wabbajack.Installer; -using Wabbajack.Interventions; using Wabbajack.Messages; using Wabbajack.Models; using Wabbajack.Paths; using Wabbajack.RateLimiter; -using Wabbajack.View_Models; using Wabbajack.Paths.IO; using Wabbajack.Services.OSIntegrated; using Wabbajack.Util; -using Configuration = Wabbajack.Networking.WabbajackClientApi.Configuration; -using Consts = Wabbajack.Consts; -using KnownFolders = Wabbajack.Paths.IO.KnownFolders; namespace Wabbajack; @@ -118,8 +106,7 @@ public class InstallerVM : BackNavigatingVM, IBackNavigatingVM, ICpuStatusVM [Reactive] public bool Installing { get; set; } - [Reactive] - public LoggerProvider LoggerProvider { get; set; } + public LoggerProvider LoggerProvider { get; } // Command properties diff --git a/Wabbajack.App.Wpf/Views/Compilers/CompilerView.xaml.cs b/Wabbajack.App.Wpf/Views/Compilers/CompilerView.xaml.cs index c9734f53..b7e6c115 100644 --- a/Wabbajack.App.Wpf/Views/Compilers/CompilerView.xaml.cs +++ b/Wabbajack.App.Wpf/Views/Compilers/CompilerView.xaml.cs @@ -22,7 +22,8 @@ namespace Wabbajack { - this.BindCommand(ViewModel, vm => vm.ExecuteCommand, view => view.BeginButton) + ViewModel.WhenAnyValue(vm => vm.ExecuteCommand) + .BindToStrict(this, view => view.BeginButton.Command) .DisposeWith(disposables); ViewModel.WhenAnyValue(vm => vm.BackCommand) diff --git a/Wabbajack.VFS/FileHashCache.cs b/Wabbajack.VFS/FileHashCache.cs index b780eea2..b9fdb680 100644 --- a/Wabbajack.VFS/FileHashCache.cs +++ b/Wabbajack.VFS/FileHashCache.cs @@ -118,7 +118,7 @@ public class FileHashCache { if (TryGetHashCache(file, out var foundHash)) return foundHash; - using var job = await _limiter.Begin($"Hasing {file.FileName}", file.Size(), token); + using var job = await _limiter.Begin($"Hashing {file.FileName}", file.Size(), token); await using var fs = file.Open(FileMode.Open, FileAccess.Read, FileShare.Read); var hash = await fs.HashingCopy(Stream.Null, token, job);