diff --git a/Directory.Packages.props b/Directory.Packages.props index e6e3983..83d9ded 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -35,6 +35,7 @@ + diff --git a/KtsuTools.BuildMonitor/BuildMonitorService.cs b/KtsuTools.BuildMonitor/BuildMonitorService.cs index a584655..5d97f7a 100644 --- a/KtsuTools.BuildMonitor/BuildMonitorService.cs +++ b/KtsuTools.BuildMonitor/BuildMonitorService.cs @@ -10,6 +10,7 @@ namespace KtsuTools.BuildMonitor; using System.Threading; using System.Threading.Tasks; using Humanizer; +using ktsu.IntervalAction; using KtsuTools.Core.Services.GitHub; using Spectre.Console; using Spectre.Console.Rendering; @@ -37,31 +38,42 @@ await AnsiConsole.Live(initial) .AutoClear(true) .StartAsync(async ctx => { - while (!ct.IsCancellationRequested) + TimeSpan interval = TimeSpan.FromSeconds(refreshIntervalSeconds); + + void Tick() { try { - Table table = await BuildDashboardTableAsync(owner, ct).ConfigureAwait(false); + Table table = BuildDashboardTableAsync(owner, ct).GetAwaiter().GetResult(); ctx.UpdateTarget(table); } catch (OperationCanceledException) { - break; } catch (HttpRequestException ex) { ctx.UpdateTarget(new Markup($"[red]API Error: {ex.Message.EscapeMarkup()}[/]")); } + } - try - { - await Task.Delay(TimeSpan.FromSeconds(refreshIntervalSeconds), ct).ConfigureAwait(false); - } - catch (OperationCanceledException) - { - break; - } + Tick(); + + IntervalAction ticker = IntervalAction.Start(new IntervalActionOptions + { + ActionInterval = interval, + PollingInterval = interval, + Action = Tick, + }); + + try + { + await Task.Delay(Timeout.InfiniteTimeSpan, ct).ConfigureAwait(false); } + catch (OperationCanceledException) + { + } + + ticker.Stop(); }).ConfigureAwait(false); } diff --git a/KtsuTools.BuildMonitor/KtsuTools.BuildMonitor.csproj b/KtsuTools.BuildMonitor/KtsuTools.BuildMonitor.csproj index a0a01df..be68e45 100644 --- a/KtsuTools.BuildMonitor/KtsuTools.BuildMonitor.csproj +++ b/KtsuTools.BuildMonitor/KtsuTools.BuildMonitor.csproj @@ -11,6 +11,7 @@ + diff --git a/KtsuTools.CodeGen/CodeGenService.cs b/KtsuTools.CodeGen/CodeGenService.cs index 6dd3f61..1f3ec66 100644 --- a/KtsuTools.CodeGen/CodeGenService.cs +++ b/KtsuTools.CodeGen/CodeGenService.cs @@ -285,6 +285,7 @@ public class CodeGenService public async Task GenerateAsync(AbsoluteFilePath inputFile, string language, AbsoluteFilePath? outputFile = null, CancellationToken ct = default) #pragma warning restore CA1822 { + Ensure.NotNull(inputFile); Ensure.NotNull(language); string fullPath = inputFile.ToString(); diff --git a/KtsuTools.FileExplorer/FileExplorerService.cs b/KtsuTools.FileExplorer/FileExplorerService.cs index d748529..0b0e950 100644 --- a/KtsuTools.FileExplorer/FileExplorerService.cs +++ b/KtsuTools.FileExplorer/FileExplorerService.cs @@ -62,6 +62,8 @@ public class FileExplorerService public async Task RunAsync(AbsoluteDirectoryPath startPath, bool showHidden = false, bool showSizes = true, CancellationToken ct = default) #pragma warning restore CA1822 { + Ensure.NotNull(startPath); + string currentPath = startPath.ToString(); if (!Directory.Exists(currentPath)) diff --git a/KtsuTools.Machine/KtsuTools.Machine.csproj b/KtsuTools.Machine/KtsuTools.Machine.csproj index be933ac..7825c24 100644 --- a/KtsuTools.Machine/KtsuTools.Machine.csproj +++ b/KtsuTools.Machine/KtsuTools.Machine.csproj @@ -11,6 +11,7 @@ + diff --git a/KtsuTools.Machine/MachineMonitorService.cs b/KtsuTools.Machine/MachineMonitorService.cs index 21028bd..9c29245 100644 --- a/KtsuTools.Machine/MachineMonitorService.cs +++ b/KtsuTools.Machine/MachineMonitorService.cs @@ -10,6 +10,7 @@ namespace KtsuTools.Machine; using System.Linq; using System.Threading; using System.Threading.Tasks; +using ktsu.IntervalAction; using LibreHardwareMonitor.Hardware; using Spectre.Console; using Spectre.Console.Rendering; @@ -48,31 +49,33 @@ public async Task RunDashboardAsync(int refreshIntervalMs = 1000, Cancellat AnsiConsole.WriteLine(); IRenderable initial = new Text("Loading hardware sensors..."); + Computer computerCapture = computer; await AnsiConsole.Live(initial) .AutoClear(true) .StartAsync(async ctx => { - while (!ct.IsCancellationRequested) + TimeSpan interval = TimeSpan.FromMilliseconds(refreshIntervalMs); + + void Tick() => ctx.UpdateTarget(BuildDashboard(computerCapture)); + + Tick(); + + IntervalAction ticker = IntervalAction.Start(new IntervalActionOptions + { + ActionInterval = interval, + PollingInterval = interval, + Action = Tick, + }); + + try + { + await Task.Delay(Timeout.InfiniteTimeSpan, ct).ConfigureAwait(false); + } + catch (OperationCanceledException) { - try - { - Table dashboard = BuildDashboard(computer); - ctx.UpdateTarget(dashboard); - } - catch (OperationCanceledException) - { - break; - } - - try - { - await Task.Delay(refreshIntervalMs, ct).ConfigureAwait(false); - } - catch (OperationCanceledException) - { - break; - } } + + ticker.Stop(); }).ConfigureAwait(false); } finally diff --git a/KtsuTools.MemFrag/KtsuTools.MemFrag.csproj b/KtsuTools.MemFrag/KtsuTools.MemFrag.csproj index 4d92c11..9a5e030 100644 --- a/KtsuTools.MemFrag/KtsuTools.MemFrag.csproj +++ b/KtsuTools.MemFrag/KtsuTools.MemFrag.csproj @@ -9,6 +9,7 @@ + diff --git a/KtsuTools.MemFrag/MemFragService.cs b/KtsuTools.MemFrag/MemFragService.cs index 9e4631f..06e9e68 100644 --- a/KtsuTools.MemFrag/MemFragService.cs +++ b/KtsuTools.MemFrag/MemFragService.cs @@ -9,6 +9,7 @@ namespace KtsuTools.MemFrag; using System.Globalization; using System.Threading; using System.Threading.Tasks; +using ktsu.IntervalAction; using Spectre.Console; using Spectre.Console.Rendering; @@ -78,33 +79,46 @@ public async Task MonitorAsync(int processId, int refreshIntervalMs = 1000, AnsiConsole.WriteLine(); IRenderable initial = new Text("Loading..."); + Process processCapture = process; await AnsiConsole.Live(initial) .AutoClear(true) .StartAsync(async ctx => { - while (!ct.IsCancellationRequested) + using CancellationTokenSource exitedCts = CancellationTokenSource.CreateLinkedTokenSource(ct); + TimeSpan interval = TimeSpan.FromMilliseconds(refreshIntervalMs); + + void Tick() { try { - process.Refresh(); - Table table = BuildMemoryTable(process); - ctx.UpdateTarget(table); + processCapture.Refresh(); + ctx.UpdateTarget(BuildMemoryTable(processCapture)); } catch (InvalidOperationException) { ctx.UpdateTarget(new Markup("[red]Process has exited.[/]")); - break; + exitedCts.Cancel(); } + } - try - { - await Task.Delay(refreshIntervalMs, ct).ConfigureAwait(false); - } - catch (OperationCanceledException) - { - break; - } + Tick(); + + IntervalAction ticker = IntervalAction.Start(new IntervalActionOptions + { + ActionInterval = interval, + PollingInterval = interval, + Action = Tick, + }); + + try + { + await Task.Delay(Timeout.InfiniteTimeSpan, exitedCts.Token).ConfigureAwait(false); } + catch (OperationCanceledException) + { + } + + ticker.Stop(); }).ConfigureAwait(false); } diff --git a/KtsuTools.Merge/MergeService.cs b/KtsuTools.Merge/MergeService.cs index e549908..2503e84 100644 --- a/KtsuTools.Merge/MergeService.cs +++ b/KtsuTools.Merge/MergeService.cs @@ -57,6 +57,7 @@ public class MergeService public async Task RunMergeAsync(AbsoluteDirectoryPath directory, string filename, CancellationToken ct = default) #pragma warning restore CA1822 { + Ensure.NotNull(directory); Ensure.NotNull(filename); string fullPath = directory.ToString(); diff --git a/KtsuTools/Commands/SyncCommand.cs b/KtsuTools/Commands/SyncCommand.cs index 5ebfb3d..bbd5abe 100644 --- a/KtsuTools/Commands/SyncCommand.cs +++ b/KtsuTools/Commands/SyncCommand.cs @@ -38,7 +38,9 @@ public sealed class Settings : CommandSettings /// [CommandOption("--filename ")] [Description("Filename pattern to scan for. Repeat the flag or pass a comma-separated list to sync several files in one run.")] +#pragma warning disable CA1819 // Properties should not return arrays - Spectre.Console.Cli binds multi-value options via T[] only. public string[] Filename { get; init; } = []; +#pragma warning restore CA1819 /// /// Gets a value indicating whether to push without prompting when all unpushed commits were authored by KtsuTools.