From d43235bca10c0daae74c3f9bdaaf00b485b47138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20H=C3=A4felfinger?= Date: Mon, 4 Sep 2023 23:12:18 +0200 Subject: [PATCH] fixes id of image on download and adds cancellation support for spectre commands --- .../Commands/DownloadImagesCommand.cs | 8 ++-- PiwigoDirectorySync/Commands/ScanCommand.cs | 9 ++--- .../Commands/SyncAlbumsCommand.cs | 8 ++-- .../Commands/SyncFullCommand.cs | 13 +++---- .../Commands/SyncImagesCommand.cs | 8 ++-- .../Infrastructure/CancellableAsyncCommand.cs | 12 ++++++ .../ConsoleAppCancellationTokenSource.cs | 39 +++++++++++++++++++ PiwigoDirectorySync/Program.cs | 2 +- .../Services/ImageSynchronizer.cs | 1 + 9 files changed, 75 insertions(+), 25 deletions(-) create mode 100644 PiwigoDirectorySync/Infrastructure/CancellableAsyncCommand.cs create mode 100644 PiwigoDirectorySync/Infrastructure/ConsoleAppCancellationTokenSource.cs diff --git a/PiwigoDirectorySync/Commands/DownloadImagesCommand.cs b/PiwigoDirectorySync/Commands/DownloadImagesCommand.cs index 524914c..d1d9847 100644 --- a/PiwigoDirectorySync/Commands/DownloadImagesCommand.cs +++ b/PiwigoDirectorySync/Commands/DownloadImagesCommand.cs @@ -1,11 +1,12 @@ using System.Diagnostics; using Microsoft.Extensions.Logging; +using PiwigoDirectorySync.Infrastructure; using PiwigoDirectorySync.Services; using Spectre.Console.Cli; namespace PiwigoDirectorySync.Commands; -internal class DownloadImagesCommand : AsyncCommand +internal class DownloadImagesCommand : CancellableAsyncCommand { private readonly IImageSynchronizer _imageSynchronizer; private readonly ILogger _logger; @@ -16,13 +17,12 @@ internal class DownloadImagesCommand : AsyncCommand _logger = logger; } - public override async Task ExecuteAsync(CommandContext context, DownloadImagesSettings settings) + protected override async Task ExecuteAsync(CommandContext context, DownloadImagesSettings settings, CancellationToken cancellationToken) { _logger.LogInformation("Starting image download for piwigo server {SettingsPiwigoServerId}", settings.PiwigoServerId); var stopWatch = Stopwatch.StartNew(); - var cancellationTokenSource = new CancellationTokenSource(); - await _imageSynchronizer.DownloadImagesAsync(settings.PiwigoServerId, cancellationTokenSource.Token); + await _imageSynchronizer.DownloadImagesAsync(settings.PiwigoServerId, cancellationToken); stopWatch.Stop(); _logger.LogInformation("Synchronized all images with piwigo server {SettingsPiwigoServerId} in {ElapsedTotalSeconds} seconds", settings.PiwigoServerId, diff --git a/PiwigoDirectorySync/Commands/ScanCommand.cs b/PiwigoDirectorySync/Commands/ScanCommand.cs index 1db7526..5611bb1 100644 --- a/PiwigoDirectorySync/Commands/ScanCommand.cs +++ b/PiwigoDirectorySync/Commands/ScanCommand.cs @@ -1,12 +1,13 @@ using System.Diagnostics; using System.Threading.Channels; using Microsoft.Extensions.Logging; +using PiwigoDirectorySync.Infrastructure; using PiwigoDirectorySync.Services; using Spectre.Console.Cli; namespace PiwigoDirectorySync.Commands; -internal class ScanCommand : AsyncCommand +internal class ScanCommand : CancellableAsyncCommand { private readonly IFileIndexer _fileIndexer; private readonly IFileSystemScanner _fileSystemScanner; @@ -19,11 +20,9 @@ internal class ScanCommand : AsyncCommand _fileSystemScanner = fileSystemScanner; } - public override async Task ExecuteAsync(CommandContext context, ScanSettings settings) + protected override async Task ExecuteAsync(CommandContext context, ScanSettings settings, CancellationToken cancellationToken) { - var cancellationTokenSource = new CancellationTokenSource(); - - await ScanDirectory(_logger, _fileIndexer, _fileSystemScanner, settings.PiwigoServerId, cancellationTokenSource.Token); + await ScanDirectory(_logger, _fileIndexer, _fileSystemScanner, settings.PiwigoServerId, cancellationToken); return 0; } diff --git a/PiwigoDirectorySync/Commands/SyncAlbumsCommand.cs b/PiwigoDirectorySync/Commands/SyncAlbumsCommand.cs index aba8e01..cda9706 100644 --- a/PiwigoDirectorySync/Commands/SyncAlbumsCommand.cs +++ b/PiwigoDirectorySync/Commands/SyncAlbumsCommand.cs @@ -1,11 +1,12 @@ using System.Diagnostics; using Microsoft.Extensions.Logging; +using PiwigoDirectorySync.Infrastructure; using PiwigoDirectorySync.Services; using Spectre.Console.Cli; namespace PiwigoDirectorySync.Commands; -internal class SyncAlbumsCommand : AsyncCommand +internal class SyncAlbumsCommand : CancellableAsyncCommand { private readonly IAlbumSynchronizer _albumSynchronizer; private readonly ILogger _logger; @@ -16,14 +17,13 @@ internal class SyncAlbumsCommand : AsyncCommand _albumSynchronizer = albumSynchronizer; } - public override async Task ExecuteAsync(CommandContext context, SyncAlbumsSettings settings) + protected override async Task ExecuteAsync(CommandContext context, SyncAlbumsSettings settings, CancellationToken cancellationToken) { _logger.LogInformation("Starting album synchronization for piwigo server {SettingsPiwigoServerId}", settings.PiwigoServerId); var stopWatch = Stopwatch.StartNew(); - var cancellationTokenSource = new CancellationTokenSource(); - await _albumSynchronizer.SynchronizeAlbums(settings.PiwigoServerId, cancellationTokenSource.Token); + await _albumSynchronizer.SynchronizeAlbums(settings.PiwigoServerId, cancellationToken); stopWatch.Stop(); _logger.LogInformation("Synchronized all albums with piwigo server {SettingsPiwigoServerId} in {ElapsedTotalSeconds} seconds", settings.PiwigoServerId, diff --git a/PiwigoDirectorySync/Commands/SyncFullCommand.cs b/PiwigoDirectorySync/Commands/SyncFullCommand.cs index 869da77..add334a 100644 --- a/PiwigoDirectorySync/Commands/SyncFullCommand.cs +++ b/PiwigoDirectorySync/Commands/SyncFullCommand.cs @@ -1,11 +1,12 @@ using System.Diagnostics; using Microsoft.Extensions.Logging; +using PiwigoDirectorySync.Infrastructure; using PiwigoDirectorySync.Services; using Spectre.Console.Cli; namespace PiwigoDirectorySync.Commands; -internal class SyncFullCommand : AsyncCommand +internal class SyncFullCommand : CancellableAsyncCommand { private readonly IAlbumSynchronizer _albumSynchronizer; private readonly IFileIndexer _fileIndexer; @@ -23,21 +24,19 @@ internal class SyncFullCommand : AsyncCommand _logger = logger; } - public override async Task ExecuteAsync(CommandContext context, SyncFullSettings settings) + protected override async Task ExecuteAsync(CommandContext context, SyncFullSettings settings, CancellationToken cancellationToken) { _logger.LogInformation("Starting full synchronization for piwigo server {SettingsPiwigoServerId}", settings.PiwigoServerId); var stopWatch = Stopwatch.StartNew(); - var cancellationTokenSource = new CancellationTokenSource(); - _logger.LogInformation("running file system scan"); - await ScanCommand.ScanDirectory(_logger, _fileIndexer, _fileSystemScanner, settings.PiwigoServerId, cancellationTokenSource.Token); + await ScanCommand.ScanDirectory(_logger, _fileIndexer, _fileSystemScanner, settings.PiwigoServerId, cancellationToken); _logger.LogInformation("running album synchronization"); - await _albumSynchronizer.SynchronizeAlbums(settings.PiwigoServerId, cancellationTokenSource.Token); + await _albumSynchronizer.SynchronizeAlbums(settings.PiwigoServerId, cancellationToken); _logger.LogInformation("running image synchronization"); - await _imageSynchronizer.SynchronizeImagesAsync(settings.PiwigoServerId, cancellationTokenSource.Token); + await _imageSynchronizer.SynchronizeImagesAsync(settings.PiwigoServerId, cancellationToken); stopWatch.Stop(); _logger.LogInformation("Full synchronization for piwigo server {SettingsPiwigoServerId} finished in {ElapsedTotalSeconds} seconds", settings.PiwigoServerId, diff --git a/PiwigoDirectorySync/Commands/SyncImagesCommand.cs b/PiwigoDirectorySync/Commands/SyncImagesCommand.cs index 1bf4a8a..ed7e43c 100644 --- a/PiwigoDirectorySync/Commands/SyncImagesCommand.cs +++ b/PiwigoDirectorySync/Commands/SyncImagesCommand.cs @@ -1,11 +1,12 @@ using System.Diagnostics; using Microsoft.Extensions.Logging; +using PiwigoDirectorySync.Infrastructure; using PiwigoDirectorySync.Services; using Spectre.Console.Cli; namespace PiwigoDirectorySync.Commands; -internal class SyncImagesCommand : AsyncCommand +internal class SyncImagesCommand : CancellableAsyncCommand { private readonly IImageSynchronizer _imageSynchronizer; private readonly ILogger _logger; @@ -16,13 +17,12 @@ internal class SyncImagesCommand : AsyncCommand _imageSynchronizer = imageSynchronizer; } - public override async Task ExecuteAsync(CommandContext context, SyncImagesSettings settings) + protected override async Task ExecuteAsync(CommandContext context, SyncImagesSettings settings, CancellationToken cancellationToken) { _logger.LogInformation("Starting image synchronization of piwigo server {SettingsPiwigoServerId}", settings.PiwigoServerId); var stopWatch = Stopwatch.StartNew(); - var cancellationTokenSource = new CancellationTokenSource(); - await _imageSynchronizer.SynchronizeImagesAsync(settings.PiwigoServerId, cancellationTokenSource.Token); + await _imageSynchronizer.SynchronizeImagesAsync(settings.PiwigoServerId, cancellationToken); stopWatch.Stop(); _logger.LogInformation("Synchronized all images with piwigo server {SettingsPiwigoServerId} in {ElapsedTotalSeconds} seconds", settings.PiwigoServerId, diff --git a/PiwigoDirectorySync/Infrastructure/CancellableAsyncCommand.cs b/PiwigoDirectorySync/Infrastructure/CancellableAsyncCommand.cs new file mode 100644 index 0000000..5602022 --- /dev/null +++ b/PiwigoDirectorySync/Infrastructure/CancellableAsyncCommand.cs @@ -0,0 +1,12 @@ +using Spectre.Console.Cli; + +namespace PiwigoDirectorySync.Infrastructure; + +public abstract class CancellableAsyncCommand : AsyncCommand where TSettings : CommandSettings +{ + private readonly ConsoleAppCancellationTokenSource _cancellationTokenSource = new(); + + protected abstract Task ExecuteAsync(CommandContext context, TSettings settings, CancellationToken cancellation); + + public sealed override async Task ExecuteAsync(CommandContext context, TSettings settings) => await ExecuteAsync(context, settings, _cancellationTokenSource.Token); +} \ No newline at end of file diff --git a/PiwigoDirectorySync/Infrastructure/ConsoleAppCancellationTokenSource.cs b/PiwigoDirectorySync/Infrastructure/ConsoleAppCancellationTokenSource.cs new file mode 100644 index 0000000..dadbf5c --- /dev/null +++ b/PiwigoDirectorySync/Infrastructure/ConsoleAppCancellationTokenSource.cs @@ -0,0 +1,39 @@ +namespace PiwigoDirectorySync.Infrastructure; + +internal sealed class ConsoleAppCancellationTokenSource +{ + private readonly CancellationTokenSource _cts = new(); + + public ConsoleAppCancellationTokenSource() + { + Console.CancelKeyPress += OnCancelKeyPress; + AppDomain.CurrentDomain.ProcessExit += OnProcessExit; + + using var _ = _cts.Token.Register(() => + { + AppDomain.CurrentDomain.ProcessExit -= OnProcessExit; + Console.CancelKeyPress -= OnCancelKeyPress; + }); + } + + public CancellationToken Token => _cts.Token; + + private void OnCancelKeyPress(object? sender, ConsoleCancelEventArgs e) + { + // NOTE: cancel event, don't terminate the process + e.Cancel = true; + _cts.Cancel(); + } + + private void OnProcessExit(object? sender, EventArgs e) + { + if (_cts.IsCancellationRequested) + { + // NOTE: SIGINT (cancel key was pressed, this shouldn't ever actually hit however, + // as we remove the event handler upon cancellation of the `cancellationSource`) + return; + } + + _cts.Cancel(); + } +} \ No newline at end of file diff --git a/PiwigoDirectorySync/Program.cs b/PiwigoDirectorySync/Program.cs index 3dcf192..3d10eda 100644 --- a/PiwigoDirectorySync/Program.cs +++ b/PiwigoDirectorySync/Program.cs @@ -54,4 +54,4 @@ app.Configure(config => }); }); -return app.Run(args); \ No newline at end of file +return await app.RunAsync(args); \ No newline at end of file diff --git a/PiwigoDirectorySync/Services/ImageSynchronizer.cs b/PiwigoDirectorySync/Services/ImageSynchronizer.cs index 046661f..09e03c6 100644 --- a/PiwigoDirectorySync/Services/ImageSynchronizer.cs +++ b/PiwigoDirectorySync/Services/ImageSynchronizer.cs @@ -127,6 +127,7 @@ internal class ImageSynchronizer : IImageSynchronizer { AlbumId = album.Id, Album = album, + ServerImageId = image.Id, FilePath = Path.Combine(album.Path, image.File!), UploadRequired = false, DeleteRequired = false