diff --git a/code/Common/Configuration/DownloadClient/ClientConfig.cs b/code/Common/Configuration/DownloadClient/ClientConfig.cs
new file mode 100644
index 00000000..b045a35e
--- /dev/null
+++ b/code/Common/Configuration/DownloadClient/ClientConfig.cs
@@ -0,0 +1,69 @@
+using Microsoft.Extensions.Configuration;
+
+namespace Common.Configuration.DownloadClient;
+
+///
+/// Configuration for a specific download client
+///
+public sealed record ClientConfig
+{
+ ///
+ /// Unique identifier for this client
+ ///
+ [ConfigurationKeyName("ID")]
+ public string Id { get; init; } = Guid.NewGuid().ToString("N");
+
+ ///
+ /// Friendly name for this client
+ ///
+ [ConfigurationKeyName("NAME")]
+ public string Name { get; init; } = string.Empty;
+
+ ///
+ /// Type of download client
+ ///
+ [ConfigurationKeyName("TYPE")]
+ public Common.Enums.DownloadClient Type { get; init; } = Common.Enums.DownloadClient.None;
+
+ ///
+ /// Host address for the download client
+ ///
+ [ConfigurationKeyName("HOST")]
+ public string Host { get; init; } = string.Empty;
+
+ ///
+ /// Port for the download client
+ ///
+ [ConfigurationKeyName("PORT")]
+ public int Port { get; init; }
+
+ ///
+ /// Username for authentication
+ ///
+ [ConfigurationKeyName("USERNAME")]
+ public string Username { get; init; } = string.Empty;
+
+ ///
+ /// Password for authentication
+ ///
+ [ConfigurationKeyName("PASSWORD")]
+ public string Password { get; init; } = string.Empty;
+
+ ///
+ /// Default category to use
+ ///
+ [ConfigurationKeyName("CATEGORY")]
+ public string Category { get; init; } = string.Empty;
+
+ ///
+ /// Path to download directory
+ ///
+ [ConfigurationKeyName("PATH")]
+ public string Path { get; init; } = string.Empty;
+
+ ///
+ /// Whether this client is enabled
+ ///
+ [ConfigurationKeyName("ENABLED")]
+ public bool Enabled { get; init; } = true;
+}
diff --git a/code/Common/Configuration/DownloadClient/DownloadClientConfig.cs b/code/Common/Configuration/DownloadClient/DownloadClientConfig.cs
index dd7da2e3..c29d1f90 100644
--- a/code/Common/Configuration/DownloadClient/DownloadClientConfig.cs
+++ b/code/Common/Configuration/DownloadClient/DownloadClientConfig.cs
@@ -1,14 +1,124 @@
-using Microsoft.Extensions.Configuration;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Common.Enums;
+using Microsoft.Extensions.Configuration;
namespace Common.Configuration.DownloadClient;
public sealed record DownloadClientConfig : IConfig
{
- [ConfigurationKeyName("DOWNLOAD_CLIENT")]
- public Enums.DownloadClient DownloadClient { get; init; } = Enums.DownloadClient.None;
+ public const string SectionName = "DownloadClient";
+ ///
+ /// Collection of download clients configured for the application
+ ///
+ public List Clients { get; init; } = new();
+
+ ///
+ /// Gets a client configuration by id
+ ///
+ /// The client id
+ /// The client configuration or null if not found
+ public ClientConfig? GetClientConfig(string id)
+ {
+ return Clients.FirstOrDefault(c => c.Id == id);
+ }
+
+ ///
+ /// Gets all enabled clients
+ ///
+ /// Collection of enabled client configurations
+ public IEnumerable GetEnabledClients()
+ {
+ return Clients.Where(c => c.Enabled);
+ }
+
+ ///
+ /// Validates the configuration to ensure it meets requirements
+ ///
public void Validate()
{
- throw new NotImplementedException();
+ // Validate clients have unique IDs
+ var duplicateIds = Clients
+ .GroupBy(c => c.Id)
+ .Where(g => g.Count() > 1)
+ .Select(g => g.Key)
+ .ToList();
+
+ if (duplicateIds.Any())
+ {
+ throw new InvalidOperationException($"Duplicate client IDs found: {string.Join(", ", duplicateIds)}");
+ }
+
+ // Validate each client configuration
+ foreach (var client in Clients)
+ {
+ if (string.IsNullOrWhiteSpace(client.Id))
+ {
+ throw new InvalidOperationException("Client ID cannot be empty");
+ }
+
+ if (string.IsNullOrWhiteSpace(client.Name))
+ {
+ throw new InvalidOperationException($"Client name cannot be empty for client ID: {client.Id}");
+ }
+
+ if (string.IsNullOrWhiteSpace(client.Host))
+ {
+ throw new InvalidOperationException($"Host cannot be empty for client ID: {client.Id}");
+ }
+
+ if (client.Port <= 0)
+ {
+ throw new InvalidOperationException($"Port must be greater than 0 for client ID: {client.Id}");
+ }
+ }
}
+}
+
+///
+/// Represents a download client configuration
+///
+public class ClientConfig
+{
+ ///
+ /// Unique identifier for the client
+ ///
+ public string Id { get; init; } = string.Empty;
+
+ ///
+ /// Display name of the client
+ ///
+ public string Name { get; init; } = string.Empty;
+
+ ///
+ /// Host address (IP or hostname)
+ ///
+ public string Host { get; init; } = string.Empty;
+
+ ///
+ /// Port number
+ ///
+ public int Port { get; init; }
+
+ ///
+ /// Username for authentication (if required)
+ ///
+ public string? Username { get; init; }
+
+ ///
+ /// Password for authentication (if required)
+ ///
+ public string? Password { get; init; }
+
+ ///
+ /// Type of download client
+ ///
+ public DownloadClientType Type { get; init; } = DownloadClientType.QBittorrent;
+
+ ///
+ /// Whether the client is enabled
+ ///
+ public bool Enabled { get; init; } = true;
}
\ No newline at end of file
diff --git a/code/Executable/Controllers/ConfigurationController.cs b/code/Executable/Controllers/ConfigurationController.cs
index 03aef25d..57357737 100644
--- a/code/Executable/Controllers/ConfigurationController.cs
+++ b/code/Executable/Controllers/ConfigurationController.cs
@@ -178,6 +178,9 @@ public class ConfigurationController : ControllerBase
{
try
{
+ // Validate the configuration
+ config.Validate();
+
// Persist the configuration
var result = await _configService.UpdateDownloadClientConfigAsync(config);
if (!result)
@@ -190,8 +193,8 @@ public class ConfigurationController : ControllerBase
}
catch (Exception ex)
{
- _logger.LogError(ex, "Error updating DownloadClient configuration");
- return StatusCode(500, "An error occurred while updating DownloadClient configuration");
+ _logger.LogError(ex, "Error updating DownloadClient configuration: {Message}", ex.Message);
+ return BadRequest(new { Error = ex.Message });
}
}
diff --git a/code/Executable/Controllers/StatusController.cs b/code/Executable/Controllers/StatusController.cs
index c9c3facb..2187fbdf 100644
--- a/code/Executable/Controllers/StatusController.cs
+++ b/code/Executable/Controllers/StatusController.cs
@@ -1,9 +1,9 @@
using Common.Configuration.Arr;
using Common.Configuration.DownloadClient;
+using Infrastructure.Configuration;
using Infrastructure.Verticals.Arr;
using Infrastructure.Verticals.DownloadClient;
using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Options;
using System.Diagnostics;
namespace Executable.Controllers;
@@ -13,38 +13,41 @@ namespace Executable.Controllers;
public class StatusController : ControllerBase
{
private readonly ILogger _logger;
- private readonly IOptionsMonitor _downloadClientConfig;
- private readonly IOptionsMonitor _sonarrConfig;
- private readonly IOptionsMonitor _radarrConfig;
- private readonly IOptionsMonitor _lidarrConfig;
+ private readonly IConfigurationManager _configManager;
private readonly DownloadServiceFactory _downloadServiceFactory;
private readonly ArrClientFactory _arrClientFactory;
public StatusController(
ILogger logger,
- IOptionsMonitor downloadClientConfig,
- IOptionsMonitor sonarrConfig,
- IOptionsMonitor radarrConfig,
- IOptionsMonitor lidarrConfig,
+ IConfigurationManager configManager,
DownloadServiceFactory downloadServiceFactory,
ArrClientFactory arrClientFactory)
{
_logger = logger;
- _downloadClientConfig = downloadClientConfig;
- _sonarrConfig = sonarrConfig;
- _radarrConfig = radarrConfig;
- _lidarrConfig = lidarrConfig;
+ _configManager = configManager;
_downloadServiceFactory = downloadServiceFactory;
_arrClientFactory = arrClientFactory;
}
[HttpGet]
- public IActionResult GetSystemStatus()
+ public async Task GetSystemStatus()
{
try
{
var process = Process.GetCurrentProcess();
+ // Get configuration
+ var downloadClientConfig = await _configManager.GetDownloadClientConfigAsync();
+ var sonarrConfig = await _configManager.GetSonarrConfigAsync();
+ var radarrConfig = await _configManager.GetRadarrConfigAsync();
+ var lidarrConfig = await _configManager.GetLidarrConfigAsync();
+
+ // Default if configs are null
+ downloadClientConfig ??= new DownloadClientConfig();
+ sonarrConfig ??= new SonarrConfig();
+ radarrConfig ??= new RadarrConfig();
+ lidarrConfig ??= new LidarrConfig();
+
var status = new
{
Application = new
@@ -57,26 +60,29 @@ public class StatusController : ControllerBase
},
DownloadClient = new
{
- Type = _downloadClientConfig.CurrentValue.DownloadClient.ToString(),
- IsConfigured = _downloadClientConfig.CurrentValue.DownloadClient != Common.Enums.DownloadClient.None &&
- _downloadClientConfig.CurrentValue.DownloadClient != Common.Enums.DownloadClient.Disabled
+ LegacyType = downloadClientConfig.DownloadClient.ToString(),
+ ConfiguredClientCount = downloadClientConfig.Clients.Count,
+ EnabledClientCount = downloadClientConfig.Clients.Count(c => c.Enabled),
+ IsConfigured = downloadClientConfig.DownloadClient != Common.Enums.DownloadClient.None &&
+ downloadClientConfig.DownloadClient != Common.Enums.DownloadClient.Disabled ||
+ downloadClientConfig.Clients.Any(c => c.Enabled)
},
MediaManagers = new
{
Sonarr = new
{
- IsEnabled = _sonarrConfig.CurrentValue.Enabled,
- InstanceCount = _sonarrConfig.CurrentValue.Instances?.Count ?? 0
+ IsEnabled = sonarrConfig.Enabled,
+ InstanceCount = sonarrConfig.Instances?.Count ?? 0
},
Radarr = new
{
- IsEnabled = _radarrConfig.CurrentValue.Enabled,
- InstanceCount = _radarrConfig.CurrentValue.Instances?.Count ?? 0
+ IsEnabled = radarrConfig.Enabled,
+ InstanceCount = radarrConfig.Instances?.Count ?? 0
},
Lidarr = new
{
- IsEnabled = _lidarrConfig.CurrentValue.Enabled,
- InstanceCount = _lidarrConfig.CurrentValue.Instances?.Count ?? 0
+ IsEnabled = lidarrConfig.Enabled,
+ InstanceCount = lidarrConfig.Instances?.Count ?? 0
}
}
};
@@ -95,37 +101,70 @@ public class StatusController : ControllerBase
{
try
{
- if (_downloadClientConfig.CurrentValue.DownloadClient == Common.Enums.DownloadClient.None ||
- _downloadClientConfig.CurrentValue.DownloadClient == Common.Enums.DownloadClient.Disabled)
+ var downloadClientConfig = await _configManager.GetDownloadClientConfigAsync();
+ if (downloadClientConfig == null)
{
- return NotFound("No download client is configured");
+ return NotFound("Download client configuration not found");
+ }
+
+ var result = new Dictionary();
+
+ // Check for configured clients
+ if (downloadClientConfig.Clients.Count > 0)
+ {
+ var clientsStatus = new List