1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-03-21 16:54:30 -04:00

Compare commits

...

4 Commits

Author SHA1 Message Date
ta264
c7c5d176be fixup! Modernize startup and ConfigFileProvider 2022-06-21 21:05:53 +01:00
ta264
31f082e516 Support legacy postgres options 2022-06-20 21:53:25 +01:00
ta264
a84ef3cd2f Rename configFileProvider 2022-06-20 21:35:11 +01:00
ta264
41e8f7aa45 Modernize startup and ConfigFileProvider 2022-06-20 21:35:11 +01:00
62 changed files with 853 additions and 892 deletions

View File

@@ -544,10 +544,10 @@ stages:
variables: variables:
pattern: 'Radarr.*.linux-core-x64.tar.gz' pattern: 'Radarr.*.linux-core-x64.tar.gz'
artifactName: linux-x64-tests artifactName: linux-x64-tests
Radarr__Postgres__Host: 'localhost' Radarr__PostgresHost: 'localhost'
Radarr__Postgres__Port: '5432' Radarr__PostgresPort: '5432'
Radarr__Postgres__User: 'radarr' Radarr__PostgresUser: 'radarr'
Radarr__Postgres__Password: 'radarr' Radarr__PostgresPassword: 'radarr'
pool: pool:
vmImage: 'ubuntu-18.04' vmImage: 'ubuntu-18.04'
@@ -681,10 +681,10 @@ stages:
condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0')) condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0'))
variables: variables:
pattern: 'Radarr.*.linux-core-x64.tar.gz' pattern: 'Radarr.*.linux-core-x64.tar.gz'
Radarr__Postgres__Host: 'localhost' Radarr__PostgresHost: 'localhost'
Radarr__Postgres__Port: '5432' Radarr__PostgresPort: '5432'
Radarr__Postgres__User: 'radarr' Radarr__PostgresUser: 'radarr'
Radarr__Postgres__Password: 'radarr' Radarr__PostgresPassword: 'radarr'
pool: pool:
vmImage: 'ubuntu-18.04' vmImage: 'ubuntu-18.04'

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic; using System.Collections.Generic;
using FluentAssertions; using FluentAssertions;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
@@ -13,7 +13,7 @@ namespace NzbDrone.Common.Test
{ {
[TestFixture] [TestFixture]
public class ConfigFileProviderTest : TestBase<ConfigFileProvider> public class ConfigFileWriterTest : TestBase<ConfigFileWriter>
{ {
private string _configFileContents; private string _configFileContents;
private string _configFilePath; private string _configFilePath;
@@ -45,56 +45,7 @@ namespace NzbDrone.Common.Test
.Callback<string, string>((p, t) => _configFileContents = t); .Callback<string, string>((p, t) => _configFileContents = t);
} }
[Test] /*
public void GetValue_Success()
{
const string key = "Port";
const string value = "7878";
var result = Subject.GetValue(key, value);
result.Should().Be(value);
}
[Test]
public void GetInt_Success()
{
const string key = "Port";
const int value = 7878;
var result = Subject.GetValueInt(key, value);
result.Should().Be(value);
}
[Test]
public void GetBool_Success()
{
const string key = "LaunchBrowser";
const bool value = true;
var result = Subject.GetValueBoolean(key, value);
result.Should().BeTrue();
}
[Test]
public void GetLaunchBrowser_Success()
{
var result = Subject.LaunchBrowser;
result.Should().Be(true);
}
[Test]
public void GetPort_Success()
{
const int value = 7878;
var result = Subject.Port;
result.Should().Be(value);
}
[Test] [Test]
public void SetValue_bool() public void SetValue_bool()
@@ -120,17 +71,6 @@ namespace NzbDrone.Common.Test
result.Should().Be(value); result.Should().Be(value);
} }
[Test]
public void GetValue_New_Key()
{
const string key = "Hello";
const string value = "World";
var result = Subject.GetValue(key, value);
result.Should().Be(value);
}
[Test] [Test]
public void GetAuthenticationType_No_Existing_Value() public void GetAuthenticationType_No_Existing_Value()
{ {
@@ -139,6 +79,7 @@ namespace NzbDrone.Common.Test
result.Should().Be(AuthenticationType.None); result.Should().Be(AuthenticationType.None);
} }
/*
[Test] [Test]
public void SaveDictionary_should_save_proper_value() public void SaveDictionary_should_save_proper_value()
{ {
@@ -170,32 +111,6 @@ namespace NzbDrone.Common.Test
Subject.Port.Should().Be(port); Subject.Port.Should().Be(port);
Subject.SslPort.Should().Be(sslPort); Subject.SslPort.Should().Be(sslPort);
} }*/
[Test]
public void should_throw_if_config_file_is_empty()
{
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.FileExists(_configFilePath))
.Returns(true);
Assert.Throws<InvalidConfigFileException>(() => Subject.GetValue("key", "value"));
}
[Test]
public void should_throw_if_config_file_contains_only_null_character()
{
_configFileContents = "\0";
Assert.Throws<InvalidConfigFileException>(() => Subject.GetValue("key", "value"));
}
[Test]
public void should_throw_if_config_file_contains_invalid_xml()
{
_configFileContents = "{ \"key\": \"value\" }";
Assert.Throws<InvalidConfigFileException>(() => Subject.GetValue("key", "value"));
}
} }
} }

View File

@@ -2,6 +2,7 @@ using System.Linq;
using DryIoc; using DryIoc;
using DryIoc.Microsoft.DependencyInjection; using DryIoc.Microsoft.DependencyInjection;
using FluentAssertions; using FluentAssertions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@@ -10,7 +11,7 @@ using NUnit.Framework;
using NzbDrone.Common.Composition.Extensions; using NzbDrone.Common.Composition.Extensions;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Instrumentation.Extensions; using NzbDrone.Common.Instrumentation.Extensions;
using NzbDrone.Core.Datastore; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Datastore.Extensions; using NzbDrone.Core.Datastore.Extensions;
using NzbDrone.Core.Lifecycle; using NzbDrone.Core.Lifecycle;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
@@ -32,7 +33,8 @@ namespace NzbDrone.Common.Test
.AddStartupContext(new StartupContext("first", "second")); .AddStartupContext(new StartupContext("first", "second"));
container.RegisterInstance(new Mock<IHostLifetime>().Object); container.RegisterInstance(new Mock<IHostLifetime>().Object);
container.RegisterInstance(new Mock<IOptions<PostgresOptions>>().Object); container.RegisterInstance(new Mock<IConfiguration>().Object);
container.RegisterInstance(new Mock<IOptionsMonitor<ConfigFileOptions>>().Object);
var serviceProvider = container.GetServiceProvider(); var serviceProvider = container.GetServiceProvider();

View File

@@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using FluentAssertions; using FluentAssertions;

View File

@@ -3,9 +3,11 @@ using System.Collections.Generic;
using System.Data.SQLite; using System.Data.SQLite;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Moq;
using Npgsql; using Npgsql;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
@@ -124,13 +126,13 @@ namespace NzbDrone.Core.Test.Framework
private void CreatePostgresDb() private void CreatePostgresDb()
{ {
var options = Mocker.Resolve<IOptions<PostgresOptions>>().Value; var options = Mocker.Resolve<IOptionsMonitor<ConfigFileOptions>>().CurrentValue;
PostgresDatabase.Create(options, MigrationType); PostgresDatabase.Create(options, MigrationType);
} }
private void DropPostgresDb() private void DropPostgresDb()
{ {
var options = Mocker.Resolve<IOptions<PostgresOptions>>().Value; var options = Mocker.Resolve<IOptionsMonitor<ConfigFileOptions>>().CurrentValue;
PostgresDatabase.Drop(options, MigrationType); PostgresDatabase.Drop(options, MigrationType);
} }
@@ -174,12 +176,11 @@ namespace NzbDrone.Core.Test.Framework
SetupLogging(); SetupLogging();
// populate the possible postgres options // populate the possible postgres options
var postgresOptions = PostgresDatabase.GetTestOptions(); var options = PostgresDatabase.GetTestOptions();
_databaseType = postgresOptions.Host.IsNotNullOrWhiteSpace() ? DatabaseType.PostgreSQL : DatabaseType.SQLite; _databaseType = options.PostgresHost.IsNotNullOrWhiteSpace() ? DatabaseType.PostgreSQL : DatabaseType.SQLite;
// Set up remaining container services // Set up remaining container services
Mocker.SetConstant(Options.Create(postgresOptions)); Mocker.GetMock<IOptionsMonitor<ConfigFileOptions>>().Setup(x => x.CurrentValue).Returns(options);
Mocker.SetConstant<IConfigFileProvider>(Mocker.Resolve<ConfigFileProvider>());
Mocker.SetConstant<IConnectionStringFactory>(Mocker.Resolve<ConnectionStringFactory>()); Mocker.SetConstant<IConnectionStringFactory>(Mocker.Resolve<ConnectionStringFactory>());
Mocker.SetConstant<IMigrationController>(Mocker.Resolve<MigrationController>()); Mocker.SetConstant<IMigrationController>(Mocker.Resolve<MigrationController>());

View File

@@ -0,0 +1,51 @@
using System;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Core.HealthCheck.Checks;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.HealthCheck.Checks
{
[TestFixture]
public class LegacyPostgresCheckFixture : CoreTest<LegacyPostgresCheck>
{
[SetUp]
public void Setup()
{
Mocker.GetMock<ILocalizationService>()
.Setup(s => s.GetLocalizedString(It.IsAny<string>()))
.Returns("Warning {0} -> {1}");
}
[TearDown]
public void Teardown()
{
foreach (var name in new[] { "__Postgres__Host", "__Postgres__Port", ":Postgres:Host", ":Postgres:Port" })
{
Environment.SetEnvironmentVariable(BuildInfo.AppName + name, null);
}
}
[Test]
public void should_return_ok_normally()
{
Subject.Check().ShouldBeOk();
}
[TestCase("__")]
[TestCase(":")]
public void should_return_error_if_vars_defined(string separator)
{
Environment.SetEnvironmentVariable(BuildInfo.AppName + separator + "Postgres" + separator + "Host", "localhost");
Environment.SetEnvironmentVariable(BuildInfo.AppName + separator + "Postgres" + separator + "Port", "localhost");
var result = Subject.Check();
result.ShouldBeError("Warning " + BuildInfo.AppName + separator + "Postgres" + separator + "Host, " +
BuildInfo.AppName + separator + "Postgres" + separator + "Port -> " +
BuildInfo.AppName + separator + "PostgresHost, " +
BuildInfo.AppName + separator + "PostgresPort");
}
}
}

View File

@@ -1,9 +1,11 @@
using Microsoft.Extensions.Options;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.HealthCheck.Checks; using NzbDrone.Core.HealthCheck.Checks;
using NzbDrone.Core.Localization; using NzbDrone.Core.Localization;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Update;
namespace NzbDrone.Core.Test.HealthCheck.Checks namespace NzbDrone.Core.Test.HealthCheck.Checks
{ {
@@ -20,9 +22,9 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
private void GivenValidBranch(string branch) private void GivenValidBranch(string branch)
{ {
Mocker.GetMock<IConfigFileProvider>() Mocker.GetMock<IOptionsMonitor<ConfigFileOptions>>()
.SetupGet(s => s.Branch) .Setup(s => s.CurrentValue)
.Returns(branch); .Returns(new ConfigFileOptions { Branch = branch });
} }
[TestCase("aphrodite")] [TestCase("aphrodite")]

View File

@@ -1,3 +1,4 @@
using Microsoft.Extensions.Options;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
@@ -19,6 +20,10 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
Mocker.GetMock<ILocalizationService>() Mocker.GetMock<ILocalizationService>()
.Setup(s => s.GetLocalizedString(It.IsAny<string>())) .Setup(s => s.GetLocalizedString(It.IsAny<string>()))
.Returns("Some Warning Message"); .Returns("Some Warning Message");
Mocker.GetMock<IOptionsMonitor<ConfigFileOptions>>()
.Setup(c => c.CurrentValue)
.Returns(new ConfigFileOptions());
} }
[Test] [Test]
@@ -44,9 +49,9 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
const string startupFolder = @"/opt/nzbdrone"; const string startupFolder = @"/opt/nzbdrone";
Mocker.GetMock<IConfigFileProvider>() Mocker.GetMock<IOptionsMonitor<ConfigFileOptions>>()
.Setup(s => s.UpdateAutomatically) .Setup(s => s.CurrentValue)
.Returns(true); .Returns(new ConfigFileOptions { UpdateAutomatically = true });
Mocker.GetMock<IAppFolderInfo>() Mocker.GetMock<IAppFolderInfo>()
.Setup(s => s.StartUpFolder) .Setup(s => s.StartUpFolder)
@@ -67,9 +72,9 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
const string startupFolder = @"/opt/nzbdrone"; const string startupFolder = @"/opt/nzbdrone";
const string uiFolder = @"/opt/nzbdrone/UI"; const string uiFolder = @"/opt/nzbdrone/UI";
Mocker.GetMock<IConfigFileProvider>() Mocker.GetMock<IOptionsMonitor<ConfigFileOptions>>()
.Setup(s => s.UpdateAutomatically) .Setup(s => s.CurrentValue)
.Returns(true); .Returns(new ConfigFileOptions { UpdateAutomatically = true });
Mocker.GetMock<IAppFolderInfo>() Mocker.GetMock<IAppFolderInfo>()
.Setup(s => s.StartUpFolder) .Setup(s => s.StartUpFolder)
@@ -91,13 +96,9 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
{ {
PosixOnly(); PosixOnly();
Mocker.GetMock<IConfigFileProvider>() Mocker.GetMock<IOptionsMonitor<ConfigFileOptions>>()
.Setup(s => s.UpdateAutomatically) .Setup(s => s.CurrentValue)
.Returns(true); .Returns(new ConfigFileOptions { UpdateAutomatically = true, UpdateMechanism = UpdateMechanism.Script });
Mocker.GetMock<IConfigFileProvider>()
.Setup(s => s.UpdateMechanism)
.Returns(UpdateMechanism.Script);
Mocker.GetMock<IAppFolderInfo>() Mocker.GetMock<IAppFolderInfo>()
.Setup(s => s.StartUpFolder) .Setup(s => s.StartUpFolder)

View File

@@ -4,10 +4,12 @@ using System.IO;
using System.Linq; using System.Linq;
using FizzWare.NBuilder; using FizzWare.NBuilder;
using FluentAssertions; using FluentAssertions;
using Microsoft.Extensions.Options;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.MediaCover; using NzbDrone.Core.MediaCover;
using NzbDrone.Core.Movies; using NzbDrone.Core.Movies;
using NzbDrone.Core.Movies.Events; using NzbDrone.Core.Movies.Events;
@@ -31,6 +33,10 @@ namespace NzbDrone.Core.Test.MediaCoverTests
.Build(); .Build();
Mocker.GetMock<IMovieService>().Setup(m => m.GetMovie(It.Is<int>(id => id == _movie.Id))).Returns(_movie); Mocker.GetMock<IMovieService>().Setup(m => m.GetMovie(It.Is<int>(id => id == _movie.Id))).Returns(_movie);
Mocker.GetMock<IOptionsMonitor<ConfigFileOptions>>()
.Setup(x => x.CurrentValue)
.Returns(new ConfigFileOptions());
} }
[Test] [Test]

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using FluentAssertions; using FluentAssertions;
using Microsoft.Extensions.Options;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common; using NzbDrone.Common;
@@ -60,9 +61,9 @@ namespace NzbDrone.Core.Test.UpdateTests
Mocker.GetMock<IProcessProvider>().Setup(c => c.GetCurrentProcess()).Returns(new ProcessInfo { Id = 12 }); Mocker.GetMock<IProcessProvider>().Setup(c => c.GetCurrentProcess()).Returns(new ProcessInfo { Id = 12 });
Mocker.GetMock<IRuntimeInfo>().Setup(c => c.ExecutingApplication).Returns(@"C:\Test\Radarr.exe"); Mocker.GetMock<IRuntimeInfo>().Setup(c => c.ExecutingApplication).Returns(@"C:\Test\Radarr.exe");
Mocker.GetMock<IConfigFileProvider>() Mocker.GetMock<IOptionsMonitor<ConfigFileOptions>>()
.SetupGet(s => s.UpdateAutomatically) .Setup(s => s.CurrentValue)
.Returns(true); .Returns(new ConfigFileOptions { UpdateAutomatically = true });
Mocker.GetMock<IDiskProvider>() Mocker.GetMock<IDiskProvider>()
.Setup(c => c.FolderWritable(It.IsAny<string>())) .Setup(c => c.FolderWritable(It.IsAny<string>()))
@@ -77,13 +78,9 @@ namespace NzbDrone.Core.Test.UpdateTests
private void GivenInstallScript(string path) private void GivenInstallScript(string path)
{ {
Mocker.GetMock<IConfigFileProvider>() Mocker.GetMock<IOptionsMonitor<ConfigFileOptions>>()
.SetupGet(s => s.UpdateMechanism) .Setup(s => s.CurrentValue)
.Returns(UpdateMechanism.Script); .Returns(new ConfigFileOptions { UpdateAutomatically = true, UpdateMechanism = UpdateMechanism.Script, UpdateScriptPath = path });
Mocker.GetMock<IConfigFileProvider>()
.SetupGet(s => s.UpdateScriptPath)
.Returns(path);
Mocker.GetMock<IDiskProvider>() Mocker.GetMock<IDiskProvider>()
.Setup(s => s.FileExists(path, StringComparison.Ordinal)) .Setup(s => s.FileExists(path, StringComparison.Ordinal))
@@ -334,7 +331,7 @@ namespace NzbDrone.Core.Test.UpdateTests
Subject.Execute(new ApplicationUpdateCommand()); Subject.Execute(new ApplicationUpdateCommand());
Mocker.GetMock<IConfigFileProvider>() Mocker.GetMock<IConfigFileWriter>()
.Verify(v => v.SaveConfigDictionary(It.Is<Dictionary<string, object>>(d => d.ContainsKey("Branch") && (string)d["Branch"] == "fake")), Times.Once()); .Verify(v => v.SaveConfigDictionary(It.Is<Dictionary<string, object>>(d => d.ContainsKey("Branch") && (string)d["Branch"] == "fake")), Times.Once());
} }

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Linq; using System.Linq;
using Microsoft.Extensions.Options;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore;
@@ -15,16 +16,16 @@ namespace NzbDrone.Core.Analytics
public class AnalyticsService : IAnalyticsService public class AnalyticsService : IAnalyticsService
{ {
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
private readonly IHistoryService _historyService; private readonly IHistoryService _historyService;
public AnalyticsService(IHistoryService historyService, IConfigFileProvider configFileProvider) public AnalyticsService(IHistoryService historyService, IOptionsMonitor<ConfigFileOptions> configFileOptions)
{ {
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
_historyService = historyService; _historyService = historyService;
} }
public bool IsEnabled => (_configFileProvider.AnalyticsEnabled && RuntimeInfo.IsProduction) || RuntimeInfo.IsDevelopment; public bool IsEnabled => (_configFileOptions.CurrentValue.AnalyticsEnabled && RuntimeInfo.IsProduction) || RuntimeInfo.IsDevelopment;
public bool InstallIsActive public bool InstallIsActive
{ {

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Linq; using System.Linq;
using Microsoft.Extensions.Options;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
@@ -19,22 +20,22 @@ namespace NzbDrone.Core.Authentication
User FindUser(Guid identifier); User FindUser(Guid identifier);
} }
public class UserService : IUserService, IHandle<ApplicationStartedEvent> public class UserService : IUserService
{ {
private readonly IUserRepository _repo; private readonly IUserRepository _repo;
private readonly IAppFolderInfo _appFolderInfo; private readonly IAppFolderInfo _appFolderInfo;
private readonly IDiskProvider _diskProvider; private readonly IDiskProvider _diskProvider;
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
public UserService(IUserRepository repo, public UserService(IUserRepository repo,
IAppFolderInfo appFolderInfo, IAppFolderInfo appFolderInfo,
IDiskProvider diskProvider, IDiskProvider diskProvider,
IConfigFileProvider configFileProvider) IOptionsMonitor<ConfigFileOptions> configFileOptions)
{ {
_repo = repo; _repo = repo;
_appFolderInfo = appFolderInfo; _appFolderInfo = appFolderInfo;
_diskProvider = diskProvider; _diskProvider = diskProvider;
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
} }
public User Add(string username, string password) public User Add(string username, string password)
@@ -102,28 +103,5 @@ namespace NzbDrone.Core.Authentication
{ {
return _repo.FindUser(identifier); return _repo.FindUser(identifier);
} }
public void Handle(ApplicationStartedEvent message)
{
if (_repo.All().Any())
{
return;
}
var xDoc = _configFileProvider.LoadConfigFile();
var config = xDoc.Descendants("Config").Single();
var usernameElement = config.Descendants("Username").FirstOrDefault();
var passwordElement = config.Descendants("Password").FirstOrDefault();
if (usernameElement == null || passwordElement == null)
{
return;
}
var username = usernameElement.Value;
var password = passwordElement.Value;
Add(username, password);
}
} }
} }

View File

@@ -0,0 +1,71 @@
using System;
using Microsoft.Extensions.Configuration;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Core.Authentication;
using NzbDrone.Core.Update;
namespace NzbDrone.Core.Configuration
{
public class ConfigFileOptions
{
[Persist]
public string BindAddress { get; set; } = "*";
[Persist]
public int Port { get; set; } = 7878;
[Persist]
public int SslPort { get; set; } = 9898;
[Persist]
public bool EnableSsl { get; set; }
[Persist]
public bool LaunchBrowser { get; set; } = true;
public AuthenticationType AuthenticationMethod { get; set; }
public bool AnalyticsEnabled { get; set; } = true;
[Persist]
public string Branch { get; set; } = "master";
[Persist]
public string LogLevel { get; set; } = "info";
public string ConsoleLogLevel { get; set; } = string.Empty;
public bool LogSql { get; set; }
public int LogRotate { get; set; } = 50;
public bool FilterSentryEvents { get; set; } = true;
[Persist]
public string ApiKey { get; set; } = GenerateApiKey();
[Persist]
public string SslCertPath { get; set; }
[Persist]
public string SslCertPassword { get; set; }
[Persist]
public string UrlBase { get; set; } = string.Empty;
[Persist]
public string InstanceName { get; set; } = BuildInfo.AppName;
public bool UpdateAutomatically { get; set; }
public UpdateMechanism UpdateMechanism { get; set; } = UpdateMechanism.BuiltIn;
public string UpdateScriptPath { get; set; } = string.Empty;
public string SyslogServer { get; set; } = string.Empty;
public int SyslogPort { get; set; } = 514;
public string SyslogLevel { get; set; } = "info";
public string PostgresHost { get; set; }
public int PostgresPort { get; set; }
public string PostgresUser { get; set; }
public string PostgresPassword { get; set; }
public string PostgresMainDb { get; set; } = BuildInfo.AppName.ToLower() + "-main";
public string PostgresLogDb { get; set; } = BuildInfo.AppName.ToLower() + "-log";
private static string GenerateApiKey()
{
return Guid.NewGuid().ToString().Replace("-", "");
}
public static ConfigFileOptions GetOptions()
{
var config = new ConfigurationBuilder()
.AddEnvironmentVariables($"{BuildInfo.AppName}:")
.Build();
var options = new ConfigFileOptions();
config.Bind(options);
return options;
}
}
}

View File

@@ -1,401 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Linq;
using Microsoft.Extensions.Options;
using NzbDrone.Common.Cache;
using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Authentication;
using NzbDrone.Core.Configuration.Events;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Lifecycle;
using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Update;
namespace NzbDrone.Core.Configuration
{
public interface IConfigFileProvider : IHandleAsync<ApplicationStartedEvent>,
IExecute<ResetApiKeyCommand>
{
XDocument LoadConfigFile();
Dictionary<string, object> GetConfigDictionary();
void SaveConfigDictionary(Dictionary<string, object> configValues);
string BindAddress { get; }
int Port { get; }
int SslPort { get; }
bool EnableSsl { get; }
bool LaunchBrowser { get; }
AuthenticationType AuthenticationMethod { get; }
bool AnalyticsEnabled { get; }
string LogLevel { get; }
string ConsoleLogLevel { get; }
bool LogSql { get; }
int LogRotate { get; }
bool FilterSentryEvents { get; }
string Branch { get; }
string ApiKey { get; }
string SslCertPath { get; }
string SslCertPassword { get; }
string UrlBase { get; }
string UiFolder { get; }
string InstanceName { get; }
bool UpdateAutomatically { get; }
UpdateMechanism UpdateMechanism { get; }
string UpdateScriptPath { get; }
string SyslogServer { get; }
int SyslogPort { get; }
string SyslogLevel { get; }
string PostgresHost { get; }
int PostgresPort { get; }
string PostgresUser { get; }
string PostgresPassword { get; }
string PostgresMainDb { get; }
string PostgresLogDb { get; }
}
public class ConfigFileProvider : IConfigFileProvider
{
public const string CONFIG_ELEMENT_NAME = "Config";
private readonly IEventAggregator _eventAggregator;
private readonly IDiskProvider _diskProvider;
private readonly ICached<string> _cache;
private readonly PostgresOptions _postgresOptions;
private readonly string _configFile;
private static readonly Regex HiddenCharacterRegex = new Regex("[^a-z0-9]", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly object Mutex = new object();
public ConfigFileProvider(IAppFolderInfo appFolderInfo,
ICacheManager cacheManager,
IEventAggregator eventAggregator,
IDiskProvider diskProvider,
IOptions<PostgresOptions> postgresOptions)
{
_cache = cacheManager.GetCache<string>(GetType());
_eventAggregator = eventAggregator;
_diskProvider = diskProvider;
_configFile = appFolderInfo.GetConfigPath();
_postgresOptions = postgresOptions.Value;
}
public Dictionary<string, object> GetConfigDictionary()
{
var dict = new Dictionary<string, object>(StringComparer.InvariantCultureIgnoreCase);
var type = GetType();
var properties = type.GetProperties();
foreach (var propertyInfo in properties)
{
var value = propertyInfo.GetValue(this, null);
dict.Add(propertyInfo.Name, value);
}
return dict;
}
public void SaveConfigDictionary(Dictionary<string, object> configValues)
{
_cache.Clear();
var allWithDefaults = GetConfigDictionary();
foreach (var configValue in configValues)
{
if (configValue.Key.Equals("ApiKey", StringComparison.InvariantCultureIgnoreCase))
{
continue;
}
object currentValue;
allWithDefaults.TryGetValue(configValue.Key, out currentValue);
if (currentValue == null)
{
continue;
}
var equal = configValue.Value.ToString().Equals(currentValue.ToString());
if (!equal)
{
SetValue(configValue.Key.FirstCharToUpper(), configValue.Value.ToString());
}
}
_eventAggregator.PublishEvent(new ConfigFileSavedEvent());
}
public string BindAddress
{
get
{
const string defaultValue = "*";
string bindAddress = GetValue("BindAddress", defaultValue);
if (string.IsNullOrWhiteSpace(bindAddress))
{
return defaultValue;
}
return bindAddress;
}
}
public int Port => GetValueInt("Port", 7878);
public int SslPort => GetValueInt("SslPort", 9898);
public bool EnableSsl => GetValueBoolean("EnableSsl", false);
public bool LaunchBrowser => GetValueBoolean("LaunchBrowser", true);
public string ApiKey
{
get
{
var apiKey = GetValue("ApiKey", GenerateApiKey());
if (apiKey.IsNullOrWhiteSpace())
{
apiKey = GenerateApiKey();
SetValue("ApiKey", apiKey);
}
return apiKey;
}
}
public AuthenticationType AuthenticationMethod
{
get
{
var enabled = GetValueBoolean("AuthenticationEnabled", false, false);
if (enabled)
{
SetValue("AuthenticationMethod", AuthenticationType.Basic);
return AuthenticationType.Basic;
}
return GetValueEnum("AuthenticationMethod", AuthenticationType.None);
}
}
public bool AnalyticsEnabled => GetValueBoolean("AnalyticsEnabled", true, persist: false);
public string Branch => GetValue("Branch", "master").ToLowerInvariant();
public string LogLevel => GetValue("LogLevel", "info").ToLowerInvariant();
public string ConsoleLogLevel => GetValue("ConsoleLogLevel", string.Empty, persist: false);
public string PostgresHost => _postgresOptions?.Host ?? GetValue("PostgresHost", string.Empty, persist: false);
public string PostgresUser => _postgresOptions?.User ?? GetValue("PostgresUser", string.Empty, persist: false);
public string PostgresPassword => _postgresOptions?.Password ?? GetValue("PostgresPassword", string.Empty, persist: false);
public string PostgresMainDb => _postgresOptions?.MainDb ?? GetValue("PostgresMainDb", "radarr-main", persist: false);
public string PostgresLogDb => _postgresOptions?.LogDb ?? GetValue("PostgresLogDb", "radarr-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 string UrlBase
{
get
{
var urlBase = GetValue("UrlBase", "").Trim('/');
if (urlBase.IsNullOrWhiteSpace())
{
return urlBase;
}
return "/" + urlBase.Trim('/').ToLower();
}
}
public string UiFolder => BuildInfo.IsDebug ? Path.Combine("..", "UI") : "UI";
public string InstanceName => GetValue("InstanceName", BuildInfo.AppName);
public bool UpdateAutomatically => GetValueBoolean("UpdateAutomatically", false, false);
public UpdateMechanism UpdateMechanism => GetValueEnum("UpdateMechanism", UpdateMechanism.BuiltIn, false);
public string UpdateScriptPath => GetValue("UpdateScriptPath", "", false);
public string SyslogServer => GetValue("SyslogServer", "", persist: false);
public int SyslogPort => GetValueInt("SyslogPort", 514, persist: false);
public string SyslogLevel => GetValue("SyslogLevel", LogLevel, false).ToLowerInvariant();
public int GetValueInt(string key, int defaultValue, bool persist = true)
{
return Convert.ToInt32(GetValue(key, defaultValue, persist));
}
public bool GetValueBoolean(string key, bool defaultValue, bool persist = true)
{
return Convert.ToBoolean(GetValue(key, defaultValue, persist));
}
public T GetValueEnum<T>(string key, T defaultValue, bool persist = true)
{
return (T)Enum.Parse(typeof(T), GetValue(key, defaultValue), persist);
}
public string GetValue(string key, object defaultValue, bool persist = true)
{
return _cache.Get(key, () =>
{
var xDoc = LoadConfigFile();
var config = xDoc.Descendants(CONFIG_ELEMENT_NAME).Single();
var parentContainer = config;
var valueHolder = parentContainer.Descendants(key).ToList();
if (valueHolder.Count == 1)
{
return valueHolder.First().Value.Trim();
}
//Save the value
if (persist)
{
SetValue(key, defaultValue);
}
//return the default value
return defaultValue.ToString();
});
}
public void SetValue(string key, object value)
{
var valueString = value.ToString().Trim();
var xDoc = LoadConfigFile();
var config = xDoc.Descendants(CONFIG_ELEMENT_NAME).Single();
var parentContainer = config;
var keyHolder = parentContainer.Descendants(key);
if (keyHolder.Count() != 1)
{
parentContainer.Add(new XElement(key, valueString));
}
else
{
parentContainer.Descendants(key).Single().Value = valueString;
}
_cache.Set(key, valueString);
SaveConfigFile(xDoc);
}
public void SetValue(string key, Enum value)
{
SetValue(key, value.ToString().ToLower());
}
private void EnsureDefaultConfigFile()
{
if (!File.Exists(_configFile))
{
SaveConfigDictionary(GetConfigDictionary());
}
}
private void DeleteOldValues()
{
var xDoc = LoadConfigFile();
var config = xDoc.Descendants(CONFIG_ELEMENT_NAME).Single();
var type = GetType();
var properties = type.GetProperties();
foreach (var configValue in config.Descendants().ToList())
{
var name = configValue.Name.LocalName;
if (!properties.Any(p => p.Name == name))
{
config.Descendants(name).Remove();
}
}
SaveConfigFile(xDoc);
}
public XDocument LoadConfigFile()
{
try
{
lock (Mutex)
{
if (_diskProvider.FileExists(_configFile))
{
var contents = _diskProvider.ReadAllText(_configFile);
if (contents.IsNullOrWhiteSpace())
{
throw new InvalidConfigFileException($"{_configFile} is empty. Please delete the config file and Radarr will recreate it.");
}
if (contents.All(char.IsControl))
{
throw new InvalidConfigFileException($"{_configFile} is corrupt. Please delete the config file and Radarr will recreate it.");
}
return XDocument.Parse(_diskProvider.ReadAllText(_configFile));
}
var xDoc = new XDocument(new XDeclaration("1.0", "utf-8", "yes"));
xDoc.Add(new XElement(CONFIG_ELEMENT_NAME));
return xDoc;
}
}
catch (XmlException ex)
{
throw new InvalidConfigFileException($"{_configFile} is corrupt is invalid. Please delete the config file and Radarr will recreate it.", ex);
}
}
private void SaveConfigFile(XDocument xDoc)
{
lock (Mutex)
{
_diskProvider.WriteAllText(_configFile, xDoc.ToString());
}
}
private string GenerateApiKey()
{
return Guid.NewGuid().ToString().Replace("-", "");
}
public void HandleAsync(ApplicationStartedEvent message)
{
EnsureDefaultConfigFile();
DeleteOldValues();
}
public void Execute(ResetApiKeyCommand message)
{
SetValue("ApiKey", GenerateApiKey());
}
}
}

View File

@@ -0,0 +1,219 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using NLog;
using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration.Events;
using NzbDrone.Core.Lifecycle;
using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Configuration
{
public interface IConfigFileWriter : IHandleAsync<ApplicationStartedEvent>,
IExecute<ResetApiKeyCommand>
{
public void EnsureDefaultConfigFile();
void SaveConfigDictionary(Dictionary<string, object> configValues);
}
public class ConfigFileWriter : IConfigFileWriter
{
public static string CONFIG_ELEMENT_NAME = BuildInfo.AppName;
private readonly IEventAggregator _eventAggregator;
private readonly IDiskProvider _diskProvider;
private readonly IConfigurationRoot _configuration;
private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
private readonly Logger _logger;
private readonly string _configFile;
private static readonly object Mutex = new object();
public ConfigFileWriter(IAppFolderInfo appFolderInfo,
IEventAggregator eventAggregator,
IDiskProvider diskProvider,
IConfiguration configuration,
IOptionsMonitor<ConfigFileOptions> configFileOptions,
Logger logger)
{
_eventAggregator = eventAggregator;
_diskProvider = diskProvider;
_configuration = configuration as IConfigurationRoot;
_configFileOptions = configFileOptions;
_logger = logger;
_configFile = appFolderInfo.GetConfigPath();
_configFileOptions.OnChange(OnChange);
}
private Dictionary<string, object> GetConfigDictionary()
{
var dict = new Dictionary<string, object>(StringComparer.InvariantCultureIgnoreCase);
var properties = typeof(ConfigFileOptions).GetProperties();
foreach (var propertyInfo in properties)
{
var value = propertyInfo.GetValue(_configFileOptions.CurrentValue, null);
dict.Add(propertyInfo.Name, value);
}
return dict;
}
public void SaveConfigDictionary(Dictionary<string, object> configValues)
{
var allWithDefaults = GetConfigDictionary();
var persistKeys = typeof(ConfigFileOptions).GetProperties()
.Where(x => Attribute.IsDefined(x, typeof(PersistAttribute)))
.Select(x => x.Name)
.ToList();
foreach (var configValue in configValues)
{
if (configValue.Key.Equals("ApiKey", StringComparison.InvariantCultureIgnoreCase))
{
continue;
}
allWithDefaults.TryGetValue(configValue.Key, out var currentValue);
if (currentValue == null)
{
continue;
}
var equal = configValue.Value.ToString().Equals(currentValue.ToString());
var persist = persistKeys.Contains(configValue.Key);
if (persist || !equal)
{
SetValue(configValue.Key.FirstCharToUpper(), configValue.Value.ToString());
}
}
_eventAggregator.PublishEvent(new ConfigFileSavedEvent());
}
public void SetValue(string key, object value)
{
var valueString = value.ToString().Trim();
var xDoc = LoadConfigFile();
var config = xDoc.Descendants(CONFIG_ELEMENT_NAME).Single();
var keyHolder = config.Descendants(key);
if (keyHolder.Count() != 1)
{
config.Add(new XElement(key, valueString));
}
else
{
config.Descendants(key).Single().Value = valueString;
}
SaveConfigFile(xDoc);
}
public void EnsureDefaultConfigFile()
{
if (!File.Exists(_configFile))
{
SaveConfigDictionary(GetConfigDictionary());
SetValue(nameof(ConfigFileOptions.ApiKey), _configFileOptions.CurrentValue.ApiKey);
}
}
private void DeleteOldValues()
{
var xDoc = LoadConfigFile();
var config = xDoc.Descendants(CONFIG_ELEMENT_NAME).Single();
var properties = typeof(ConfigFileOptions).GetProperties();
foreach (var configValue in config.Descendants().ToList())
{
var name = configValue.Name.LocalName;
if (!properties.Any(p => p.Name == name))
{
config.Descendants(name).Remove();
}
}
SaveConfigFile(xDoc);
}
public XDocument LoadConfigFile()
{
try
{
lock (Mutex)
{
if (_diskProvider.FileExists(_configFile))
{
var contents = _diskProvider.ReadAllText(_configFile);
if (contents.IsNullOrWhiteSpace())
{
throw new InvalidConfigFileException($"{_configFile} is empty. Please delete the config file and Radarr will recreate it.");
}
if (contents.All(char.IsControl))
{
throw new InvalidConfigFileException($"{_configFile} is corrupt. Please delete the config file and Radarr will recreate it.");
}
return XDocument.Parse(_diskProvider.ReadAllText(_configFile));
}
var xDoc = new XDocument(new XDeclaration("1.0", "utf-8", "yes"));
xDoc.Add(new XElement(CONFIG_ELEMENT_NAME));
return xDoc;
}
}
catch (XmlException ex)
{
throw new InvalidConfigFileException($"{_configFile} is corrupt is invalid. Please delete the config file and Radarr will recreate it.", ex);
}
}
private void SaveConfigFile(XDocument xDoc)
{
lock (Mutex)
{
_diskProvider.WriteAllText(_configFile, xDoc.ToString());
_configuration.Reload();
}
}
public void HandleAsync(ApplicationStartedEvent message)
{
DeleteOldValues();
}
public void Execute(ResetApiKeyCommand message)
{
SetValue(nameof(ConfigFileOptions.ApiKey), new ConfigFileOptions().ApiKey);
}
private void OnChange(ConfigFileOptions options)
{
_logger.Info("Config file updated");
_eventAggregator.PublishEvent(new ConfigFileSavedEvent());
}
}
}

View File

@@ -0,0 +1,9 @@
using System;
namespace NzbDrone.Core.Configuration
{
[AttributeUsage(AttributeTargets.Property)]
public class PersistAttribute : Attribute
{
}
}

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Data.SQLite; using System.Data.SQLite;
using Microsoft.Extensions.Options;
using Npgsql; using Npgsql;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
@@ -16,16 +17,25 @@ namespace NzbDrone.Core.Datastore
public class ConnectionStringFactory : IConnectionStringFactory public class ConnectionStringFactory : IConnectionStringFactory
{ {
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
public ConnectionStringFactory(IAppFolderInfo appFolderInfo, IConfigFileProvider configFileProvider) // Catch legacy config, to be removed soon
private readonly PostgresOptions _postgresOptions;
public ConnectionStringFactory(IAppFolderInfo appFolderInfo,
IOptionsMonitor<ConfigFileOptions> configFileOptions)
{ {
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
_postgresOptions = PostgresOptions.GetOptions();
MainDbConnectionString = _configFileProvider.PostgresHost.IsNotNullOrWhiteSpace() ? GetPostgresConnectionString(_configFileProvider.PostgresMainDb) : var isPostgres = _configFileOptions.CurrentValue.PostgresHost.IsNotNullOrWhiteSpace() || _postgresOptions.Host.IsNotNullOrWhiteSpace();
var mainDb = _configFileOptions.CurrentValue.PostgresMainDb ?? _postgresOptions.MainDb;
var logDb = _configFileOptions.CurrentValue.PostgresLogDb ?? _postgresOptions.LogDb;
MainDbConnectionString = isPostgres ? GetPostgresConnectionString(mainDb) :
GetConnectionString(appFolderInfo.GetDatabase()); GetConnectionString(appFolderInfo.GetDatabase());
LogDbConnectionString = _configFileProvider.PostgresHost.IsNotNullOrWhiteSpace() ? GetPostgresConnectionString(_configFileProvider.PostgresLogDb) : LogDbConnectionString = isPostgres ? GetPostgresConnectionString(logDb) :
GetConnectionString(appFolderInfo.GetLogDatabase()); GetConnectionString(appFolderInfo.GetLogDatabase());
} }
@@ -63,10 +73,10 @@ namespace NzbDrone.Core.Datastore
var connectionBuilder = new NpgsqlConnectionStringBuilder(); var connectionBuilder = new NpgsqlConnectionStringBuilder();
connectionBuilder.Database = dbName; connectionBuilder.Database = dbName;
connectionBuilder.Host = _configFileProvider.PostgresHost; connectionBuilder.Host = _configFileOptions.CurrentValue.PostgresHost ?? _postgresOptions.Host;
connectionBuilder.Username = _configFileProvider.PostgresUser; connectionBuilder.Username = _configFileOptions.CurrentValue.PostgresUser ?? _postgresOptions.User;
connectionBuilder.Password = _configFileProvider.PostgresPassword; connectionBuilder.Password = _configFileOptions.CurrentValue.PostgresPassword ?? _postgresOptions.Password;
connectionBuilder.Port = _configFileProvider.PostgresPort; connectionBuilder.Port = _configFileOptions.CurrentValue.PostgresPort > 0 ? _configFileOptions.CurrentValue.PostgresPort : _postgresOptions.Port;
connectionBuilder.Enlist = false; connectionBuilder.Enlist = false;
return connectionBuilder.ConnectionString; return connectionBuilder.ConnectionString;

View File

@@ -1,4 +1,5 @@
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Core.Datastore namespace NzbDrone.Core.Datastore
{ {
@@ -18,7 +19,7 @@ namespace NzbDrone.Core.Datastore
.Build(); .Build();
var postgresOptions = new PostgresOptions(); var postgresOptions = new PostgresOptions();
config.GetSection("Radarr:Postgres").Bind(postgresOptions); config.GetSection($"{BuildInfo.AppName}:Postgres").Bind(postgresOptions);
return postgresOptions; return postgresOptions;
} }

View File

@@ -0,0 +1,47 @@
using System;
using System.Collections;
using System.Linq;
using NLog;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Localization;
namespace NzbDrone.Core.HealthCheck.Checks
{
public class LegacyPostgresCheck : HealthCheckBase
{
private readonly Logger _logger;
public LegacyPostgresCheck(ILocalizationService localizationService, Logger logger)
: base(localizationService)
{
_logger = logger;
}
public override HealthCheck Check()
{
var legacyVars = Environment
.GetEnvironmentVariables()
.Cast<DictionaryEntry>()
.Select(x => x.Key.ToString())
.Where(k => k.StartsWith(BuildInfo.AppName + "__Postgres__") || k.StartsWith(BuildInfo.AppName + ":Postgres:"))
.ToList();
if (legacyVars.Count == 0)
{
return new HealthCheck(GetType());
}
var legacyString = legacyVars.OrderBy(x => x).ConcatToString();
var newString = legacyString
.Replace(BuildInfo.AppName + "__Postgres__", BuildInfo.AppName + "__Postgres")
.Replace(BuildInfo.AppName + ":Postgres:", BuildInfo.AppName + ":Postgres");
return new HealthCheck(GetType(),
HealthCheckResult.Error,
string.Format(_localizationService.GetLocalizedString("PostgresLegacyEnvironmentVariables"), legacyString, newString));
}
public override bool CheckOnSchedule => false;
}
}

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Linq; using System.Linq;
using Microsoft.Extensions.Options;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Configuration.Events; using NzbDrone.Core.Configuration.Events;
using NzbDrone.Core.Localization; using NzbDrone.Core.Localization;
@@ -9,9 +10,9 @@ namespace NzbDrone.Core.HealthCheck.Checks
[CheckOn(typeof(ConfigSavedEvent))] [CheckOn(typeof(ConfigSavedEvent))]
public class ReleaseBranchCheck : HealthCheckBase public class ReleaseBranchCheck : HealthCheckBase
{ {
private readonly IConfigFileProvider _configFileService; private readonly IOptionsMonitor<ConfigFileOptions> _configFileService;
public ReleaseBranchCheck(IConfigFileProvider configFileService, ILocalizationService localizationService) public ReleaseBranchCheck(IOptionsMonitor<ConfigFileOptions> configFileService, ILocalizationService localizationService)
: base(localizationService) : base(localizationService)
{ {
_configFileService = configFileService; _configFileService = configFileService;
@@ -19,11 +20,11 @@ namespace NzbDrone.Core.HealthCheck.Checks
public override HealthCheck Check() public override HealthCheck Check()
{ {
var currentBranch = _configFileService.Branch.ToLower(); var currentBranch = _configFileService.CurrentValue.Branch.ToLower();
if (!Enum.GetNames(typeof(ReleaseBranches)).Any(x => x.ToLower() == currentBranch)) if (!Enum.GetNames(typeof(ReleaseBranches)).Any(x => x.ToLower() == currentBranch))
{ {
return new HealthCheck(GetType(), HealthCheckResult.Warning, string.Format(_localizationService.GetLocalizedString("ReleaseBranchCheckOfficialBranchMessage"), _configFileService.Branch), "#branch-is-not-a-valid-release-branch"); return new HealthCheck(GetType(), HealthCheckResult.Warning, string.Format(_localizationService.GetLocalizedString("ReleaseBranchCheckOfficialBranchMessage"), _configFileService.CurrentValue.Branch), "#branch-is-not-a-valid-release-branch");
} }
return new HealthCheck(GetType()); return new HealthCheck(GetType());

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.IO; using System.IO;
using Microsoft.Extensions.Options;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
@@ -16,13 +17,13 @@ namespace NzbDrone.Core.HealthCheck.Checks
private readonly IDiskProvider _diskProvider; private readonly IDiskProvider _diskProvider;
private readonly IAppFolderInfo _appFolderInfo; private readonly IAppFolderInfo _appFolderInfo;
private readonly ICheckUpdateService _checkUpdateService; private readonly ICheckUpdateService _checkUpdateService;
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
private readonly IOsInfo _osInfo; private readonly IOsInfo _osInfo;
public UpdateCheck(IDiskProvider diskProvider, public UpdateCheck(IDiskProvider diskProvider,
IAppFolderInfo appFolderInfo, IAppFolderInfo appFolderInfo,
ICheckUpdateService checkUpdateService, ICheckUpdateService checkUpdateService,
IConfigFileProvider configFileProvider, IOptionsMonitor<ConfigFileOptions> configFileOptions,
IOsInfo osInfo, IOsInfo osInfo,
ILocalizationService localizationService) ILocalizationService localizationService)
: base(localizationService) : base(localizationService)
@@ -30,7 +31,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
_diskProvider = diskProvider; _diskProvider = diskProvider;
_appFolderInfo = appFolderInfo; _appFolderInfo = appFolderInfo;
_checkUpdateService = checkUpdateService; _checkUpdateService = checkUpdateService;
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
_osInfo = osInfo; _osInfo = osInfo;
} }
@@ -39,8 +40,8 @@ namespace NzbDrone.Core.HealthCheck.Checks
var startupFolder = _appFolderInfo.StartUpFolder; var startupFolder = _appFolderInfo.StartUpFolder;
var uiFolder = Path.Combine(startupFolder, "UI"); var uiFolder = Path.Combine(startupFolder, "UI");
if ((OsInfo.IsWindows || _configFileProvider.UpdateAutomatically) && if ((OsInfo.IsWindows || _configFileOptions.CurrentValue.UpdateAutomatically) &&
_configFileProvider.UpdateMechanism == UpdateMechanism.BuiltIn && _configFileOptions.CurrentValue.UpdateMechanism == UpdateMechanism.BuiltIn &&
!_osInfo.IsDocker) !_osInfo.IsDocker)
{ {
if (OsInfo.IsOsx && startupFolder.GetAncestorFolders().Contains("AppTranslocation")) if (OsInfo.IsOsx && startupFolder.GetAncestorFolders().Contains("AppTranslocation"))

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Microsoft.Extensions.Options;
using NLog; using NLog;
using NzbDrone.Common.Cloud; using NzbDrone.Common.Cloud;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
@@ -19,14 +20,14 @@ namespace NzbDrone.Core.HealthCheck
public class ServerSideNotificationService : IServerSideNotificationService public class ServerSideNotificationService : IServerSideNotificationService
{ {
private readonly IHttpClient _client; private readonly IHttpClient _client;
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
private readonly IHttpRequestBuilderFactory _cloudRequestBuilder; private readonly IHttpRequestBuilderFactory _cloudRequestBuilder;
private readonly Logger _logger; private readonly Logger _logger;
public ServerSideNotificationService(IHttpClient client, IConfigFileProvider configFileProvider, IRadarrCloudRequestBuilder cloudRequestBuilder, Logger logger) public ServerSideNotificationService(IHttpClient client, IOptionsMonitor<ConfigFileOptions> configFileOptions, IRadarrCloudRequestBuilder cloudRequestBuilder, Logger logger)
{ {
_client = client; _client = client;
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
_cloudRequestBuilder = cloudRequestBuilder.Services; _cloudRequestBuilder = cloudRequestBuilder.Services;
_logger = logger; _logger = logger;
} }
@@ -39,7 +40,7 @@ namespace NzbDrone.Core.HealthCheck
.AddQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant()) .AddQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant())
.AddQueryParam("arch", RuntimeInformation.OSArchitecture) .AddQueryParam("arch", RuntimeInformation.OSArchitecture)
.AddQueryParam("runtime", PlatformInfo.Platform.ToString().ToLowerInvariant()) .AddQueryParam("runtime", PlatformInfo.Platform.ToString().ToLowerInvariant())
.AddQueryParam("branch", _configFileProvider.Branch) .AddQueryParam("branch", _configFileOptions.CurrentValue.Branch)
.Build(); .Build();
try try
{ {

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.Extensions.Options;
using NLog; using NLog;
using NLog.Config; using NLog.Config;
using NLog.Targets.Syslog; using NLog.Targets.Syslog;
@@ -17,21 +18,21 @@ namespace NzbDrone.Core.Instrumentation
{ {
public class ReconfigureLogging : IHandleAsync<ConfigFileSavedEvent> public class ReconfigureLogging : IHandleAsync<ConfigFileSavedEvent>
{ {
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
public ReconfigureLogging(IConfigFileProvider configFileProvider) public ReconfigureLogging(IOptionsMonitor<ConfigFileOptions> configFileOptions)
{ {
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
} }
public void Reconfigure() public void Reconfigure()
{ {
var minimumLogLevel = LogLevel.FromString(_configFileProvider.LogLevel); var minimumLogLevel = LogLevel.FromString(_configFileOptions.CurrentValue.LogLevel);
LogLevel minimumConsoleLogLevel; LogLevel minimumConsoleLogLevel;
if (_configFileProvider.ConsoleLogLevel.IsNotNullOrWhiteSpace()) if (_configFileOptions.CurrentValue.ConsoleLogLevel.IsNotNullOrWhiteSpace())
{ {
minimumConsoleLogLevel = LogLevel.FromString(_configFileProvider.ConsoleLogLevel); minimumConsoleLogLevel = LogLevel.FromString(_configFileOptions.CurrentValue.ConsoleLogLevel);
} }
else if (minimumLogLevel > LogLevel.Info) else if (minimumLogLevel > LogLevel.Info)
{ {
@@ -42,10 +43,10 @@ namespace NzbDrone.Core.Instrumentation
minimumConsoleLogLevel = LogLevel.Info; minimumConsoleLogLevel = LogLevel.Info;
} }
if (_configFileProvider.SyslogServer.IsNotNullOrWhiteSpace()) if (_configFileOptions.CurrentValue.SyslogServer.IsNotNullOrWhiteSpace())
{ {
var syslogLevel = LogLevel.FromString(_configFileProvider.SyslogLevel); var syslogLevel = LogLevel.FromString(_configFileOptions.CurrentValue.SyslogLevel);
SetSyslogParameters(_configFileProvider.SyslogServer, _configFileProvider.SyslogPort, syslogLevel); SetSyslogParameters(_configFileOptions.CurrentValue.SyslogServer, _configFileOptions.CurrentValue.SyslogPort, syslogLevel);
} }
var rules = LogManager.Configuration.LoggingRules; var rules = LogManager.Configuration.LoggingRules;
@@ -60,7 +61,7 @@ namespace NzbDrone.Core.Instrumentation
SetLogRotation(); SetLogRotation();
//Log Sql //Log Sql
SqlBuilderExtensions.LogSql = _configFileProvider.LogSql; SqlBuilderExtensions.LogSql = _configFileOptions.CurrentValue.LogSql;
//Sentry //Sentry
ReconfigureSentry(); ReconfigureSentry();
@@ -95,7 +96,7 @@ namespace NzbDrone.Core.Instrumentation
{ {
foreach (var target in LogManager.Configuration.AllTargets.OfType<NzbDroneFileTarget>()) foreach (var target in LogManager.Configuration.AllTargets.OfType<NzbDroneFileTarget>())
{ {
target.MaxArchiveFiles = _configFileProvider.LogRotate; target.MaxArchiveFiles = _configFileOptions.CurrentValue.LogRotate;
} }
} }
@@ -104,8 +105,8 @@ namespace NzbDrone.Core.Instrumentation
var sentryTarget = LogManager.Configuration.AllTargets.OfType<SentryTarget>().FirstOrDefault(); var sentryTarget = LogManager.Configuration.AllTargets.OfType<SentryTarget>().FirstOrDefault();
if (sentryTarget != null) if (sentryTarget != null)
{ {
sentryTarget.SentryEnabled = (RuntimeInfo.IsProduction && _configFileProvider.AnalyticsEnabled) || RuntimeInfo.IsDevelopment; sentryTarget.SentryEnabled = (RuntimeInfo.IsProduction && _configFileOptions.CurrentValue.AnalyticsEnabled) || RuntimeInfo.IsDevelopment;
sentryTarget.FilterEvents = _configFileProvider.FilterSentryEvents; sentryTarget.FilterEvents = _configFileOptions.CurrentValue.FilterSentryEvents;
} }
} }
@@ -119,7 +120,7 @@ namespace NzbDrone.Core.Instrumentation
syslogTarget.MessageSend.Udp.Server = syslogServer; syslogTarget.MessageSend.Udp.Server = syslogServer;
syslogTarget.MessageSend.Udp.ReconnectInterval = 500; syslogTarget.MessageSend.Udp.ReconnectInterval = 500;
syslogTarget.MessageCreation.Rfc = RfcNumber.Rfc5424; syslogTarget.MessageCreation.Rfc = RfcNumber.Rfc5424;
syslogTarget.MessageCreation.Rfc5424.AppName = _configFileProvider.InstanceName; syslogTarget.MessageCreation.Rfc5424.AppName = _configFileOptions.CurrentValue.InstanceName;
var loggingRule = new LoggingRule("*", minimumLogLevel, syslogTarget); var loggingRule = new LoggingRule("*", minimumLogLevel, syslogTarget);

View File

@@ -1,4 +1,5 @@
using System.Linq; using System.Linq;
using Microsoft.Extensions.Options;
using NLog; using NLog;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Instrumentation.Sentry; using NzbDrone.Common.Instrumentation.Sentry;
@@ -11,15 +12,15 @@ namespace NzbDrone.Core.Instrumentation
{ {
public class ReconfigureSentry : IHandleAsync<ApplicationStartedEvent> public class ReconfigureSentry : IHandleAsync<ApplicationStartedEvent>
{ {
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
private readonly IPlatformInfo _platformInfo; private readonly IPlatformInfo _platformInfo;
private readonly IMainDatabase _database; private readonly IMainDatabase _database;
public ReconfigureSentry(IConfigFileProvider configFileProvider, public ReconfigureSentry(IOptionsMonitor<ConfigFileOptions> configFileOptions,
IPlatformInfo platformInfo, IPlatformInfo platformInfo,
IMainDatabase database) IMainDatabase database)
{ {
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
_platformInfo = platformInfo; _platformInfo = platformInfo;
_database = database; _database = database;
} }
@@ -30,7 +31,7 @@ namespace NzbDrone.Core.Instrumentation
var sentryTarget = LogManager.Configuration.AllTargets.OfType<SentryTarget>().FirstOrDefault(); var sentryTarget = LogManager.Configuration.AllTargets.OfType<SentryTarget>().FirstOrDefault();
if (sentryTarget != null) if (sentryTarget != null)
{ {
sentryTarget.UpdateScope(_database.Version, _database.Migration, _configFileProvider.Branch, _platformInfo); sentryTarget.UpdateScope(_database.Version, _database.Migration, _configFileOptions.CurrentValue.Branch, _platformInfo);
} }
} }

View File

@@ -696,6 +696,7 @@
"PosterOptions": "Poster Options", "PosterOptions": "Poster Options",
"Posters": "Posters", "Posters": "Posters",
"PosterSize": "Poster Size", "PosterSize": "Poster Size",
"PostgresLegacyEnvironmentVariables": "You have defined the following legacy PostgreSQL environment variables: {0}. Please update them to: {1}",
"PreferAndUpgrade": "Prefer and Upgrade", "PreferAndUpgrade": "Prefer and Upgrade",
"PreferIndexerFlags": "Prefer Indexer Flags", "PreferIndexerFlags": "Prefer Indexer Flags",
"PreferIndexerFlagsHelpText": "Prioritize releases with special flags", "PreferIndexerFlagsHelpText": "Prioritize releases with special flags",

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using Microsoft.Extensions.Options;
using NzbDrone.Common.Cache; using NzbDrone.Common.Cache;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
@@ -18,13 +19,13 @@ namespace NzbDrone.Core.MediaCover
public class MediaCoverProxy : IMediaCoverProxy public class MediaCoverProxy : IMediaCoverProxy
{ {
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
private readonly ICached<string> _cache; private readonly ICached<string> _cache;
public MediaCoverProxy(IHttpClient httpClient, IConfigFileProvider configFileProvider, ICacheManager cacheManager) public MediaCoverProxy(IHttpClient httpClient, IOptionsMonitor<ConfigFileOptions> configFileOptions, ICacheManager cacheManager)
{ {
_httpClient = httpClient; _httpClient = httpClient;
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
_cache = cacheManager.GetCache<string>(GetType()); _cache = cacheManager.GetCache<string>(GetType());
} }
@@ -37,7 +38,7 @@ namespace NzbDrone.Core.MediaCover
_cache.ClearExpired(); _cache.ClearExpired();
var fileName = Path.GetFileName(url); var fileName = Path.GetFileName(url);
return _configFileProvider.UrlBase + @"/MediaCoverProxy/" + hash + "/" + fileName; return _configFileOptions.CurrentValue.UrlBase + @"/MediaCoverProxy/" + hash + "/" + fileName;
} }
public string GetUrl(string hash) public string GetUrl(string hash)

View File

@@ -4,6 +4,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Threading; using System.Threading;
using Microsoft.Extensions.Options;
using NLog; using NLog;
using NzbDrone.Common; using NzbDrone.Common;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
@@ -35,7 +36,7 @@ namespace NzbDrone.Core.MediaCover
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
private readonly IDiskProvider _diskProvider; private readonly IDiskProvider _diskProvider;
private readonly ICoverExistsSpecification _coverExistsSpecification; private readonly ICoverExistsSpecification _coverExistsSpecification;
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
private readonly IEventAggregator _eventAggregator; private readonly IEventAggregator _eventAggregator;
private readonly Logger _logger; private readonly Logger _logger;
@@ -51,7 +52,7 @@ namespace NzbDrone.Core.MediaCover
IDiskProvider diskProvider, IDiskProvider diskProvider,
IAppFolderInfo appFolderInfo, IAppFolderInfo appFolderInfo,
ICoverExistsSpecification coverExistsSpecification, ICoverExistsSpecification coverExistsSpecification,
IConfigFileProvider configFileProvider, IOptionsMonitor<ConfigFileOptions> configFileOptions,
IEventAggregator eventAggregator, IEventAggregator eventAggregator,
Logger logger) Logger logger)
{ {
@@ -60,7 +61,7 @@ namespace NzbDrone.Core.MediaCover
_httpClient = httpClient; _httpClient = httpClient;
_diskProvider = diskProvider; _diskProvider = diskProvider;
_coverExistsSpecification = coverExistsSpecification; _coverExistsSpecification = coverExistsSpecification;
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
_eventAggregator = eventAggregator; _eventAggregator = eventAggregator;
_logger = logger; _logger = logger;
@@ -104,7 +105,7 @@ namespace NzbDrone.Core.MediaCover
var filePath = GetCoverPath(movieId, mediaCover.CoverType); var filePath = GetCoverPath(movieId, mediaCover.CoverType);
mediaCover.RemoteUrl = mediaCover.Url; mediaCover.RemoteUrl = mediaCover.Url;
mediaCover.Url = _configFileProvider.UrlBase + @"/MediaCover/" + movieId + "/" + mediaCover.CoverType.ToString().ToLower() + ".jpg"; mediaCover.Url = _configFileOptions.CurrentValue.UrlBase + @"/MediaCover/" + movieId + "/" + mediaCover.CoverType.ToString().ToLower() + ".jpg";
FileInfo file; FileInfo file;
var fileExists = false; var fileExists = false;

View File

@@ -13,7 +13,8 @@
<PackageReference Include="System.Memory" Version="4.5.4" /> <PackageReference Include="System.Memory" Version="4.5.4" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.1" /> <PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0-preview.5.22301.12" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="7.0.0-preview.5.22301.12" />
<PackageReference Include="FluentMigrator.Runner" Version="3.3.2" /> <PackageReference Include="FluentMigrator.Runner" Version="3.3.2" />
<PackageReference Include="FluentMigrator.Runner.SQLite" Version="3.3.2" /> <PackageReference Include="FluentMigrator.Runner.SQLite" Version="3.3.2" />
<PackageReference Include="FluentValidation" Version="8.6.2" /> <PackageReference Include="FluentValidation" Version="8.6.2" />

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.Extensions.Options;
using NLog; using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
@@ -16,19 +17,21 @@ namespace NzbDrone.Core.Update
public class UpdaterConfigProvider : IUpdaterConfigProvider, IHandle<ApplicationStartedEvent> public class UpdaterConfigProvider : IUpdaterConfigProvider, IHandle<ApplicationStartedEvent>
{ {
private readonly Logger _logger; private readonly Logger _logger;
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
private readonly IConfigFileWriter _configFileWriter;
private readonly IDeploymentInfoProvider _deploymentInfoProvider; private readonly IDeploymentInfoProvider _deploymentInfoProvider;
public UpdaterConfigProvider(IDeploymentInfoProvider deploymentInfoProvider, IConfigFileProvider configFileProvider, Logger logger) public UpdaterConfigProvider(IDeploymentInfoProvider deploymentInfoProvider, IOptionsMonitor<ConfigFileOptions> configFileOptions, IConfigFileWriter configFileWriter, Logger logger)
{ {
_deploymentInfoProvider = deploymentInfoProvider; _deploymentInfoProvider = deploymentInfoProvider;
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
_configFileWriter = configFileWriter;
_logger = logger; _logger = logger;
} }
public void Handle(ApplicationStartedEvent message) public void Handle(ApplicationStartedEvent message)
{ {
var updateMechanism = _configFileProvider.UpdateMechanism; var updateMechanism = _configFileOptions.CurrentValue.UpdateMechanism;
var packageUpdateMechanism = _deploymentInfoProvider.PackageUpdateMechanism; var packageUpdateMechanism = _deploymentInfoProvider.PackageUpdateMechanism;
var externalMechanisms = Enum.GetValues(typeof(UpdateMechanism)) var externalMechanisms = Enum.GetValues(typeof(UpdateMechanism))
@@ -49,7 +52,7 @@ namespace NzbDrone.Core.Update
if (_deploymentInfoProvider.IsExternalUpdateMechanism) if (_deploymentInfoProvider.IsExternalUpdateMechanism)
{ {
var currentBranch = _configFileProvider.Branch; var currentBranch = _configFileOptions.CurrentValue.Branch;
var packageBranch = _deploymentInfoProvider.PackageBranch; var packageBranch = _deploymentInfoProvider.PackageBranch;
if (packageBranch.IsNotNullOrWhiteSpace() && packageBranch != currentBranch) if (packageBranch.IsNotNullOrWhiteSpace() && packageBranch != currentBranch)
{ {
@@ -63,18 +66,18 @@ namespace NzbDrone.Core.Update
{ {
var config = new Dictionary<string, object> var config = new Dictionary<string, object>
{ {
[nameof(_configFileProvider.UpdateMechanism)] = updateMechanism [nameof(_configFileOptions.CurrentValue.UpdateMechanism)] = updateMechanism
}; };
_configFileProvider.SaveConfigDictionary(config); _configFileWriter.SaveConfigDictionary(config);
} }
private void ChangeBranch(string branch) private void ChangeBranch(string branch)
{ {
var config = new Dictionary<string, object> var config = new Dictionary<string, object>
{ {
[nameof(_configFileProvider.Branch)] = branch [nameof(_configFileOptions.CurrentValue.Branch)] = branch
}; };
_configFileProvider.SaveConfigDictionary(config); _configFileWriter.SaveConfigDictionary(config);
} }
} }
} }

View File

@@ -1,8 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Drawing;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using Microsoft.Extensions.Options;
using NLog; using NLog;
using NzbDrone.Common; using NzbDrone.Common;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
@@ -34,7 +36,8 @@ namespace NzbDrone.Core.Update
private readonly IVerifyUpdates _updateVerifier; private readonly IVerifyUpdates _updateVerifier;
private readonly IStartupContext _startupContext; private readonly IStartupContext _startupContext;
private readonly IDeploymentInfoProvider _deploymentInfoProvider; private readonly IDeploymentInfoProvider _deploymentInfoProvider;
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
private readonly IConfigFileWriter _configFileWriter;
private readonly IRuntimeInfo _runtimeInfo; private readonly IRuntimeInfo _runtimeInfo;
private readonly IBackupService _backupService; private readonly IBackupService _backupService;
private readonly IOsInfo _osInfo; private readonly IOsInfo _osInfo;
@@ -50,15 +53,16 @@ namespace NzbDrone.Core.Update
IVerifyUpdates updateVerifier, IVerifyUpdates updateVerifier,
IStartupContext startupContext, IStartupContext startupContext,
IDeploymentInfoProvider deploymentInfoProvider, IDeploymentInfoProvider deploymentInfoProvider,
IConfigFileProvider configFileProvider, IOptionsMonitor<ConfigFileOptions> configFileOptions,
IConfigFileWriter configFileWriter,
IRuntimeInfo runtimeInfo, IRuntimeInfo runtimeInfo,
IBackupService backupService, IBackupService backupService,
IOsInfo osInfo, IOsInfo osInfo,
Logger logger) Logger logger)
{ {
if (configFileProvider == null) if (configFileOptions == null)
{ {
throw new ArgumentNullException(nameof(configFileProvider)); throw new ArgumentNullException(nameof(configFileOptions));
} }
_checkUpdateService = checkUpdateService; _checkUpdateService = checkUpdateService;
@@ -72,7 +76,8 @@ namespace NzbDrone.Core.Update
_updateVerifier = updateVerifier; _updateVerifier = updateVerifier;
_startupContext = startupContext; _startupContext = startupContext;
_deploymentInfoProvider = deploymentInfoProvider; _deploymentInfoProvider = deploymentInfoProvider;
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
_configFileWriter = configFileWriter;
_runtimeInfo = runtimeInfo; _runtimeInfo = runtimeInfo;
_backupService = backupService; _backupService = backupService;
_osInfo = osInfo; _osInfo = osInfo;
@@ -83,7 +88,7 @@ namespace NzbDrone.Core.Update
{ {
EnsureAppDataSafety(); EnsureAppDataSafety();
if (OsInfo.IsWindows || _configFileProvider.UpdateMechanism != UpdateMechanism.Script) if (OsInfo.IsWindows || _configFileOptions.CurrentValue.UpdateMechanism != UpdateMechanism.Script)
{ {
var startupFolder = _appFolderInfo.StartUpFolder; var startupFolder = _appFolderInfo.StartUpFolder;
var uiFolder = Path.Combine(startupFolder, "UI"); var uiFolder = Path.Combine(startupFolder, "UI");
@@ -137,7 +142,7 @@ namespace NzbDrone.Core.Update
_backupService.Backup(BackupType.Update); _backupService.Backup(BackupType.Update);
if (OsInfo.IsNotWindows && _configFileProvider.UpdateMechanism == UpdateMechanism.Script) if (OsInfo.IsNotWindows && _configFileOptions.CurrentValue.UpdateMechanism == UpdateMechanism.Script)
{ {
InstallUpdateWithScript(updateSandboxFolder); InstallUpdateWithScript(updateSandboxFolder);
return true; return true;
@@ -170,7 +175,7 @@ namespace NzbDrone.Core.Update
private void EnsureValidBranch(UpdatePackage package) private void EnsureValidBranch(UpdatePackage package)
{ {
var currentBranch = _configFileProvider.Branch; var currentBranch = _configFileOptions.CurrentValue.Branch;
if (package.Branch != currentBranch) if (package.Branch != currentBranch)
{ {
try try
@@ -178,7 +183,7 @@ namespace NzbDrone.Core.Update
_logger.Info("Branch [{0}] is being redirected to [{1}]]", currentBranch, package.Branch); _logger.Info("Branch [{0}] is being redirected to [{1}]]", currentBranch, package.Branch);
var config = new Dictionary<string, object>(); var config = new Dictionary<string, object>();
config["Branch"] = package.Branch; config["Branch"] = package.Branch;
_configFileProvider.SaveConfigDictionary(config); _configFileWriter.SaveConfigDictionary(config);
} }
catch (Exception e) catch (Exception e)
{ {
@@ -189,7 +194,7 @@ namespace NzbDrone.Core.Update
private void InstallUpdateWithScript(string updateSandboxFolder) private void InstallUpdateWithScript(string updateSandboxFolder)
{ {
var scriptPath = _configFileProvider.UpdateScriptPath; var scriptPath = _configFileOptions.CurrentValue.UpdateScriptPath;
if (scriptPath.IsNullOrWhiteSpace()) if (scriptPath.IsNullOrWhiteSpace())
{ {
@@ -204,7 +209,7 @@ namespace NzbDrone.Core.Update
_logger.Info("Removing Radarr.Update"); _logger.Info("Removing Radarr.Update");
_diskProvider.DeleteFolder(_appFolderInfo.GetUpdateClientFolder(), true); _diskProvider.DeleteFolder(_appFolderInfo.GetUpdateClientFolder(), true);
_logger.ProgressInfo("Starting update script: {0}", _configFileProvider.UpdateScriptPath); _logger.ProgressInfo("Starting update script: {0}", _configFileOptions.CurrentValue.UpdateScriptPath);
_processProvider.Start(scriptPath, GetUpdaterArgs(updateSandboxFolder)); _processProvider.Start(scriptPath, GetUpdaterArgs(updateSandboxFolder));
} }
@@ -243,19 +248,19 @@ namespace NzbDrone.Core.Update
return null; return null;
} }
if (OsInfo.IsNotWindows && !_configFileProvider.UpdateAutomatically && updateTrigger != CommandTrigger.Manual) if (OsInfo.IsNotWindows && !_configFileOptions.CurrentValue.UpdateAutomatically && updateTrigger != CommandTrigger.Manual)
{ {
_logger.ProgressDebug("Auto-update not enabled, not installing available update."); _logger.ProgressDebug("Auto-update not enabled, not installing available update.");
return null; return null;
} }
// Safety net, ConfigureUpdateMechanism should take care of invalid settings // Safety net, ConfigureUpdateMechanism should take care of invalid settings
if (_configFileProvider.UpdateMechanism == UpdateMechanism.BuiltIn && _deploymentInfoProvider.IsExternalUpdateMechanism) if (_configFileOptions.CurrentValue.UpdateMechanism == UpdateMechanism.BuiltIn && _deploymentInfoProvider.IsExternalUpdateMechanism)
{ {
_logger.ProgressDebug("Built-In updater disabled, please use {0} to install", _deploymentInfoProvider.PackageUpdateMechanism); _logger.ProgressDebug("Built-In updater disabled, please use {0} to install", _deploymentInfoProvider.PackageUpdateMechanism);
return null; return null;
} }
else if (_configFileProvider.UpdateMechanism != UpdateMechanism.Script && _deploymentInfoProvider.IsExternalUpdateMechanism) else if (_configFileOptions.CurrentValue.UpdateMechanism != UpdateMechanism.Script && _deploymentInfoProvider.IsExternalUpdateMechanism)
{ {
_logger.ProgressDebug("Update available, please use {0} to install", _deploymentInfoProvider.PackageUpdateMechanism); _logger.ProgressDebug("Update available, please use {0} to install", _deploymentInfoProvider.PackageUpdateMechanism);
return null; return null;
@@ -315,8 +320,8 @@ namespace NzbDrone.Core.Update
_logger.Debug("Post-install update check requested"); _logger.Debug("Post-install update check requested");
// Don't do a prestartup update check unless BuiltIn update is enabled // Don't do a prestartup update check unless BuiltIn update is enabled
if (!_configFileProvider.UpdateAutomatically || if (!_configFileOptions.CurrentValue.UpdateAutomatically ||
_configFileProvider.UpdateMechanism != UpdateMechanism.BuiltIn || _configFileOptions.CurrentValue.UpdateMechanism != UpdateMechanism.BuiltIn ||
_deploymentInfoProvider.IsExternalUpdateMechanism) _deploymentInfoProvider.IsExternalUpdateMechanism)
{ {
_logger.Debug("Built-in updater disabled, skipping post-install update check"); _logger.Debug("Built-in updater disabled, skipping post-install update check");

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.Extensions.Options;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Update.History; using NzbDrone.Core.Update.History;
@@ -12,22 +13,22 @@ namespace NzbDrone.Core.Update
public class RecentUpdateProvider : IRecentUpdateProvider public class RecentUpdateProvider : IRecentUpdateProvider
{ {
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
private readonly IUpdatePackageProvider _updatePackageProvider; private readonly IUpdatePackageProvider _updatePackageProvider;
private readonly IUpdateHistoryService _updateHistoryService; private readonly IUpdateHistoryService _updateHistoryService;
public RecentUpdateProvider(IConfigFileProvider configFileProvider, public RecentUpdateProvider(IOptionsMonitor<ConfigFileOptions> configFileOptions,
IUpdatePackageProvider updatePackageProvider, IUpdatePackageProvider updatePackageProvider,
IUpdateHistoryService updateHistoryService) IUpdateHistoryService updateHistoryService)
{ {
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
_updatePackageProvider = updatePackageProvider; _updatePackageProvider = updatePackageProvider;
_updateHistoryService = updateHistoryService; _updateHistoryService = updateHistoryService;
} }
public List<UpdatePackage> GetRecentUpdatePackages() public List<UpdatePackage> GetRecentUpdatePackages()
{ {
var branch = _configFileProvider.Branch; var branch = _configFileOptions.CurrentValue.Branch;
var version = BuildInfo.Version; var version = BuildInfo.Version;
var prevVersion = _updateHistoryService.PreviouslyInstalled(); var prevVersion = _updateHistoryService.PreviouslyInstalled();
return _updatePackageProvider.GetRecentUpdates(branch, version, prevVersion); return _updatePackageProvider.GetRecentUpdates(branch, version, prevVersion);

View File

@@ -1,3 +1,4 @@
using Microsoft.Extensions.Options;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
@@ -11,18 +12,18 @@ namespace NzbDrone.Core.Update
public class CheckUpdateService : ICheckUpdateService public class CheckUpdateService : ICheckUpdateService
{ {
private readonly IUpdatePackageProvider _updatePackageProvider; private readonly IUpdatePackageProvider _updatePackageProvider;
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
public CheckUpdateService(IUpdatePackageProvider updatePackageProvider, public CheckUpdateService(IUpdatePackageProvider updatePackageProvider,
IConfigFileProvider configFileProvider) IOptionsMonitor<ConfigFileOptions> configFileOptions)
{ {
_updatePackageProvider = updatePackageProvider; _updatePackageProvider = updatePackageProvider;
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
} }
public UpdatePackage AvailableUpdate() public UpdatePackage AvailableUpdate()
{ {
return _updatePackageProvider.GetLatestUpdate(_configFileProvider.Branch, BuildInfo.Version); return _updatePackageProvider.GetLatestUpdate(_configFileOptions.CurrentValue.Branch, BuildInfo.Version);
} }
} }
} }

View File

@@ -12,6 +12,7 @@ using NzbDrone.Common;
using NzbDrone.Common.Composition.Extensions; using NzbDrone.Common.Composition.Extensions;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Instrumentation.Extensions; using NzbDrone.Common.Instrumentation.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore;
using NzbDrone.Core.Datastore.Extensions; using NzbDrone.Core.Datastore.Extensions;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
@@ -44,9 +45,9 @@ namespace NzbDrone.App.Test
.AddStartupContext(args); .AddStartupContext(args);
// dummy lifetime and broadcaster so tests resolve // dummy lifetime and broadcaster so tests resolve
container.RegisterInstance<IHostLifetime>(new Mock<IHostLifetime>().Object); container.RegisterInstance(new Mock<IHostLifetime>().Object);
container.RegisterInstance<IBroadcastSignalRMessage>(new Mock<IBroadcastSignalRMessage>().Object); container.RegisterInstance(new Mock<IBroadcastSignalRMessage>().Object);
container.RegisterInstance<IOptions<PostgresOptions>>(new Mock<IOptions<PostgresOptions>>().Object); container.RegisterInstance(new Mock<IOptionsMonitor<ConfigFileOptions>>().Object);
_container = container.GetServiceProvider(); _container = container.GetServiceProvider();
} }

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Linq; using System.Linq;
using Microsoft.Extensions.Options;
using NetFwTypeLib; using NetFwTypeLib;
using NLog; using NLog;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
@@ -16,12 +17,12 @@ namespace Radarr.Host.AccessControl
{ {
private const NET_FW_PROFILE_TYPE_ FIREWALL_PROFILE = NET_FW_PROFILE_TYPE_.NET_FW_PROFILE_STANDARD; private const NET_FW_PROFILE_TYPE_ FIREWALL_PROFILE = NET_FW_PROFILE_TYPE_.NET_FW_PROFILE_STANDARD;
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
private readonly Logger _logger; private readonly Logger _logger;
public FirewallAdapter(IConfigFileProvider configFileProvider, Logger logger) public FirewallAdapter(IOptionsMonitor<ConfigFileOptions> configFileOptions, Logger logger)
{ {
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
_logger = logger; _logger = logger;
} }
@@ -29,16 +30,16 @@ namespace Radarr.Host.AccessControl
{ {
if (IsFirewallEnabled()) if (IsFirewallEnabled())
{ {
if (!IsNzbDronePortOpen(_configFileProvider.Port)) if (!IsNzbDronePortOpen(_configFileOptions.CurrentValue.Port))
{ {
_logger.Debug("Opening Port for Radarr: {0}", _configFileProvider.Port); _logger.Debug("Opening Port for Radarr: {0}", _configFileOptions.CurrentValue.Port);
OpenFirewallPort(_configFileProvider.Port); OpenFirewallPort(_configFileOptions.CurrentValue.Port);
} }
if (_configFileProvider.EnableSsl && !IsNzbDronePortOpen(_configFileProvider.SslPort)) if (_configFileOptions.CurrentValue.EnableSsl && !IsNzbDronePortOpen(_configFileOptions.CurrentValue.SslPort))
{ {
_logger.Debug("Opening SSL Port for Radarr: {0}", _configFileProvider.SslPort); _logger.Debug("Opening SSL Port for Radarr: {0}", _configFileOptions.CurrentValue.SslPort);
OpenFirewallPort(_configFileProvider.SslPort); OpenFirewallPort(_configFileOptions.CurrentValue.SslPort);
} }
} }
} }

View File

@@ -1,6 +1,7 @@
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using NLog; using NLog;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Processes; using NzbDrone.Common.Processes;
@@ -14,7 +15,7 @@ namespace NzbDrone.Host
public class AppLifetime : IHostedService, IHandle<ApplicationShutdownRequested> public class AppLifetime : IHostedService, IHandle<ApplicationShutdownRequested>
{ {
private readonly IHostApplicationLifetime _appLifetime; private readonly IHostApplicationLifetime _appLifetime;
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
private readonly IRuntimeInfo _runtimeInfo; private readonly IRuntimeInfo _runtimeInfo;
private readonly IStartupContext _startupContext; private readonly IStartupContext _startupContext;
private readonly IBrowserService _browserService; private readonly IBrowserService _browserService;
@@ -23,7 +24,7 @@ namespace NzbDrone.Host
private readonly Logger _logger; private readonly Logger _logger;
public AppLifetime(IHostApplicationLifetime appLifetime, public AppLifetime(IHostApplicationLifetime appLifetime,
IConfigFileProvider configFileProvider, IOptionsMonitor<ConfigFileOptions> configFileOptions,
IRuntimeInfo runtimeInfo, IRuntimeInfo runtimeInfo,
IStartupContext startupContext, IStartupContext startupContext,
IBrowserService browserService, IBrowserService browserService,
@@ -32,7 +33,7 @@ namespace NzbDrone.Host
Logger logger) Logger logger)
{ {
_appLifetime = appLifetime; _appLifetime = appLifetime;
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
_runtimeInfo = runtimeInfo; _runtimeInfo = runtimeInfo;
_startupContext = startupContext; _startupContext = startupContext;
_browserService = browserService; _browserService = browserService;
@@ -59,7 +60,7 @@ namespace NzbDrone.Host
_runtimeInfo.IsExiting = false; _runtimeInfo.IsExiting = false;
if (!_startupContext.Flags.Contains(StartupContext.NO_BROWSER) if (!_startupContext.Flags.Contains(StartupContext.NO_BROWSER)
&& _configFileProvider.LaunchBrowser) && _configFileOptions.CurrentValue.LaunchBrowser)
{ {
_browserService.LaunchWebUI(); _browserService.LaunchWebUI();
} }

View File

@@ -3,8 +3,6 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text; using System.Text;
using DryIoc; using DryIoc;
using DryIoc.Microsoft.DependencyInjection; using DryIoc.Microsoft.DependencyInjection;
@@ -23,7 +21,6 @@ using NzbDrone.Common.Instrumentation.Extensions;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Datastore.Extensions; using NzbDrone.Core.Datastore.Extensions;
using NzbDrone.Host; using NzbDrone.Host;
using PostgresOptions = NzbDrone.Core.Datastore.PostgresOptions;
namespace Radarr.Host namespace Radarr.Host
{ {
@@ -53,7 +50,6 @@ namespace Radarr.Host
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
var appMode = GetApplicationMode(startupContext); var appMode = GetApplicationMode(startupContext);
var config = GetConfiguration(startupContext);
switch (appMode) switch (appMode)
{ {
@@ -86,18 +82,13 @@ namespace Radarr.Host
.UseServiceProviderFactory(new DryIocServiceProviderFactory(new Container(rules => rules.WithNzbDroneRules()))) .UseServiceProviderFactory(new DryIocServiceProviderFactory(new Container(rules => rules.WithNzbDroneRules())))
.ConfigureContainer<IContainer>(c => .ConfigureContainer<IContainer>(c =>
{ {
c.AutoAddServices(Bootstrap.ASSEMBLIES) c.AutoAddServices(ASSEMBLIES)
.AddNzbDroneLogger() .AddNzbDroneLogger()
.AddDatabase() .AddDatabase()
.AddStartupContext(startupContext) .AddStartupContext(startupContext)
.Resolve<UtilityModeRouter>() .Resolve<UtilityModeRouter>()
.Route(appMode); .Route(appMode);
})
.ConfigureServices(services =>
{
services.Configure<PostgresOptions>(config.GetSection("Radarr:Postgres"));
}).Build(); }).Build();
break; break;
} }
} }
@@ -115,55 +106,20 @@ namespace Radarr.Host
public static IHostBuilder CreateConsoleHostBuilder(string[] args, StartupContext context) public static IHostBuilder CreateConsoleHostBuilder(string[] args, StartupContext context)
{ {
var config = GetConfiguration(context);
var bindAddress = config.GetValue(nameof(ConfigFileProvider.BindAddress), "*");
var port = config.GetValue(nameof(ConfigFileProvider.Port), 7878);
var sslPort = config.GetValue(nameof(ConfigFileProvider.SslPort), 8787);
var enableSsl = config.GetValue(nameof(ConfigFileProvider.EnableSsl), false);
var sslCertPath = config.GetValue<string>(nameof(ConfigFileProvider.SslCertPath));
var sslCertPassword = config.GetValue<string>(nameof(ConfigFileProvider.SslCertPassword));
var urls = new List<string> { BuildUrl("http", bindAddress, port) };
if (enableSsl && sslCertPath.IsNotNullOrWhiteSpace())
{
urls.Add(BuildUrl("https", bindAddress, sslPort));
}
return new HostBuilder() return new HostBuilder()
.UseContentRoot(Directory.GetCurrentDirectory()) .UseContentRoot(Directory.GetCurrentDirectory())
.AddConfig(context)
.UseServiceProviderFactory(new DryIocServiceProviderFactory(new Container(rules => rules.WithNzbDroneRules()))) .UseServiceProviderFactory(new DryIocServiceProviderFactory(new Container(rules => rules.WithNzbDroneRules())))
.ConfigureContainer<IContainer>(c => .ConfigureContainer<IContainer>(c =>
{ {
c.AutoAddServices(Bootstrap.ASSEMBLIES) c.AutoAddServices(ASSEMBLIES)
.AddNzbDroneLogger() .AddNzbDroneLogger()
.AddDatabase() .AddDatabase()
.AddStartupContext(context); .AddStartupContext(context);
}) })
.ConfigureServices(services =>
{
services.Configure<PostgresOptions>(config.GetSection("Radarr:Postgres"));
})
.ConfigureWebHost(builder => .ConfigureWebHost(builder =>
{ {
builder.UseConfiguration(config); builder.UseKestrel();
builder.UseUrls(urls.ToArray());
builder.UseKestrel(options =>
{
if (enableSsl && sslCertPath.IsNotNullOrWhiteSpace())
{
options.ConfigureHttpsDefaults(configureOptions =>
{
configureOptions.ServerCertificate = ValidateSslCertificate(sslCertPath, sslCertPassword);
});
}
});
builder.ConfigureKestrel(serverOptions =>
{
serverOptions.AllowSynchronousIO = true;
serverOptions.Limits.MaxRequestBodySize = null;
});
builder.UseStartup<Startup>(); builder.UseStartup<Startup>();
}); });
} }
@@ -209,41 +165,15 @@ namespace Radarr.Host
return ApplicationModes.Interactive; return ApplicationModes.Interactive;
} }
private static IConfiguration GetConfiguration(StartupContext context) private static IHostBuilder AddConfig(this IHostBuilder builder, StartupContext context)
{ {
var appFolder = new AppFolderInfo(context); var appFolder = new AppFolderInfo(context);
return new ConfigurationBuilder() return builder.ConfigureAppConfiguration((_, config) =>
.AddXmlFile(appFolder.GetConfigPath(), optional: true, reloadOnChange: false) {
config.AddXmlFile(appFolder.GetConfigPath(), optional: true, reloadOnChange: true)
.AddInMemoryCollection(new List<KeyValuePair<string, string>> { new ("dataProtectionFolder", appFolder.GetDataProtectionPath()) }) .AddInMemoryCollection(new List<KeyValuePair<string, string>> { new ("dataProtectionFolder", appFolder.GetDataProtectionPath()) })
.AddEnvironmentVariables() .AddEnvironmentVariables($"{BuildInfo.AppName}:");
.Build(); });
}
private static string BuildUrl(string scheme, string bindAddress, int port)
{
return $"{scheme}://{bindAddress}:{port}";
}
private static X509Certificate2 ValidateSslCertificate(string cert, string password)
{
X509Certificate2 certificate;
try
{
certificate = new X509Certificate2(cert, password, X509KeyStorageFlags.DefaultKeySet);
}
catch (CryptographicException ex)
{
if (ex.HResult == 0x2 || ex.HResult == 0x2006D080)
{
throw new RadarrStartupException(ex,
$"The SSL certificate file {cert} does not exist");
}
throw new RadarrStartupException(ex);
}
return certificate;
} }
} }
} }

View File

@@ -1,4 +1,5 @@
using System; using System;
using Microsoft.Extensions.Options;
using NLog; using NLog;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Processes; using NzbDrone.Common.Processes;
@@ -14,21 +15,21 @@ namespace Radarr.Host
public class BrowserService : IBrowserService public class BrowserService : IBrowserService
{ {
private readonly IProcessProvider _processProvider; private readonly IProcessProvider _processProvider;
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
private readonly IRuntimeInfo _runtimeInfo; private readonly IRuntimeInfo _runtimeInfo;
private readonly Logger _logger; private readonly Logger _logger;
public BrowserService(IProcessProvider processProvider, IConfigFileProvider configFileProvider, IRuntimeInfo runtimeInfo, Logger logger) public BrowserService(IProcessProvider processProvider, IOptionsMonitor<ConfigFileOptions> configFileOptions, IRuntimeInfo runtimeInfo, Logger logger)
{ {
_processProvider = processProvider; _processProvider = processProvider;
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
_runtimeInfo = runtimeInfo; _runtimeInfo = runtimeInfo;
_logger = logger; _logger = logger;
} }
public void LaunchWebUI() public void LaunchWebUI()
{ {
var url = string.Format("http://localhost:{0}", _configFileProvider.Port); var url = string.Format("http://localhost:{0}", _configFileOptions.CurrentValue.Port);
try try
{ {
if (_runtimeInfo.IsUserInteractive) if (_runtimeInfo.IsUserInteractive)

View File

@@ -0,0 +1,81 @@
using System;
using System.Net;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.Options;
using NzbDrone.Common.Exceptions;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
namespace NzbDrone.Host
{
public class ConfigureKestrel : IConfigureOptions<KestrelServerOptions>
{
private readonly IOptionsMonitor<ConfigFileOptions> _config;
public ConfigureKestrel(IOptionsMonitor<ConfigFileOptions> config)
{
_config = config;
}
public void Configure(KestrelServerOptions options)
{
options.AllowSynchronousIO = true;
options.Limits.MaxRequestBodySize = null;
Listen(options, _config.CurrentValue.BindAddress, _config.CurrentValue.Port);
if (_config.CurrentValue.EnableSsl && _config.CurrentValue.SslCertPath.IsNotNullOrWhiteSpace())
{
options.ConfigureHttpsDefaults(opts => opts.ServerCertificate = ValidateSslCertificate(_config.CurrentValue.SslCertPath, _config.CurrentValue.SslCertPassword));
Listen(options, _config.CurrentValue.BindAddress, _config.CurrentValue.SslPort, opts => opts.UseHttps());
}
}
private static void Listen(KestrelServerOptions options, string address, int port)
{
Listen(options, address, port, _ => { });
}
private static void Listen(KestrelServerOptions options, string address, int port, Action<ListenOptions> configureListenOptions)
{
// following https://github.com/dotnet/aspnetcore/blob/d96a100bddc72606f7417b665428411388b8ac54/src/Servers/Kestrel/Core/src/Internal/AddressBinder.cs#L123
if (string.Equals(address, "localhost", StringComparison.OrdinalIgnoreCase))
{
options.ListenLocalhost(port, configureListenOptions);
}
else if (IPAddress.TryParse(address, out var endpoint))
{
options.Listen(endpoint, port, configureListenOptions);
}
else
{
options.ListenAnyIP(port, configureListenOptions);
}
}
private static X509Certificate2 ValidateSslCertificate(string cert, string password)
{
X509Certificate2 certificate;
try
{
certificate = new X509Certificate2(cert, password, X509KeyStorageFlags.DefaultKeySet);
}
catch (CryptographicException ex)
{
if (ex.HResult == 0x2 || ex.HResult == 0x2006D080)
{
throw new RadarrStartupException(ex,
$"The SSL certificate file {cert} does not exist");
}
throw new RadarrStartupException(ex);
}
return certificate;
}
}
}

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing;
using System.IO; using System.IO;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
@@ -10,6 +11,7 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using NLog.Extensions.Logging; using NLog.Extensions.Logging;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
@@ -44,13 +46,14 @@ namespace NzbDrone.Host
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
services.Configure<ConfigFileOptions>(Configuration);
services.AddLogging(b => services.AddLogging(b =>
{ {
b.ClearProviders(); b.ClearProviders();
b.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace); b.SetMinimumLevel(LogLevel.Trace);
b.AddFilter("Microsoft.AspNetCore", Microsoft.Extensions.Logging.LogLevel.Warning); b.AddFilter("Microsoft.AspNetCore", LogLevel.Warning);
b.AddFilter("Radarr.Http.Authentication", LogLevel.Information); b.AddFilter("Radarr.Http.Authentication", LogLevel.Information);
b.AddFilter("Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager", LogLevel.Error);
b.AddNLog(); b.AddNLog();
}); });
@@ -213,7 +216,8 @@ namespace NzbDrone.Host
ReconfigureLogging reconfigureLogging, ReconfigureLogging reconfigureLogging,
IAppFolderFactory appFolderFactory, IAppFolderFactory appFolderFactory,
IProvidePidFile pidFileProvider, IProvidePidFile pidFileProvider,
IConfigFileProvider configFileProvider, IConfigFileWriter configFileWriter,
IOptions<ConfigFileOptions> configFileOptions,
IRuntimeInfo runtimeInfo, IRuntimeInfo runtimeInfo,
IFirewallAdapter firewallAdapter, IFirewallAdapter firewallAdapter,
RadarrErrorPipeline errorHandler) RadarrErrorPipeline errorHandler)
@@ -221,6 +225,7 @@ namespace NzbDrone.Host
initializeLogger.Initialize(); initializeLogger.Initialize();
appFolderFactory.Register(); appFolderFactory.Register();
pidFileProvider.Write(); pidFileProvider.Write();
configFileWriter.EnsureDefaultConfigFile();
reconfigureLogging.Reconfigure(); reconfigureLogging.Reconfigure();
@@ -244,7 +249,7 @@ namespace NzbDrone.Host
app.UseForwardedHeaders(); app.UseForwardedHeaders();
app.UseMiddleware<LoggingMiddleware>(); app.UseMiddleware<LoggingMiddleware>();
app.UsePathBase(new PathString(configFileProvider.UrlBase)); app.UsePathBase(new PathString(configFileOptions.Value.UrlBase));
app.UseExceptionHandler(new ExceptionHandlerOptions app.UseExceptionHandler(new ExceptionHandlerOptions
{ {
AllowStatusCode404Response = true, AllowStatusCode404Response = true,
@@ -259,7 +264,7 @@ namespace NzbDrone.Host
app.Properties["host.AppName"] = BuildInfo.AppName; app.Properties["host.AppName"] = BuildInfo.AppName;
app.UseMiddleware<VersionMiddleware>(); app.UseMiddleware<VersionMiddleware>();
app.UseMiddleware<UrlBaseMiddleware>(configFileProvider.UrlBase); app.UseMiddleware<UrlBaseMiddleware>(configFileOptions.Value.UrlBase);
app.UseMiddleware<CacheHeaderMiddleware>(); app.UseMiddleware<CacheHeaderMiddleware>();
app.UseMiddleware<IfModifiedMiddleware>(); app.UseMiddleware<IfModifiedMiddleware>();
app.UseMiddleware<BufferingMiddleware>(new List<string> { "/api/v3/command" }); app.UseMiddleware<BufferingMiddleware>(new List<string> { "/api/v3/command" });

View File

@@ -5,6 +5,7 @@ using NLog;
using Npgsql; using Npgsql;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore;
using NzbDrone.Core.Datastore.Migration.Framework; using NzbDrone.Core.Datastore.Migration.Framework;
using NzbDrone.Core.Indexers.Newznab; using NzbDrone.Core.Indexers.Newznab;
@@ -25,7 +26,7 @@ namespace NzbDrone.Integration.Test
protected int Port { get; private set; } protected int Port { get; private set; }
protected PostgresOptions PostgresOptions { get; set; } = new (); protected ConfigFileOptions Options { get; set; } = new ();
protected override string RootUrl => $"http://localhost:{Port}/"; protected override string RootUrl => $"http://localhost:{Port}/";
@@ -35,14 +36,14 @@ namespace NzbDrone.Integration.Test
{ {
Port = Interlocked.Increment(ref StaticPort); Port = Interlocked.Increment(ref StaticPort);
PostgresOptions = PostgresDatabase.GetTestOptions(); Options = PostgresDatabase.GetTestOptions();
if (PostgresOptions?.Host != null) if (Options?.PostgresHost != null)
{ {
CreatePostgresDb(PostgresOptions); CreatePostgresDb(Options);
} }
_runner = new NzbDroneRunner(LogManager.GetCurrentClassLogger(), PostgresOptions, Port); _runner = new NzbDroneRunner(LogManager.GetCurrentClassLogger(), Options, Port);
_runner.Kill(); _runner.Kill();
_runner.Start(); _runner.Start();
@@ -74,19 +75,19 @@ namespace NzbDrone.Integration.Test
protected override void StopTestTarget() protected override void StopTestTarget()
{ {
_runner.Kill(); _runner.Kill();
if (PostgresOptions?.Host != null) if (Options?.PostgresHost != null)
{ {
DropPostgresDb(PostgresOptions); DropPostgresDb(Options);
} }
} }
private static void CreatePostgresDb(PostgresOptions options) private static void CreatePostgresDb(ConfigFileOptions options)
{ {
PostgresDatabase.Create(options, MigrationType.Main); PostgresDatabase.Create(options, MigrationType.Main);
PostgresDatabase.Create(options, MigrationType.Log); PostgresDatabase.Create(options, MigrationType.Log);
} }
private static void DropPostgresDb(PostgresOptions options) private static void DropPostgresDb(ConfigFileOptions options)
{ {
PostgresDatabase.Drop(options, MigrationType.Main); PostgresDatabase.Drop(options, MigrationType.Main);
PostgresDatabase.Drop(options, MigrationType.Log); PostgresDatabase.Drop(options, MigrationType.Log);

View File

@@ -1,5 +1,6 @@
using System; using System;
using Npgsql; using Npgsql;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore;
using NzbDrone.Core.Datastore.Migration.Framework; using NzbDrone.Core.Datastore.Migration.Framework;
@@ -7,18 +8,18 @@ namespace NzbDrone.Test.Common.Datastore
{ {
public static class PostgresDatabase public static class PostgresDatabase
{ {
public static PostgresOptions GetTestOptions() public static ConfigFileOptions GetTestOptions()
{ {
var options = PostgresOptions.GetOptions(); var options = ConfigFileOptions.GetOptions();
var uid = TestBase.GetUID(); var uid = TestBase.GetUID();
options.MainDb = uid + "_main"; options.PostgresMainDb = uid + "_main";
options.LogDb = uid + "_log"; options.PostgresLogDb = uid + "_log";
return options; return options;
} }
public static void Create(PostgresOptions options, MigrationType migrationType) public static void Create(ConfigFileOptions options, MigrationType migrationType)
{ {
var db = GetDatabaseName(options, migrationType); var db = GetDatabaseName(options, migrationType);
var connectionString = GetConnectionString(options); var connectionString = GetConnectionString(options);
@@ -26,11 +27,11 @@ namespace NzbDrone.Test.Common.Datastore
conn.Open(); conn.Open();
using var cmd = conn.CreateCommand(); using var cmd = conn.CreateCommand();
cmd.CommandText = $"CREATE DATABASE \"{db}\" WITH OWNER = {options.User} ENCODING = 'UTF8' CONNECTION LIMIT = -1;"; cmd.CommandText = $"CREATE DATABASE \"{db}\" WITH OWNER = {options.PostgresUser} ENCODING = 'UTF8' CONNECTION LIMIT = -1;";
cmd.ExecuteNonQuery(); cmd.ExecuteNonQuery();
} }
public static void Drop(PostgresOptions options, MigrationType migrationType) public static void Drop(ConfigFileOptions options, MigrationType migrationType)
{ {
var db = GetDatabaseName(options, migrationType); var db = GetDatabaseName(options, migrationType);
var connectionString = GetConnectionString(options); var connectionString = GetConnectionString(options);
@@ -42,26 +43,26 @@ namespace NzbDrone.Test.Common.Datastore
cmd.ExecuteNonQuery(); cmd.ExecuteNonQuery();
} }
private static string GetConnectionString(PostgresOptions options) private static string GetConnectionString(ConfigFileOptions options)
{ {
var builder = new NpgsqlConnectionStringBuilder() var builder = new NpgsqlConnectionStringBuilder()
{ {
Host = options.Host, Host = options.PostgresHost,
Port = options.Port, Port = options.PostgresPort,
Username = options.User, Username = options.PostgresUser,
Password = options.Password, Password = options.PostgresPassword,
Enlist = false Enlist = false
}; };
return builder.ConnectionString; return builder.ConnectionString;
} }
private static string GetDatabaseName(PostgresOptions options, MigrationType migrationType) private static string GetDatabaseName(ConfigFileOptions options, MigrationType migrationType)
{ {
return migrationType switch return migrationType switch
{ {
MigrationType.Main => options.MainDb, MigrationType.Main => options.PostgresMainDb,
MigrationType.Log => options.LogDb, MigrationType.Log => options.PostgresLogDb,
_ => throw new NotImplementedException("Unknown migration type") _ => throw new NotImplementedException("Unknown migration type")
}; };
} }

View File

@@ -25,15 +25,15 @@ namespace NzbDrone.Test.Common
public string AppData { get; private set; } public string AppData { get; private set; }
public string ApiKey { get; private set; } public string ApiKey { get; private set; }
public PostgresOptions PostgresOptions { get; private set; } public ConfigFileOptions Options { get; private set; }
public int Port { get; private set; } public int Port { get; private set; }
public NzbDroneRunner(Logger logger, PostgresOptions postgresOptions, int port = 7878) public NzbDroneRunner(Logger logger, ConfigFileOptions options, int port = 7878)
{ {
_processProvider = new ProcessProvider(logger); _processProvider = new ProcessProvider(logger);
_restClient = new RestClient($"http://localhost:{port}/api/v3"); _restClient = new RestClient($"http://localhost:{port}/api/v3");
PostgresOptions = postgresOptions; Options = options;
Port = port; Port = port;
} }
@@ -138,14 +138,14 @@ namespace NzbDrone.Test.Common
private void Start(string outputRadarrConsoleExe) private void Start(string outputRadarrConsoleExe)
{ {
StringDictionary envVars = new (); StringDictionary envVars = new ();
if (PostgresOptions?.Host != null) if (Options?.PostgresHost != null)
{ {
envVars.Add("Radarr__Postgres__Host", PostgresOptions.Host); envVars.Add("Radarr__PostgresHost", Options.PostgresHost);
envVars.Add("Radarr__Postgres__Port", PostgresOptions.Port.ToString()); envVars.Add("Radarr__PostgresPort", Options.PostgresPort.ToString());
envVars.Add("Radarr__Postgres__User", PostgresOptions.User); envVars.Add("Radarr__PostgresUser", Options.PostgresUser);
envVars.Add("Radarr__Postgres__Password", PostgresOptions.Password); envVars.Add("Radarr__PostgresPassword", Options.PostgresPassword);
envVars.Add("Radarr__Postgres__MainDb", PostgresOptions.MainDb); envVars.Add("Radarr__PostgresMainDb", Options.PostgresMainDb);
envVars.Add("Radarr__Postgres__LogDb", PostgresOptions.LogDb); envVars.Add("Radarr__PostgresLogDb", Options.PostgresLogDb);
TestContext.Progress.WriteLine("Using env vars:\n{0}", envVars.ToJson()); TestContext.Progress.WriteLine("Using env vars:\n{0}", envVars.ToJson());
} }
@@ -175,11 +175,11 @@ namespace NzbDrone.Test.Common
var xDoc = new XDocument( var xDoc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"), new XDeclaration("1.0", "utf-8", "yes"),
new XElement(ConfigFileProvider.CONFIG_ELEMENT_NAME, new XElement(ConfigFileWriter.CONFIG_ELEMENT_NAME,
new XElement(nameof(ConfigFileProvider.ApiKey), apiKey), new XElement(nameof(ConfigFileOptions.ApiKey), apiKey),
new XElement(nameof(ConfigFileProvider.LogLevel), "trace"), new XElement(nameof(ConfigFileOptions.LogLevel), "trace"),
new XElement(nameof(ConfigFileProvider.AnalyticsEnabled), false), new XElement(nameof(ConfigFileOptions.AnalyticsEnabled), false),
new XElement(nameof(ConfigFileProvider.Port), Port))); new XElement(nameof(ConfigFileOptions.Port), Port)));
var data = xDoc.ToString(); var data = xDoc.ToString();

View File

@@ -4,6 +4,7 @@ using System.Reflection;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using FluentValidation; using FluentValidation;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Authentication; using NzbDrone.Core.Authentication;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
@@ -19,16 +20,19 @@ namespace Radarr.Api.V3.Config
[V3ApiController("config/host")] [V3ApiController("config/host")]
public class HostConfigController : RestController<HostConfigResource> public class HostConfigController : RestController<HostConfigResource>
{ {
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
private readonly IConfigFileWriter _configFileWriter;
private readonly IConfigService _configService; private readonly IConfigService _configService;
private readonly IUserService _userService; private readonly IUserService _userService;
public HostConfigController(IConfigFileProvider configFileProvider, public HostConfigController(IOptionsMonitor<ConfigFileOptions> configFileOptions,
IConfigFileWriter configFileWriter,
IConfigService configService, IConfigService configService,
IUserService userService, IUserService userService,
FileExistsValidator fileExistsValidator) FileExistsValidator fileExistsValidator)
{ {
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
_configFileWriter = configFileWriter;
_configService = configService; _configService = configService;
_userService = userService; _userService = userService;
@@ -87,7 +91,7 @@ namespace Radarr.Api.V3.Config
[HttpGet] [HttpGet]
public HostConfigResource GetHostConfig() public HostConfigResource GetHostConfig()
{ {
var resource = _configFileProvider.ToResource(_configService); var resource = _configFileOptions.CurrentValue.ToResource(_configService);
resource.Id = 1; resource.Id = 1;
var user = _userService.FindUser(); var user = _userService.FindUser();
@@ -107,7 +111,7 @@ namespace Radarr.Api.V3.Config
.GetProperties(BindingFlags.Instance | BindingFlags.Public) .GetProperties(BindingFlags.Instance | BindingFlags.Public)
.ToDictionary(prop => prop.Name, prop => prop.GetValue(resource, null)); .ToDictionary(prop => prop.Name, prop => prop.GetValue(resource, null));
_configFileProvider.SaveConfigDictionary(dictionary); _configFileWriter.SaveConfigDictionary(dictionary);
_configService.SaveConfigDictionary(dictionary); _configService.SaveConfigDictionary(dictionary);
if (resource.Username.IsNotNullOrWhiteSpace() && resource.Password.IsNotNullOrWhiteSpace()) if (resource.Username.IsNotNullOrWhiteSpace() && resource.Password.IsNotNullOrWhiteSpace())

View File

@@ -45,7 +45,7 @@ namespace Radarr.Api.V3.Config
public static class HostConfigResourceMapper public static class HostConfigResourceMapper
{ {
public static HostConfigResource ToResource(this IConfigFileProvider model, IConfigService configService) public static HostConfigResource ToResource(this ConfigFileOptions model, IConfigService configService)
{ {
// TODO: Clean this mess up. don't mix data from multiple classes, use sub-resources instead? // TODO: Clean this mess up. don't mix data from multiple classes, use sub-resources instead?
return new HostConfigResource return new HostConfigResource

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using Microsoft.Extensions.Options;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
@@ -16,8 +17,8 @@ namespace Radarr.Api.V3.Logs
public LogFileController(IAppFolderInfo appFolderInfo, public LogFileController(IAppFolderInfo appFolderInfo,
IDiskProvider diskProvider, IDiskProvider diskProvider,
IConfigFileProvider configFileProvider) IOptionsMonitor<ConfigFileOptions> configFileOptions)
: base(diskProvider, configFileProvider, "") : base(diskProvider, configFileOptions, "")
{ {
_appFolderInfo = appFolderInfo; _appFolderInfo = appFolderInfo;
_diskProvider = diskProvider; _diskProvider = diskProvider;

View File

@@ -2,6 +2,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using NLog; using NLog;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
@@ -14,14 +15,14 @@ namespace Radarr.Api.V3.Logs
protected string _resource; protected string _resource;
private readonly IDiskProvider _diskProvider; private readonly IDiskProvider _diskProvider;
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
public LogFileControllerBase(IDiskProvider diskProvider, public LogFileControllerBase(IDiskProvider diskProvider,
IConfigFileProvider configFileProvider, IOptionsMonitor<ConfigFileOptions> configFileOptions,
string resource) string resource)
{ {
_diskProvider = diskProvider; _diskProvider = diskProvider;
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
_resource = resource; _resource = resource;
} }
@@ -42,8 +43,8 @@ namespace Radarr.Api.V3.Logs
Id = i + 1, Id = i + 1,
Filename = filename, Filename = filename,
LastWriteTime = _diskProvider.FileGetLastWrite(file), LastWriteTime = _diskProvider.FileGetLastWrite(file),
ContentsUrl = string.Format("{0}/api/v1/{1}/{2}", _configFileProvider.UrlBase, _resource, filename), ContentsUrl = string.Format("{0}/api/v1/{1}/{2}", _configFileOptions.CurrentValue.UrlBase, _resource, filename),
DownloadUrl = string.Format("{0}/{1}/{2}", _configFileProvider.UrlBase, DownloadUrlRoot, filename) DownloadUrl = string.Format("{0}/{1}/{2}", _configFileOptions.CurrentValue.UrlBase, DownloadUrlRoot, filename)
}); });
} }

View File

@@ -2,6 +2,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Microsoft.Extensions.Options;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
@@ -18,8 +19,8 @@ namespace Radarr.Api.V3.Logs
public UpdateLogFileController(IAppFolderInfo appFolderInfo, public UpdateLogFileController(IAppFolderInfo appFolderInfo,
IDiskProvider diskProvider, IDiskProvider diskProvider,
IConfigFileProvider configFileProvider) IOptionsMonitor<ConfigFileOptions> configFileOptions)
: base(diskProvider, configFileProvider, "update") : base(diskProvider, configFileOptions, "update")
{ {
_appFolderInfo = appFolderInfo; _appFolderInfo = appFolderInfo;
_diskProvider = diskProvider; _diskProvider = diskProvider;

View File

@@ -3,6 +3,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Routing.Internal; using Microsoft.AspNetCore.Routing.Internal;
using Microsoft.Extensions.Options;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
@@ -20,7 +21,7 @@ namespace Radarr.Api.V3.System
private readonly IRuntimeInfo _runtimeInfo; private readonly IRuntimeInfo _runtimeInfo;
private readonly IPlatformInfo _platformInfo; private readonly IPlatformInfo _platformInfo;
private readonly IOsInfo _osInfo; private readonly IOsInfo _osInfo;
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
private readonly IMainDatabase _database; private readonly IMainDatabase _database;
private readonly ILifecycleService _lifecycleService; private readonly ILifecycleService _lifecycleService;
private readonly IDeploymentInfoProvider _deploymentInfoProvider; private readonly IDeploymentInfoProvider _deploymentInfoProvider;
@@ -32,7 +33,7 @@ namespace Radarr.Api.V3.System
IRuntimeInfo runtimeInfo, IRuntimeInfo runtimeInfo,
IPlatformInfo platformInfo, IPlatformInfo platformInfo,
IOsInfo osInfo, IOsInfo osInfo,
IConfigFileProvider configFileProvider, IOptionsMonitor<ConfigFileOptions> configFileOptions,
IMainDatabase database, IMainDatabase database,
ILifecycleService lifecycleService, ILifecycleService lifecycleService,
IDeploymentInfoProvider deploymentInfoProvider, IDeploymentInfoProvider deploymentInfoProvider,
@@ -44,7 +45,7 @@ namespace Radarr.Api.V3.System
_runtimeInfo = runtimeInfo; _runtimeInfo = runtimeInfo;
_platformInfo = platformInfo; _platformInfo = platformInfo;
_osInfo = osInfo; _osInfo = osInfo;
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
_database = database; _database = database;
_lifecycleService = lifecycleService; _lifecycleService = lifecycleService;
_deploymentInfoProvider = deploymentInfoProvider; _deploymentInfoProvider = deploymentInfoProvider;
@@ -59,7 +60,7 @@ namespace Radarr.Api.V3.System
return new return new
{ {
AppName = BuildInfo.AppName, AppName = BuildInfo.AppName,
InstanceName = _configFileProvider.InstanceName, InstanceName = _configFileOptions.CurrentValue.InstanceName,
Version = BuildInfo.Version.ToString(), Version = BuildInfo.Version.ToString(),
BuildTime = BuildInfo.BuildDateTime, BuildTime = BuildInfo.BuildDateTime,
IsDebug = BuildInfo.IsDebug, IsDebug = BuildInfo.IsDebug,
@@ -76,12 +77,12 @@ namespace Radarr.Api.V3.System
IsWindows = OsInfo.IsWindows, IsWindows = OsInfo.IsWindows,
IsDocker = _osInfo.IsDocker, IsDocker = _osInfo.IsDocker,
Mode = _runtimeInfo.Mode, Mode = _runtimeInfo.Mode,
Branch = _configFileProvider.Branch, Branch = _configFileOptions.CurrentValue.Branch,
Authentication = _configFileProvider.AuthenticationMethod, Authentication = _configFileOptions.CurrentValue.AuthenticationMethod,
DatabaseType = _database.DatabaseType, DatabaseType = _database.DatabaseType,
DatabaseVersion = _database.Version, DatabaseVersion = _database.Version,
MigrationVersion = _database.Migration, MigrationVersion = _database.Migration,
UrlBase = _configFileProvider.UrlBase, UrlBase = _configFileOptions.CurrentValue.UrlBase,
RuntimeVersion = _platformInfo.Version, RuntimeVersion = _platformInfo.Version,
RuntimeName = PlatformInfo.Platform, RuntimeName = PlatformInfo.Platform,
StartTime = _runtimeInfo.StartTime, StartTime = _runtimeInfo.StartTime,

View File

@@ -28,10 +28,10 @@ namespace Radarr.Http.Authentication
ILoggerFactory logger, ILoggerFactory logger,
UrlEncoder encoder, UrlEncoder encoder,
ISystemClock clock, ISystemClock clock,
IConfigFileProvider config) IOptionsMonitor<ConfigFileOptions> config)
: base(options, logger, encoder, clock) : base(options, logger, encoder, clock)
{ {
_apiKey = config.ApiKey; _apiKey = config.CurrentValue.ApiKey;
} }
private string ParseApiKey() private string ParseApiKey()

View File

@@ -4,6 +4,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using NzbDrone.Core.Authentication; using NzbDrone.Core.Authentication;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
@@ -14,12 +15,12 @@ namespace Radarr.Http.Authentication
public class AuthenticationController : Controller public class AuthenticationController : Controller
{ {
private readonly IAuthenticationService _authService; private readonly IAuthenticationService _authService;
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
public AuthenticationController(IAuthenticationService authService, IConfigFileProvider configFileProvider) public AuthenticationController(IAuthenticationService authService, IOptionsMonitor<ConfigFileOptions> configFileOptions)
{ {
_authService = authService; _authService = authService;
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
} }
[HttpPost("login")] [HttpPost("login")]
@@ -46,7 +47,7 @@ namespace Radarr.Http.Authentication
await HttpContext.SignInAsync(AuthenticationType.Forms.ToString(), new ClaimsPrincipal(new ClaimsIdentity(claims, "Cookies", "user", "identifier")), authProperties); await HttpContext.SignInAsync(AuthenticationType.Forms.ToString(), new ClaimsPrincipal(new ClaimsIdentity(claims, "Cookies", "user", "identifier")), authProperties);
return Redirect(_configFileProvider.UrlBase + "/"); return Redirect(_configFileOptions.CurrentValue.UrlBase + "/");
} }
[HttpGet("logout")] [HttpGet("logout")]
@@ -54,7 +55,7 @@ namespace Radarr.Http.Authentication
{ {
_authService.Logout(HttpContext); _authService.Logout(HttpContext);
await HttpContext.SignOutAsync(AuthenticationType.Forms.ToString()); await HttpContext.SignOutAsync(AuthenticationType.Forms.ToString());
return Redirect(_configFileProvider.UrlBase + "/"); return Redirect(_configFileOptions.CurrentValue.UrlBase + "/");
} }
} }
} }

View File

@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using NLog; using NLog;
using NzbDrone.Core.Authentication; using NzbDrone.Core.Authentication;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
@@ -22,11 +23,11 @@ namespace Radarr.Http.Authentication
private static string API_KEY; private static string API_KEY;
private static AuthenticationType AUTH_METHOD; private static AuthenticationType AUTH_METHOD;
public AuthenticationService(IConfigFileProvider configFileProvider, IUserService userService) public AuthenticationService(IOptionsMonitor<ConfigFileOptions> configFileOptions, IUserService userService)
{ {
_userService = userService; _userService = userService;
API_KEY = configFileProvider.ApiKey; API_KEY = configFileOptions.CurrentValue.ApiKey;
AUTH_METHOD = configFileProvider.AuthenticationMethod; AUTH_METHOD = configFileOptions.CurrentValue.AuthenticationMethod;
} }
public User Login(HttpRequest request, string username, string password) public User Login(HttpRequest request, string username, string password)

View File

@@ -9,12 +9,12 @@ namespace NzbDrone.Http.Authentication
public class UiAuthorizationPolicyProvider : IAuthorizationPolicyProvider public class UiAuthorizationPolicyProvider : IAuthorizationPolicyProvider
{ {
private const string POLICY_NAME = "UI"; private const string POLICY_NAME = "UI";
private readonly IConfigFileProvider _config; private readonly IOptionsMonitor<ConfigFileOptions> _config;
public DefaultAuthorizationPolicyProvider FallbackPolicyProvider { get; } public DefaultAuthorizationPolicyProvider FallbackPolicyProvider { get; }
public UiAuthorizationPolicyProvider(IOptions<AuthorizationOptions> options, public UiAuthorizationPolicyProvider(IOptions<AuthorizationOptions> options,
IConfigFileProvider config) IOptionsMonitor<ConfigFileOptions> config)
{ {
FallbackPolicyProvider = new DefaultAuthorizationPolicyProvider(options); FallbackPolicyProvider = new DefaultAuthorizationPolicyProvider(options);
_config = config; _config = config;
@@ -28,7 +28,7 @@ namespace NzbDrone.Http.Authentication
{ {
if (policyName.Equals(POLICY_NAME, StringComparison.OrdinalIgnoreCase)) if (policyName.Equals(POLICY_NAME, StringComparison.OrdinalIgnoreCase))
{ {
var policy = new AuthorizationPolicyBuilder(_config.AuthenticationMethod.ToString()) var policy = new AuthorizationPolicyBuilder(_config.CurrentValue.AuthenticationMethod.ToString())
.RequireAuthenticatedUser(); .RequireAuthenticatedUser();
return Task.FromResult(policy.Build()); return Task.FromResult(policy.Build());
} }

View File

@@ -1,6 +1,7 @@
using System.Text; using System.Text;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using NzbDrone.Common; using NzbDrone.Common;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Core.Analytics; using NzbDrone.Core.Analytics;
@@ -12,21 +13,17 @@ namespace Radarr.Http.Frontend
[ApiController] [ApiController]
public class InitializeJsController : Controller public class InitializeJsController : Controller
{ {
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
private readonly IAnalyticsService _analyticsService; private readonly IAnalyticsService _analyticsService;
private static string _apiKey; private string ApiKey => _configFileOptions.CurrentValue.ApiKey;
private static string _urlBase; private string UrlBase => _configFileOptions.CurrentValue.UrlBase;
private string _generatedContent;
public InitializeJsController(IConfigFileProvider configFileProvider, public InitializeJsController(IOptionsMonitor<ConfigFileOptions> configFileOptions,
IAnalyticsService analyticsService) IAnalyticsService analyticsService)
{ {
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
_analyticsService = analyticsService; _analyticsService = analyticsService;
_apiKey = configFileProvider.ApiKey;
_urlBase = configFileProvider.UrlBase;
} }
[HttpGet("/initialize.js")] [HttpGet("/initialize.js")]
@@ -37,28 +34,21 @@ namespace Radarr.Http.Frontend
private string GetContent() private string GetContent()
{ {
if (RuntimeInfo.IsProduction && _generatedContent != null)
{
return _generatedContent;
}
var builder = new StringBuilder(); var builder = new StringBuilder();
builder.AppendLine("window.Radarr = {"); builder.AppendLine("window.Radarr = {");
builder.AppendLine($" apiRoot: '{_urlBase}/api/v3',"); builder.AppendLine($" apiRoot: '{UrlBase}/api/v3',");
builder.AppendLine($" apiKey: '{_apiKey}',"); builder.AppendLine($" apiKey: '{ApiKey}',");
builder.AppendLine($" release: '{BuildInfo.Release}',"); builder.AppendLine($" release: '{BuildInfo.Release}',");
builder.AppendLine($" version: '{BuildInfo.Version.ToString()}',"); builder.AppendLine($" version: '{BuildInfo.Version.ToString()}',");
builder.AppendLine($" instanceName: '{_configFileProvider.InstanceName.ToString()}',"); builder.AppendLine($" instanceName: '{_configFileOptions.CurrentValue.InstanceName}',");
builder.AppendLine($" branch: '{_configFileProvider.Branch.ToLower()}',"); builder.AppendLine($" branch: '{_configFileOptions.CurrentValue.Branch.ToLower()}',");
builder.AppendLine($" analytics: {_analyticsService.IsEnabled.ToString().ToLowerInvariant()},"); builder.AppendLine($" analytics: {_analyticsService.IsEnabled.ToString().ToLowerInvariant()},");
builder.AppendLine($" userHash: '{HashUtil.AnonymousToken()}',"); builder.AppendLine($" userHash: '{HashUtil.AnonymousToken()}',");
builder.AppendLine($" urlBase: '{_urlBase}',"); builder.AppendLine($" urlBase: '{UrlBase}',");
builder.AppendLine($" isProduction: {RuntimeInfo.IsProduction.ToString().ToLowerInvariant()}"); builder.AppendLine($" isProduction: {RuntimeInfo.IsProduction.ToString().ToLowerInvariant()}");
builder.AppendLine("};"); builder.AppendLine("};");
_generatedContent = builder.ToString(); return builder.ToString();
return _generatedContent;
} }
} }
} }

View File

@@ -1,4 +1,5 @@
using System.IO; using System.IO;
using Microsoft.Extensions.Options;
using NLog; using NLog;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
@@ -9,13 +10,13 @@ namespace Radarr.Http.Frontend.Mappers
public class BrowserConfig : StaticResourceMapperBase public class BrowserConfig : StaticResourceMapperBase
{ {
private readonly IAppFolderInfo _appFolderInfo; private readonly IAppFolderInfo _appFolderInfo;
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
public BrowserConfig(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, IConfigFileProvider configFileProvider, Logger logger) public BrowserConfig(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, IOptionsMonitor<ConfigFileOptions> configFileOptions, Logger logger)
: base(diskProvider, logger) : base(diskProvider, logger)
{ {
_appFolderInfo = appFolderInfo; _appFolderInfo = appFolderInfo;
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
} }
public override string Map(string resourceUrl) public override string Map(string resourceUrl)
@@ -23,7 +24,7 @@ namespace Radarr.Http.Frontend.Mappers
var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar); var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar);
path = path.Trim(Path.DirectorySeparatorChar); path = path.Trim(Path.DirectorySeparatorChar);
return Path.ChangeExtension(Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, path), "xml"); return Path.ChangeExtension(Path.Combine(_appFolderInfo.StartUpFolder, _uiFolder, path), "xml");
} }
public override bool CanHandle(string resourceUrl) public override bool CanHandle(string resourceUrl)

View File

@@ -1,4 +1,5 @@
using System.IO; using System.IO;
using Microsoft.Extensions.Options;
using NLog; using NLog;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
@@ -9,13 +10,13 @@ namespace Radarr.Http.Frontend.Mappers
public class FaviconMapper : StaticResourceMapperBase public class FaviconMapper : StaticResourceMapperBase
{ {
private readonly IAppFolderInfo _appFolderInfo; private readonly IAppFolderInfo _appFolderInfo;
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
public FaviconMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, IConfigFileProvider configFileProvider, Logger logger) public FaviconMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, IOptionsMonitor<ConfigFileOptions> configFileOptions, Logger logger)
: base(diskProvider, logger) : base(diskProvider, logger)
{ {
_appFolderInfo = appFolderInfo; _appFolderInfo = appFolderInfo;
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
} }
public override string Map(string resourceUrl) public override string Map(string resourceUrl)
@@ -29,7 +30,7 @@ namespace Radarr.Http.Frontend.Mappers
var path = Path.Combine("Content", "Images", "Icons", fileName); var path = Path.Combine("Content", "Images", "Icons", fileName);
return Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, path); return Path.Combine(_appFolderInfo.StartUpFolder, _uiFolder, path);
} }
public override bool CanHandle(string resourceUrl) public override bool CanHandle(string resourceUrl)

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.IO; using System.IO;
using Microsoft.Extensions.Options;
using NLog; using NLog;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
@@ -9,19 +10,19 @@ namespace Radarr.Http.Frontend.Mappers
{ {
public class IndexHtmlMapper : HtmlMapperBase public class IndexHtmlMapper : HtmlMapperBase
{ {
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
public IndexHtmlMapper(IAppFolderInfo appFolderInfo, public IndexHtmlMapper(IAppFolderInfo appFolderInfo,
IDiskProvider diskProvider, IDiskProvider diskProvider,
IConfigFileProvider configFileProvider, IOptionsMonitor<ConfigFileOptions> configFileOptions,
Lazy<ICacheBreakerProvider> cacheBreakProviderFactory, Lazy<ICacheBreakerProvider> cacheBreakProviderFactory,
Logger logger) Logger logger)
: base(diskProvider, cacheBreakProviderFactory, logger) : base(diskProvider, cacheBreakProviderFactory, logger)
{ {
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
HtmlPath = Path.Combine(appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, "index.html"); HtmlPath = Path.Combine(appFolderInfo.StartUpFolder, _uiFolder, "index.html");
UrlBase = configFileProvider.UrlBase; UrlBase = configFileOptions.CurrentValue.UrlBase;
} }
public override string Map(string resourceUrl) public override string Map(string resourceUrl)

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.IO; using System.IO;
using Microsoft.Extensions.Options;
using NLog; using NLog;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
@@ -12,12 +13,12 @@ namespace Radarr.Http.Frontend.Mappers
public LoginHtmlMapper(IAppFolderInfo appFolderInfo, public LoginHtmlMapper(IAppFolderInfo appFolderInfo,
IDiskProvider diskProvider, IDiskProvider diskProvider,
Lazy<ICacheBreakerProvider> cacheBreakProviderFactory, Lazy<ICacheBreakerProvider> cacheBreakProviderFactory,
IConfigFileProvider configFileProvider, IOptionsMonitor<ConfigFileOptions> configFileOptions,
Logger logger) Logger logger)
: base(diskProvider, cacheBreakProviderFactory, logger) : base(diskProvider, cacheBreakProviderFactory, logger)
{ {
HtmlPath = Path.Combine(appFolderInfo.StartUpFolder, configFileProvider.UiFolder, "login.html"); HtmlPath = Path.Combine(appFolderInfo.StartUpFolder, _uiFolder, "login.html");
UrlBase = configFileProvider.UrlBase; UrlBase = configFileOptions.CurrentValue.UrlBase;
} }
public override string Map(string resourceUrl) public override string Map(string resourceUrl)

View File

@@ -1,4 +1,5 @@
using System.IO; using System.IO;
using Microsoft.Extensions.Options;
using NLog; using NLog;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
@@ -9,13 +10,13 @@ namespace Radarr.Http.Frontend.Mappers
public class ManifestMapper : StaticResourceMapperBase public class ManifestMapper : StaticResourceMapperBase
{ {
private readonly IAppFolderInfo _appFolderInfo; private readonly IAppFolderInfo _appFolderInfo;
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
public ManifestMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, IConfigFileProvider configFileProvider, Logger logger) public ManifestMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, IOptionsMonitor<ConfigFileOptions> configFileOptions, Logger logger)
: base(diskProvider, logger) : base(diskProvider, logger)
{ {
_appFolderInfo = appFolderInfo; _appFolderInfo = appFolderInfo;
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
} }
public override string Map(string resourceUrl) public override string Map(string resourceUrl)
@@ -23,7 +24,7 @@ namespace Radarr.Http.Frontend.Mappers
var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar); var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar);
path = path.Trim(Path.DirectorySeparatorChar); path = path.Trim(Path.DirectorySeparatorChar);
return Path.ChangeExtension(Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, path), "json"); return Path.ChangeExtension(Path.Combine(_appFolderInfo.StartUpFolder, _uiFolder, path), "json");
} }
public override bool CanHandle(string resourceUrl) public override bool CanHandle(string resourceUrl)

View File

@@ -1,4 +1,5 @@
using System.IO; using System.IO;
using Microsoft.Extensions.Options;
using NLog; using NLog;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
@@ -9,20 +10,20 @@ namespace Radarr.Http.Frontend.Mappers
public class RobotsTxtMapper : StaticResourceMapperBase public class RobotsTxtMapper : StaticResourceMapperBase
{ {
private readonly IAppFolderInfo _appFolderInfo; private readonly IAppFolderInfo _appFolderInfo;
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
public RobotsTxtMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, IConfigFileProvider configFileProvider, Logger logger) public RobotsTxtMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, IOptionsMonitor<ConfigFileOptions> configFileOptions, Logger logger)
: base(diskProvider, logger) : base(diskProvider, logger)
{ {
_appFolderInfo = appFolderInfo; _appFolderInfo = appFolderInfo;
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
} }
public override string Map(string resourceUrl) public override string Map(string resourceUrl)
{ {
var path = Path.Combine("Content", "robots.txt"); var path = Path.Combine("Content", "robots.txt");
return Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, path); return Path.Combine(_appFolderInfo.StartUpFolder, _uiFolder, path);
} }
public override bool CanHandle(string resourceUrl) public override bool CanHandle(string resourceUrl)

View File

@@ -1,4 +1,5 @@
using System.IO; using System.IO;
using Microsoft.Extensions.Options;
using NLog; using NLog;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
@@ -9,13 +10,13 @@ namespace Radarr.Http.Frontend.Mappers
public class StaticResourceMapper : StaticResourceMapperBase public class StaticResourceMapper : StaticResourceMapperBase
{ {
private readonly IAppFolderInfo _appFolderInfo; private readonly IAppFolderInfo _appFolderInfo;
private readonly IConfigFileProvider _configFileProvider; private readonly IOptionsMonitor<ConfigFileOptions> _configFileOptions;
public StaticResourceMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, IConfigFileProvider configFileProvider, Logger logger) public StaticResourceMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, IOptionsMonitor<ConfigFileOptions> configFileOptions, Logger logger)
: base(diskProvider, logger) : base(diskProvider, logger)
{ {
_appFolderInfo = appFolderInfo; _appFolderInfo = appFolderInfo;
_configFileProvider = configFileProvider; _configFileOptions = configFileOptions;
} }
public override string Map(string resourceUrl) public override string Map(string resourceUrl)
@@ -23,7 +24,7 @@ namespace Radarr.Http.Frontend.Mappers
var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar); var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar);
path = path.Trim(Path.DirectorySeparatorChar); path = path.Trim(Path.DirectorySeparatorChar);
return Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, path); return Path.Combine(_appFolderInfo.StartUpFolder, _uiFolder, path);
} }
public override bool CanHandle(string resourceUrl) public override bool CanHandle(string resourceUrl)

View File

@@ -10,6 +10,8 @@ namespace Radarr.Http.Frontend.Mappers
{ {
public abstract class StaticResourceMapperBase : IMapHttpRequestsToDisk public abstract class StaticResourceMapperBase : IMapHttpRequestsToDisk
{ {
protected readonly string _uiFolder;
private readonly IDiskProvider _diskProvider; private readonly IDiskProvider _diskProvider;
private readonly Logger _logger; private readonly Logger _logger;
private readonly StringComparison _caseSensitive; private readonly StringComparison _caseSensitive;
@@ -22,6 +24,7 @@ namespace Radarr.Http.Frontend.Mappers
_mimeTypeProvider = new FileExtensionContentTypeProvider(); _mimeTypeProvider = new FileExtensionContentTypeProvider();
_caseSensitive = RuntimeInfo.IsProduction ? DiskProviderBase.PathStringComparison : StringComparison.OrdinalIgnoreCase; _caseSensitive = RuntimeInfo.IsProduction ? DiskProviderBase.PathStringComparison : StringComparison.OrdinalIgnoreCase;
_uiFolder = BuildInfo.IsDebug ? Path.Combine("..", "UI") : "UI";
} }
public abstract string Map(string resourceUrl); public abstract string Map(string resourceUrl);

View File

@@ -2,10 +2,10 @@
<RunSettings> <RunSettings>
<RunConfiguration> <RunConfiguration>
<EnvironmentVariables> <EnvironmentVariables>
<Radarr__Postgres__Host>192.168.100.5</Radarr__Postgres__Host> <Radarr__PostgresHost>192.168.100.5</Radarr__PostgresHost>
<Radarr__Postgres__Port>5432</Radarr__Postgres__Port> <Radarr__PostgresPort>5432</Radarr__PostgresPort>
<Radarr__Postgres__User>abc</Radarr__Postgres__User> <Radarr__PostgresUser>abc</Radarr__PostgresUser>
<Radarr__Postgres__Password>abc</Radarr__Postgres__Password> <Radarr__PostgresPassword>abc</Radarr__PostgresPassword>
</EnvironmentVariables> </EnvironmentVariables>
</RunConfiguration> </RunConfiguration>
</RunSettings> </RunSettings>