diff --git a/src/NzbDrone.Common.Test/ConfigFileProviderTest.cs b/src/NzbDrone.Common.Test/ConfigFileProviderTest.cs index f381a96a0..b6fe45584 100644 --- a/src/NzbDrone.Common.Test/ConfigFileProviderTest.cs +++ b/src/NzbDrone.Common.Test/ConfigFileProviderTest.cs @@ -1,10 +1,12 @@ using System.Collections.Generic; using FluentAssertions; +using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; +using NzbDrone.Common.Options; using NzbDrone.Core.Authentication; using NzbDrone.Core.Configuration; using NzbDrone.Test.Common; @@ -43,6 +45,26 @@ namespace NzbDrone.Common.Test Mocker.GetMock() .Setup(v => v.WriteAllText(configFile, It.IsAny())) .Callback((p, t) => _configFileContents = t); + + Mocker.GetMock>() + .Setup(v => v.Value) + .Returns(new AuthOptions()); + + Mocker.GetMock>() + .Setup(v => v.Value) + .Returns(new AppOptions()); + + Mocker.GetMock>() + .Setup(v => v.Value) + .Returns(new ServerOptions()); + + Mocker.GetMock>() + .Setup(v => v.Value) + .Returns(new LogOptions()); + + Mocker.GetMock>() + .Setup(v => v.Value) + .Returns(new UpdateOptions()); } [Test] diff --git a/src/NzbDrone.Common.Test/ServiceFactoryFixture.cs b/src/NzbDrone.Common.Test/ServiceFactoryFixture.cs index 58642f2e4..6749006e5 100644 --- a/src/NzbDrone.Common.Test/ServiceFactoryFixture.cs +++ b/src/NzbDrone.Common.Test/ServiceFactoryFixture.cs @@ -10,6 +10,7 @@ using NUnit.Framework; using NzbDrone.Common.Composition.Extensions; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Instrumentation.Extensions; +using NzbDrone.Common.Options; using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore.Extensions; using NzbDrone.Core.Lifecycle; @@ -33,6 +34,11 @@ namespace NzbDrone.Common.Test container.RegisterInstance(new Mock().Object); container.RegisterInstance(new Mock>().Object); + container.RegisterInstance(new Mock>().Object); + container.RegisterInstance(new Mock>().Object); + container.RegisterInstance(new Mock>().Object); + container.RegisterInstance(new Mock>().Object); + container.RegisterInstance(new Mock>().Object); var serviceProvider = container.GetServiceProvider(); diff --git a/src/NzbDrone.Common/Options/AppOptions.cs b/src/NzbDrone.Common/Options/AppOptions.cs new file mode 100644 index 000000000..74cdf1d29 --- /dev/null +++ b/src/NzbDrone.Common/Options/AppOptions.cs @@ -0,0 +1,8 @@ +namespace NzbDrone.Common.Options; + +public class AppOptions +{ + public string InstanceName { get; set; } + public string Theme { get; set; } + public bool? LaunchBrowser { get; set; } +} diff --git a/src/NzbDrone.Common/Options/AuthOptions.cs b/src/NzbDrone.Common/Options/AuthOptions.cs new file mode 100644 index 000000000..2b63308d3 --- /dev/null +++ b/src/NzbDrone.Common/Options/AuthOptions.cs @@ -0,0 +1,9 @@ +namespace NzbDrone.Common.Options; + +public class AuthOptions +{ + public string ApiKey { get; set; } + public bool? Enabled { get; set; } + public string Method { get; set; } + public string Required { get; set; } +} diff --git a/src/NzbDrone.Common/Options/LogOptions.cs b/src/NzbDrone.Common/Options/LogOptions.cs new file mode 100644 index 000000000..c36533cb4 --- /dev/null +++ b/src/NzbDrone.Common/Options/LogOptions.cs @@ -0,0 +1,14 @@ +namespace NzbDrone.Common.Options; + +public class LogOptions +{ + public string Level { get; set; } + public bool? FilterSentryEvents { get; set; } + public int? Rotate { get; set; } + public bool? Sql { get; set; } + public string ConsoleLevel { get; set; } + public bool? AnalyticsEnabled { get; set; } + public string SyslogServer { get; set; } + public int? SyslogPort { get; set; } + public string SyslogLevel { get; set; } +} diff --git a/src/NzbDrone.Common/Options/ServerOptions.cs b/src/NzbDrone.Common/Options/ServerOptions.cs new file mode 100644 index 000000000..d21e12b2a --- /dev/null +++ b/src/NzbDrone.Common/Options/ServerOptions.cs @@ -0,0 +1,12 @@ +namespace NzbDrone.Common.Options; + +public class ServerOptions +{ + public string UrlBase { get; set; } + public string BindAddress { get; set; } + public int? Port { get; set; } + public bool? EnableSsl { get; set; } + public int? SslPort { get; set; } + public string SslCertPath { get; set; } + public string SslCertPassword { get; set; } +} diff --git a/src/NzbDrone.Common/Options/UpdateOptions.cs b/src/NzbDrone.Common/Options/UpdateOptions.cs new file mode 100644 index 000000000..a8eaad8fb --- /dev/null +++ b/src/NzbDrone.Common/Options/UpdateOptions.cs @@ -0,0 +1,9 @@ +namespace NzbDrone.Common.Options; + +public class UpdateOptions +{ + public string Mechanism { get; set; } + public bool? Automatically { get; set; } + public string ScriptPath { get; set; } + public string Branch { get; set; } +} diff --git a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs index fc2a29eb4..e1168c2fb 100644 --- a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs +++ b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs @@ -10,6 +10,7 @@ using NzbDrone.Common.Cache; using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; +using NzbDrone.Common.Options; using NzbDrone.Core.Authentication; using NzbDrone.Core.Configuration.Events; using NzbDrone.Core.Datastore; @@ -70,6 +71,11 @@ namespace NzbDrone.Core.Configuration private readonly IDiskProvider _diskProvider; private readonly ICached _cache; private readonly PostgresOptions _postgresOptions; + private readonly AuthOptions _authOptions; + private readonly AppOptions _appOptions; + private readonly ServerOptions _serverOptions; + private readonly UpdateOptions _updateOptions; + private readonly LogOptions _logOptions; private readonly string _configFile; private static readonly Regex HiddenCharacterRegex = new Regex("[^a-z0-9]", RegexOptions.Compiled | RegexOptions.IgnoreCase); @@ -80,13 +86,23 @@ namespace NzbDrone.Core.Configuration ICacheManager cacheManager, IEventAggregator eventAggregator, IDiskProvider diskProvider, - IOptions postgresOptions) + IOptions postgresOptions, + IOptions authOptions, + IOptions appOptions, + IOptions serverOptions, + IOptions updateOptions, + IOptions logOptions) { _cache = cacheManager.GetCache(GetType()); _eventAggregator = eventAggregator; _diskProvider = diskProvider; _configFile = appFolderInfo.GetConfigPath(); _postgresOptions = postgresOptions.Value; + _authOptions = authOptions.Value; + _appOptions = appOptions.Value; + _serverOptions = serverOptions.Value; + _updateOptions = updateOptions.Value; + _logOptions = logOptions.Value; } public Dictionary GetConfigDictionary() @@ -142,7 +158,7 @@ namespace NzbDrone.Core.Configuration { const string defaultValue = "*"; - var bindAddress = GetValue("BindAddress", defaultValue); + var bindAddress = _serverOptions.BindAddress ?? GetValue("BindAddress", defaultValue); if (string.IsNullOrWhiteSpace(bindAddress)) { return defaultValue; @@ -152,19 +168,19 @@ namespace NzbDrone.Core.Configuration } } - public int Port => GetValueInt("Port", 8989); + public int Port => _serverOptions.Port ?? GetValueInt("Port", 8989); - public int SslPort => GetValueInt("SslPort", 9898); + public int SslPort => _serverOptions.SslPort ?? GetValueInt("SslPort", 9898); - public bool EnableSsl => GetValueBoolean("EnableSsl", false); + public bool EnableSsl => _serverOptions.EnableSsl ?? GetValueBoolean("EnableSsl", false); - public bool LaunchBrowser => GetValueBoolean("LaunchBrowser", true); + public bool LaunchBrowser => _appOptions.LaunchBrowser ?? GetValueBoolean("LaunchBrowser", true); public string ApiKey { get { - var apiKey = GetValue("ApiKey", GenerateApiKey()); + var apiKey = _authOptions.ApiKey ?? GetValue("ApiKey", GenerateApiKey()); if (apiKey.IsNullOrWhiteSpace()) { @@ -180,7 +196,7 @@ namespace NzbDrone.Core.Configuration { get { - var enabled = GetValueBoolean("AuthenticationEnabled", false, false); + var enabled = _authOptions.Enabled ?? GetValueBoolean("AuthenticationEnabled", false, false); if (enabled) { @@ -188,20 +204,25 @@ namespace NzbDrone.Core.Configuration return AuthenticationType.Basic; } - return GetValueEnum("AuthenticationMethod", AuthenticationType.None); + return Enum.TryParse(_authOptions.Method, out var enumValue) + ? enumValue + : GetValueEnum("AuthenticationMethod", AuthenticationType.None); } } - public AuthenticationRequiredType AuthenticationRequired => GetValueEnum("AuthenticationRequired", AuthenticationRequiredType.Enabled); + public AuthenticationRequiredType AuthenticationRequired => + Enum.TryParse(_authOptions.Required, out var enumValue) + ? enumValue + : GetValueEnum("AuthenticationRequired", AuthenticationRequiredType.Enabled); - public bool AnalyticsEnabled => GetValueBoolean("AnalyticsEnabled", true, persist: false); + public bool AnalyticsEnabled => _logOptions.AnalyticsEnabled ?? GetValueBoolean("AnalyticsEnabled", true, persist: false); - public string Branch => GetValue("Branch", "main").ToLowerInvariant(); + public string Branch => _updateOptions.Branch ?? GetValue("Branch", "main").ToLowerInvariant(); - public string LogLevel => GetValue("LogLevel", "info").ToLowerInvariant(); - public string ConsoleLogLevel => GetValue("ConsoleLogLevel", string.Empty, persist: false); + public string LogLevel => _logOptions.Level ?? GetValue("LogLevel", "info").ToLowerInvariant(); + public string ConsoleLogLevel => _logOptions.ConsoleLevel ?? GetValue("ConsoleLogLevel", string.Empty, persist: false); - public string Theme => GetValue("Theme", "auto", persist: false); + public string Theme => _appOptions.Theme ?? GetValue("Theme", "auto", persist: false); public string PostgresHost => _postgresOptions?.Host ?? GetValue("PostgresHost", string.Empty, persist: false); public string PostgresUser => _postgresOptions?.User ?? GetValue("PostgresUser", string.Empty, persist: false); @@ -210,17 +231,17 @@ namespace NzbDrone.Core.Configuration public string PostgresLogDb => _postgresOptions?.LogDb ?? GetValue("PostgresLogDb", "sonarr-log", persist: false); public int PostgresPort => (_postgresOptions?.Port ?? 0) != 0 ? _postgresOptions.Port : GetValueInt("PostgresPort", 5432, persist: false); - public bool LogSql => GetValueBoolean("LogSql", false, persist: false); - public int LogRotate => GetValueInt("LogRotate", 50, persist: false); - public bool FilterSentryEvents => GetValueBoolean("FilterSentryEvents", true, persist: false); - public string SslCertPath => GetValue("SslCertPath", ""); - public string SslCertPassword => GetValue("SslCertPassword", ""); + public bool LogSql => _logOptions.Sql ?? GetValueBoolean("LogSql", false, persist: false); + public int LogRotate => _logOptions.Rotate ?? GetValueInt("LogRotate", 50, persist: false); + public bool FilterSentryEvents => _logOptions.FilterSentryEvents ?? GetValueBoolean("FilterSentryEvents", true, persist: false); + public string SslCertPath => _serverOptions.SslCertPath ?? GetValue("SslCertPath", ""); + public string SslCertPassword => _serverOptions.SslCertPassword ?? GetValue("SslCertPassword", ""); public string UrlBase { get { - var urlBase = GetValue("UrlBase", "").Trim('/'); + var urlBase = _serverOptions.UrlBase ?? GetValue("UrlBase", "").Trim('/'); if (urlBase.IsNullOrWhiteSpace()) { @@ -237,7 +258,7 @@ namespace NzbDrone.Core.Configuration { get { - var instanceName = GetValue("InstanceName", BuildInfo.AppName); + var instanceName = _appOptions.InstanceName ?? GetValue("InstanceName", BuildInfo.AppName); if (instanceName.StartsWith(BuildInfo.AppName) || instanceName.EndsWith(BuildInfo.AppName)) { @@ -248,17 +269,20 @@ namespace NzbDrone.Core.Configuration } } - public bool UpdateAutomatically => GetValueBoolean("UpdateAutomatically", false, false); + public bool UpdateAutomatically => _updateOptions.Automatically ?? GetValueBoolean("UpdateAutomatically", false, false); - public UpdateMechanism UpdateMechanism => GetValueEnum("UpdateMechanism", UpdateMechanism.BuiltIn, false); + public UpdateMechanism UpdateMechanism => + Enum.TryParse(_updateOptions.Mechanism, out var enumValue) + ? enumValue + : GetValueEnum("UpdateMechanism", UpdateMechanism.BuiltIn, false); - public string UpdateScriptPath => GetValue("UpdateScriptPath", "", false); + public string UpdateScriptPath => _updateOptions.ScriptPath ?? GetValue("UpdateScriptPath", "", false); - public string SyslogServer => GetValue("SyslogServer", "", persist: false); + public string SyslogServer => _logOptions.SyslogServer ?? GetValue("SyslogServer", "", persist: false); - public int SyslogPort => GetValueInt("SyslogPort", 514, persist: false); + public int SyslogPort => _logOptions.SyslogPort ?? GetValueInt("SyslogPort", 514, persist: false); - public string SyslogLevel => GetValue("SyslogLevel", LogLevel, persist: false).ToLowerInvariant(); + public string SyslogLevel => _logOptions.SyslogLevel ?? GetValue("SyslogLevel", LogLevel, persist: false).ToLowerInvariant(); public int GetValueInt(string key, int defaultValue, bool persist = true) { diff --git a/src/NzbDrone.Host.Test/ContainerFixture.cs b/src/NzbDrone.Host.Test/ContainerFixture.cs index 6a43eaff9..8279a18f0 100644 --- a/src/NzbDrone.Host.Test/ContainerFixture.cs +++ b/src/NzbDrone.Host.Test/ContainerFixture.cs @@ -12,6 +12,7 @@ using NzbDrone.Common; using NzbDrone.Common.Composition.Extensions; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Instrumentation.Extensions; +using NzbDrone.Common.Options; using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore.Extensions; using NzbDrone.Core.Download; @@ -46,6 +47,11 @@ namespace NzbDrone.App.Test container.RegisterInstance(new Mock().Object); container.RegisterInstance(new Mock().Object); container.RegisterInstance>(new Mock>().Object); + container.RegisterInstance>(new Mock>().Object); + container.RegisterInstance>(new Mock>().Object); + container.RegisterInstance>(new Mock>().Object); + container.RegisterInstance>(new Mock>().Object); + container.RegisterInstance>(new Mock>().Object); _container = container.GetServiceProvider(); } diff --git a/src/NzbDrone.Host/Bootstrap.cs b/src/NzbDrone.Host/Bootstrap.cs index 0e9ff30a4..2073eb622 100644 --- a/src/NzbDrone.Host/Bootstrap.cs +++ b/src/NzbDrone.Host/Bootstrap.cs @@ -20,6 +20,7 @@ using NzbDrone.Common.Exceptions; using NzbDrone.Common.Extensions; using NzbDrone.Common.Instrumentation; using NzbDrone.Common.Instrumentation.Extensions; +using NzbDrone.Common.Options; using NzbDrone.Core.Configuration; using NzbDrone.Core.Datastore.Extensions; using Sonarr.Http.ClientSchema; @@ -98,6 +99,11 @@ namespace NzbDrone.Host .ConfigureServices(services => { services.Configure(config.GetSection("Sonarr:Postgres")); + services.Configure(config.GetSection("Sonarr:App")); + services.Configure(config.GetSection("Sonarr:Auth")); + services.Configure(config.GetSection("Sonarr:Server")); + services.Configure(config.GetSection("Sonarr:Log")); + services.Configure(config.GetSection("Sonarr:Update")); }).Build(); break; @@ -119,12 +125,12 @@ namespace NzbDrone.Host { var config = GetConfiguration(context); - var bindAddress = config.GetValue(nameof(ConfigFileProvider.BindAddress), "*"); - var port = config.GetValue(nameof(ConfigFileProvider.Port), 8989); - var sslPort = config.GetValue(nameof(ConfigFileProvider.SslPort), 9898); - var enableSsl = config.GetValue(nameof(ConfigFileProvider.EnableSsl), false); - var sslCertPath = config.GetValue(nameof(ConfigFileProvider.SslCertPath)); - var sslCertPassword = config.GetValue(nameof(ConfigFileProvider.SslCertPassword)); + var bindAddress = config.GetValue($"Sonarr:Server:{nameof(ServerOptions.BindAddress)}") ?? config.GetValue(nameof(ConfigFileProvider.BindAddress), "*"); + var port = config.GetValue($"Sonarr:Server:{nameof(ServerOptions.Port)}") ?? config.GetValue(nameof(ConfigFileProvider.Port), 8989); + var sslPort = config.GetValue($"Sonarr:Server:{nameof(ServerOptions.SslPort)}") ?? config.GetValue(nameof(ConfigFileProvider.SslPort), 9898); + var enableSsl = config.GetValue($"Sonarr:Server:{nameof(ServerOptions.EnableSsl)}") ?? config.GetValue(nameof(ConfigFileProvider.EnableSsl), false); + var sslCertPath = config.GetValue($"Sonarr:Server:{nameof(ServerOptions.SslCertPath)}") ?? config.GetValue(nameof(ConfigFileProvider.SslCertPath)); + var sslCertPassword = config.GetValue($"Sonarr:Server:{nameof(ServerOptions.SslCertPassword)}") ?? config.GetValue(nameof(ConfigFileProvider.SslCertPassword)); var urls = new List { BuildUrl("http", bindAddress, port) }; @@ -152,6 +158,11 @@ namespace NzbDrone.Host .ConfigureServices(services => { services.Configure(config.GetSection("Sonarr:Postgres")); + services.Configure(config.GetSection("Sonarr:App")); + services.Configure(config.GetSection("Sonarr:Auth")); + services.Configure(config.GetSection("Sonarr:Server")); + services.Configure(config.GetSection("Sonarr:Log")); + services.Configure(config.GetSection("Sonarr:Update")); }) .ConfigureWebHost(builder => {