diff --git a/code/Executable/DependencyInjection/ServicesDI.cs b/code/Executable/DependencyInjection/ServicesDI.cs index 30ac9704..4c5ef10a 100644 --- a/code/Executable/DependencyInjection/ServicesDI.cs +++ b/code/Executable/DependencyInjection/ServicesDI.cs @@ -38,7 +38,6 @@ public static class ServicesDI .AddTransient() .AddTransient() // Download client services - .AddTransient() .AddTransient() .AddTransient() .AddTransient() diff --git a/code/Infrastructure/Verticals/ContentBlocker/ContentBlocker.cs b/code/Infrastructure/Verticals/ContentBlocker/ContentBlocker.cs index af07571f..3d5815d3 100644 --- a/code/Infrastructure/Verticals/ContentBlocker/ContentBlocker.cs +++ b/code/Infrastructure/Verticals/ContentBlocker/ContentBlocker.cs @@ -76,9 +76,9 @@ public sealed class ContentBlocker : GenericHandler // Refresh configurations before executing await InitializeConfigs(); - if (_downloadClientConfig.DownloadClient is Common.Enums.DownloadClient.None or Common.Enums.DownloadClient.Disabled) + if (_downloadClientConfig.Clients.Count == 0) { - _logger.LogWarning("download client is not set"); + _logger.LogWarning("No download clients configured"); return; } diff --git a/code/Infrastructure/Verticals/DownloadCleaner/DownloadCleaner.cs b/code/Infrastructure/Verticals/DownloadCleaner/DownloadCleaner.cs index 5828f1ac..671316c2 100644 --- a/code/Infrastructure/Verticals/DownloadCleaner/DownloadCleaner.cs +++ b/code/Infrastructure/Verticals/DownloadCleaner/DownloadCleaner.cs @@ -89,6 +89,10 @@ public sealed class DownloadCleaner : GenericHandler _downloadServices.Add(downloadService); _logger.LogDebug("Added download client: {name} ({id})", client.Name, client.Id); } + else + { + _logger.LogWarning("Download client service not available for: {id}", client.Id); + } } catch (Exception ex) { @@ -164,7 +168,7 @@ public sealed class DownloadCleaner : GenericHandler { try { - if (_downloadClientConfig.Clients.Any(x => x.Id == Common.Enums.DownloadClient.QBittorrent) && !_config.UnlinkedUseTag) + if (_downloadClientConfig.Clients.Any(x => x.Type == Common.Enums.DownloadClientType.QBittorrent) && !_config.UnlinkedUseTag) { _logger.LogDebug("creating category {cat}", _config.UnlinkedTargetCategory); await downloadService.CreateCategoryAsync(_config.UnlinkedTargetCategory); diff --git a/code/Infrastructure/Verticals/DownloadClient/DownloadServiceFactory.cs b/code/Infrastructure/Verticals/DownloadClient/DownloadServiceFactory.cs index 5417fc50..c57a6827 100644 --- a/code/Infrastructure/Verticals/DownloadClient/DownloadServiceFactory.cs +++ b/code/Infrastructure/Verticals/DownloadClient/DownloadServiceFactory.cs @@ -1,4 +1,4 @@ -using Common.Configuration.DownloadClient; +using Common.Configuration.DownloadClient; using Common.Enums; using Infrastructure.Configuration; using Infrastructure.Verticals.DownloadClient.Deluge; @@ -9,6 +9,9 @@ using Microsoft.Extensions.Logging; namespace Infrastructure.Verticals.DownloadClient; +/// +/// Factory responsible for creating download client service instances +/// public sealed class DownloadServiceFactory { private readonly IServiceProvider _serviceProvider; @@ -29,29 +32,29 @@ public sealed class DownloadServiceFactory /// Creates a download service using the specified client ID /// /// The client ID to create a service for - /// An implementation of IDownloadService - public IDownloadService GetDownloadService(string clientId) + /// An implementation of IDownloadService or null if the client is not available + public IDownloadService? GetDownloadService(string clientId) { var config = _configManager.GetDownloadClientConfigAsync().GetAwaiter().GetResult(); if (config == null) { - _logger.LogWarning("No download client configuration found, using empty service"); - return _serviceProvider.GetRequiredService(); + _logger.LogWarning("No download client configuration found"); + return null; } var clientConfig = config.GetClientConfig(clientId); if (clientConfig == null) { - _logger.LogWarning("No download client configuration found for ID {clientId}, using empty service", clientId); - return _serviceProvider.GetRequiredService(); + _logger.LogWarning("No download client configuration found for ID {clientId}", clientId); + return null; } if (!clientConfig.Enabled) { - _logger.LogWarning("Download client {clientId} is disabled, using empty service", clientId); - return _serviceProvider.GetRequiredService(); + _logger.LogWarning("Download client {clientId} is disabled", clientId); + return null; } return GetDownloadService(clientConfig); @@ -61,29 +64,28 @@ public sealed class DownloadServiceFactory /// Creates a download service using the specified client configuration /// /// The client configuration to use - /// An implementation of IDownloadService - public IDownloadService GetDownloadService(ClientConfig clientConfig) + /// An implementation of IDownloadService or null if the client is not available + public IDownloadService? GetDownloadService(ClientConfig clientConfig) { if (clientConfig == null) { - _logger.LogWarning("Client configuration is null, using empty service"); - return _serviceProvider.GetRequiredService(); + _logger.LogWarning("Client configuration is null"); + return null; } if (!clientConfig.Enabled) { - _logger.LogWarning("Download client {clientId} is disabled, using empty service", clientConfig.Id); - return _serviceProvider.GetRequiredService(); + _logger.LogWarning("Download client {clientId} is disabled", clientConfig.Id); + return null; } return clientConfig.Type switch { - DownloadClient.QBittorrent => CreateClientService(clientConfig), - DownloadClient.Deluge => CreateClientService(clientConfig), - DownloadClient.Transmission => CreateClientService(clientConfig), - DownloadClient.Usenet => _serviceProvider.GetRequiredService(), - DownloadClient.Disabled => _serviceProvider.GetRequiredService(), - _ => _serviceProvider.GetRequiredService() + DownloadClientType.QBittorrent => CreateClientService(clientConfig), + DownloadClientType.Deluge => CreateClientService(clientConfig), + DownloadClientType.Transmission => CreateClientService(clientConfig), + DownloadClientType.Usenet => null, // Usenet clients are handled elsewhere + _ => null }; } diff --git a/code/Infrastructure/Verticals/DownloadClient/EmptyDownloadService.cs b/code/Infrastructure/Verticals/DownloadClient/EmptyDownloadService.cs deleted file mode 100644 index ee00dd18..00000000 --- a/code/Infrastructure/Verticals/DownloadClient/EmptyDownloadService.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System.Collections.Concurrent; -using System.Text.RegularExpressions; -using Common.Configuration.ContentBlocker; -using Common.Configuration.DownloadCleaner; -using Domain.Enums; -using Microsoft.Extensions.Logging; - -namespace Infrastructure.Verticals.DownloadClient; - -/// -/// Empty implementation of IDownloadService that performs no operations -/// This is used when no download client is configured or available -/// -public sealed class EmptyDownloadService : IDownloadService -{ - private readonly ILogger _logger; - - public EmptyDownloadService(ILogger logger) - { - _logger = logger; - } - - public void Dispose() - { - // Nothing to dispose - } - - public Task LoginAsync() - { - _logger.LogDebug("EmptyDownloadService: Login called (no-op)"); - return Task.CompletedTask; - } - - public Task ShouldRemoveFromArrQueueAsync(string hash, IReadOnlyList ignoredDownloads) - { - _logger.LogDebug("EmptyDownloadService: ShouldRemoveFromArrQueueAsync called (no-op)"); - return Task.FromResult(new DownloadCheckResult()); - } - - public Task BlockUnwantedFilesAsync(string hash, BlocklistType blocklistType, ConcurrentBag patterns, ConcurrentBag regexes, IReadOnlyList ignoredDownloads) - { - _logger.LogDebug("EmptyDownloadService: BlockUnwantedFilesAsync called (no-op)"); - return Task.FromResult(new BlockFilesResult()); - } - - public Task DeleteDownload(string hash) - { - _logger.LogDebug("EmptyDownloadService: DeleteDownload called (no-op)"); - return Task.CompletedTask; - } - - public Task?> GetSeedingDownloads() - { - _logger.LogDebug("EmptyDownloadService: GetSeedingDownloads called (no-op)"); - return Task.FromResult?>(new List()); - } - - public List? FilterDownloadsToBeCleanedAsync(List? downloads, List categories) - { - _logger.LogDebug("EmptyDownloadService: FilterDownloadsToBeCleanedAsync called (no-op)"); - return new List(); - } - - public List? FilterDownloadsToChangeCategoryAsync(List? downloads, List categories) - { - _logger.LogDebug("EmptyDownloadService: FilterDownloadsToChangeCategoryAsync called (no-op)"); - return new List(); - } - - public Task CleanDownloadsAsync(List? downloads, List categoriesToClean, HashSet excludedHashes, IReadOnlyList ignoredDownloads) - { - _logger.LogDebug("EmptyDownloadService: CleanDownloadsAsync called (no-op)"); - return Task.CompletedTask; - } - - public Task ChangeCategoryForNoHardLinksAsync(List? downloads, HashSet excludedHashes, IReadOnlyList ignoredDownloads) - { - _logger.LogDebug("EmptyDownloadService: ChangeCategoryForNoHardLinksAsync called (no-op)"); - return Task.CompletedTask; - } - - public Task CreateCategoryAsync(string name) - { - _logger.LogDebug("EmptyDownloadService: CreateCategoryAsync called (no-op)"); - return Task.CompletedTask; - } -} diff --git a/code/Infrastructure/Verticals/Jobs/GenericHandler.cs b/code/Infrastructure/Verticals/Jobs/GenericHandler.cs index 145896cd..5cf74a7c 100644 --- a/code/Infrastructure/Verticals/Jobs/GenericHandler.cs +++ b/code/Infrastructure/Verticals/Jobs/GenericHandler.cs @@ -66,8 +66,16 @@ public abstract class GenericHandler : IHandler, IDisposable { try { - _downloadServices.Add(_downloadServiceFactory.GetDownloadService(client.Id)); - _logger.LogDebug("Initialized download client: {name} ({id})", client.Name, client.Id); + var service = _downloadServiceFactory.GetDownloadService(client.Id); + if (service != null) + { + _downloadServices.Add(service); + _logger.LogDebug("Initialized download client: {name} ({id})", client.Name, client.Id); + } + else + { + _logger.LogWarning("Download client service not available for: {id}", client.Id); + } } catch (Exception ex) { diff --git a/code/Infrastructure/Verticals/QueueCleaner/QueueCleaner.cs b/code/Infrastructure/Verticals/QueueCleaner/QueueCleaner.cs index 4d68a656..1f49fd6b 100644 --- a/code/Infrastructure/Verticals/QueueCleaner/QueueCleaner.cs +++ b/code/Infrastructure/Verticals/QueueCleaner/QueueCleaner.cs @@ -75,10 +75,25 @@ public sealed class QueueCleaner : GenericHandler // Initialize download services if (_downloadClientConfig.Clients.Count > 0) { - foreach (var clientConfig in _downloadClientConfig.Clients) + foreach (var client in _downloadClientConfig.GetEnabledClients()) { - var downloadService = _downloadServiceFactory.GetDownloadService(clientConfig); - _downloadServices.Add(downloadService); + try + { + var service = _downloadServiceFactory.GetDownloadService(client.Id); + if (service != null) + { + _downloadServices.Add(service); + _logger.LogDebug("Added download client: {name} ({id})", client.Name, client.Id); + } + else + { + _logger.LogWarning("Download client service not available for: {id}", client.Id); + } + } + catch (Exception ex) + { + _logger.LogError(ex, "Error initializing download client {id}: {message}", client.Id, ex.Message); + } } } } @@ -138,10 +153,9 @@ public sealed class QueueCleaner : GenericHandler if (record.Protocol is "torrent") { - if (_downloadClientConfig.DownloadClient is Common.Enums.DownloadClient.None && - _downloadClientConfig.Clients.Count == 0) + if (_downloadClientConfig.Clients.Count == 0) { - _logger.LogWarning("skip | download client is not configured | {title}", record.Title); + _logger.LogWarning("skip | no download clients configured | {title}", record.Title); continue; }