From a290996037cc8602171afd1d63e90d30f6327c47 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Sun, 27 Jul 2025 12:16:39 +0100 Subject: [PATCH] [Blazor] Move importing DAT to single thread. Does not take so much longer, but UX is much improved. --- .../Components/Dialogs/ImportDats.razor | 17 +- .../Components/Dialogs/ImportDats.razor.cs | 161 +++++++++++++----- 2 files changed, 130 insertions(+), 48 deletions(-) diff --git a/RomRepoMgr.Blazor/Components/Dialogs/ImportDats.razor b/RomRepoMgr.Blazor/Components/Dialogs/ImportDats.razor index 6a912b3..c33ee86 100644 --- a/RomRepoMgr.Blazor/Components/Dialogs/ImportDats.razor +++ b/RomRepoMgr.Blazor/Components/Dialogs/ImportDats.razor @@ -3,13 +3,22 @@ - - @StatusMessage - +
+ + @StatusMessage + +
+ @if(Progress2Visible) + { +
+

@StatusMessage2

+ +
+ }
- Start + Start Close diff --git a/RomRepoMgr.Blazor/Components/Dialogs/ImportDats.razor.cs b/RomRepoMgr.Blazor/Components/Dialogs/ImportDats.razor.cs index b6ab5e3..a9761eb 100644 --- a/RomRepoMgr.Blazor/Components/Dialogs/ImportDats.razor.cs +++ b/RomRepoMgr.Blazor/Components/Dialogs/ImportDats.razor.cs @@ -1,9 +1,11 @@ using System.Diagnostics; using Microsoft.AspNetCore.Components; using Microsoft.FluentUI.AspNetCore.Components; +using RomRepoMgr.Core.EventArgs; using RomRepoMgr.Core.Workers; using Serilog; using Serilog.Extensions.Logging; +using ErrorEventArgs = RomRepoMgr.Core.EventArgs.ErrorEventArgs; namespace RomRepoMgr.Blazor.Components.Dialogs; @@ -17,27 +19,34 @@ public partial class ImportDats : ComponentBase public string StatusMessage { get; set; } public bool IsBusy { get; set; } [CascadingParameter] - public FluentDialog Dialog { get; set; } - public int? ProgressMax { get; set; } - public int? ProgressMin { get; set; } - public int? ProgressValue { get; set; } - public bool CannotClose { get; set; } - public bool ProgressVisible { get; set; } - public Color? StatusColor { get; set; } + public FluentDialog Dialog { get; set; } + public int? ProgressMax { get; set; } + public int? ProgressMin { get; set; } + public int? ProgressValue { get; set; } + public bool CannotClose { get; set; } + public bool ProgressVisible { get; set; } + public string StatusMessage2 { get; set; } + public bool Progress2Visible { get; set; } + public int? Progress2Max { get; set; } + public int? Progress2Min { get; set; } + public int? Progress2Value { get; set; } + public Color? StatusColor { get; set; } /// protected override void OnInitialized() { base.OnInitialized(); - path = Path.Combine(Environment.CurrentDirectory, Consts.IncomingDatFolder); - StatusMessage = string.Empty; - IsBusy = false; - CannotClose = false; - ProgressVisible = false; + path = Path.Combine(Environment.CurrentDirectory, Consts.IncomingDatFolder); + StatusMessage = ""; + StatusMessage2 = ""; + IsBusy = false; + CannotClose = false; + ProgressVisible = false; + Progress2Visible = false; } - Task StartAsync() + void Start() { IsBusy = true; CannotClose = true; @@ -59,49 +68,113 @@ public partial class ImportDats : ComponentBase StatusMessage = string.Format("Found {0} files...", _datFiles.Length); - ProgressMin = 0; - ProgressMax = _datFiles.Length; - ProgressValue = 0; - _listPosition = 0; - _workers = 0; + ProgressMin = 0; + ProgressMax = _datFiles.Length; + ProgressValue = 0; + Progress2Visible = true; + _listPosition = 0; + _workers = 0; StateHasChanged(); - return ImportAsync(); - } - - async Task ImportAsync() - { _stopwatch.Restart(); Logger.LogDebug("Starting to import DAT files..."); + Import(); + } - Parallel.ForEach(_datFiles, - datFile => - { - _ = InvokeAsync(() => - { - StatusMessage = string.Format("Importing {0}...", Path.GetFileName(datFile)); + void Import() + { + if(_listPosition >= _datFiles.Length) + { + _ = InvokeAsync(() => + { + ProgressVisible = false; + Progress2Visible = false; + StatusMessage = "Finished"; + CannotClose = false; - ProgressValue = _listPosition; - StateHasChanged(); - }); + StateHasChanged(); + }); - var worker = new DatImporter(datFile, null, new SerilogLoggerFactory(Log.Logger)); + _stopwatch.Stop(); - worker.Import(); + Logger.LogDebug("Took {TotalSeconds} seconds to import {Length} DAT files", + _stopwatch.Elapsed.TotalSeconds, + _datFiles.Length); - Interlocked.Increment(ref _listPosition); - }); - ProgressVisible = false; - StatusMessage = "Finished"; - CannotClose = false; - _stopwatch.Stop(); + return; + } - Logger.LogDebug("Took {TotalSeconds} seconds to import {Length} DAT files", - _stopwatch.Elapsed.TotalSeconds, - _datFiles.Length); + _ = InvokeAsync(() => + { + StatusMessage = string.Format("Importing {0}...", Path.GetFileName(_datFiles[_listPosition])); + ProgressValue = _listPosition; - StateHasChanged(); + StateHasChanged(); + }); + + var worker = new DatImporter(_datFiles[_listPosition], null, new SerilogLoggerFactory(Log.Logger)); + + worker.ErrorOccurred += OnWorkerOnErrorOccurred; + worker.SetIndeterminateProgress += OnWorkerOnSetIndeterminateProgress; + worker.SetMessage += OnWorkerOnSetMessage; + worker.SetProgress += OnWorkerOnSetProgress; + worker.SetProgressBounds += OnWorkerOnSetProgressBounds; + worker.WorkFinished += OnWorkerOnWorkFinished; + _ = Task.Run(worker.Import); + } + + void OnWorkerOnWorkFinished(object? sender, MessageEventArgs args) + { + _listPosition++; + Import(); + } + + void OnWorkerOnSetProgressBounds(object? sender, ProgressBoundsEventArgs args) + { + _ = InvokeAsync(() => + { + Progress2Value = 0; + Progress2Max = (int?)args.Maximum; + Progress2Min = (int?)args.Minimum; + StateHasChanged(); + }); + } + + void OnWorkerOnSetProgress(object? sender, ProgressEventArgs args) + { + _ = InvokeAsync(() => + { + Progress2Value = (int?)args.Value; + StateHasChanged(); + }); + } + + void OnWorkerOnSetMessage(object? sender, MessageEventArgs args) + { + _ = InvokeAsync(() => + { + StatusMessage2 = args.Message; + StateHasChanged(); + }); + } + + void OnWorkerOnSetIndeterminateProgress(object? sender, EventArgs args) + { + _ = InvokeAsync(() => + { + Progress2Value = null; + StateHasChanged(); + }); + } + + void OnWorkerOnErrorOccurred(object? sender, ErrorEventArgs args) + { + _ = InvokeAsync(() => + { + _listPosition++; + Import(); + }); } Task CloseAsync() => Dialog.CloseAsync();