From ad7d571b24f05866961eece1d0d80582f0c0d57a Mon Sep 17 00:00:00 2001 From: Keivan Beigi Date: Tue, 3 Jan 2017 18:36:47 -0800 Subject: [PATCH] New: Better platform detection specifically for Non-Windows Systems --- .../Frontend/CacheableSpecification.cs | 2 +- .../Frontend/Mappers/IndexHtmlMapper.cs | 4 +- .../Frontend/Mappers/LoginHtmlMapper.cs | 2 +- .../Mappers/StaticResourceMapperBase.cs | 2 +- src/NzbDrone.Api/NancyBootstrapper.cs | 4 +- src/NzbDrone.Api/Series/SeriesModule.cs | 2 +- src/NzbDrone.Api/System/SystemModule.cs | 53 ++++--- .../EnvironmentProviderTest.cs | 2 +- .../Http/HttpClientFixture.cs | 55 ++++--- .../Cloud/SonarrCloudRequestBuilder.cs | 4 +- src/NzbDrone.Common/Disk/DiskProviderBase.cs | 15 +- .../EnsureThat/EnsureStringExtensions.cs | 8 +- .../EnvironmentInfo/AppFolderInfo.cs | 6 +- .../IOperatingSystemVersionInfo.cs | 9 ++ .../EnvironmentInfo/IOsVersionAdapter.cs | 9 ++ .../EnvironmentInfo/IPlatformInfo.cs | 37 +++++ .../EnvironmentInfo/IRuntimeInfo.cs | 8 +- src/NzbDrone.Common/EnvironmentInfo/OsInfo.cs | 144 +++++++++--------- .../EnvironmentInfo/OsVersionModel.cs | 29 ++++ .../{RuntimeInfoBase.cs => RuntimeInfo.cs} | 50 +++--- .../Exceptron/ExceptionExtentions.cs | 31 ---- .../Extensions/PathExtensions.cs | 5 +- .../Http/Dispatchers/CurlHttpDispatcher.cs | 8 +- .../Dispatchers/FallbackHttpDispatcher.cs | 6 +- .../Http/Dispatchers/ManagedHttpDispatcher.cs | 6 +- src/NzbDrone.Common/Http/HttpClient.cs | 13 +- src/NzbDrone.Common/Http/HttpRequest.cs | 2 +- src/NzbDrone.Common/Http/UserAgentBuilder.cs | 32 ++-- .../Instrumentation/ExceptronTarget.cs | 89 ----------- .../GlobalExceptionHandlers.cs | 2 +- .../Instrumentation/NzbDroneLogger.cs | 12 +- src/NzbDrone.Common/NzbDrone.Common.csproj | 7 +- .../Processes/ProcessProvider.cs | 4 +- src/NzbDrone.Core.Test/Framework/CoreTest.cs | 14 +- .../Checks/MonoVersionCheckFixture.cs | 17 +-- .../UpdatePackageProviderFixture.cs | 7 + .../Analytics/AnalyticsService.cs | 2 +- .../Configuration/ConfigService.cs | 3 +- .../HealthCheck/Checks/MonoVersionCheck.cs | 55 +++---- .../Lifecycle/ApplicationShutdownRequested.cs | 8 +- .../MediaFiles/UpdateEpisodeFileService.cs | 1 - src/NzbDrone.Core/Rest/RestClientFactory.cs | 9 +- .../Update/UpdateCheckService.cs | 9 +- .../Update/UpdatePackageProvider.cs | 6 +- .../AccessControl/UrlAclAdapter.cs | 10 +- src/NzbDrone.Host/ApplicationServer.cs | 4 +- src/NzbDrone.Host/SpinService.cs | 3 +- .../IntegrationTest.cs | 2 +- .../MonoPlatformInfoFixture.cs | 20 +++ .../ReleaseFileVersionAdapterFixture.cs | 29 ++++ .../MacOsVersionAdapterFixture.cs | 77 ++++++++++ .../ReleaseFileVersionAdapterFixture.cs | 82 ++++++++++ .../Files/linux/lsb-release | 4 + src/NzbDrone.Mono.Test/Files/linux/os-release | 9 ++ .../Files/macOS/SystemVersion.plist | 16 ++ src/NzbDrone.Mono.Test/Files/synology/VERSION | 8 + .../NzbDrone.Mono.Test.csproj | 20 +++ .../EnvironmentInfo/MonoPlatformInfo.cs | 46 ++++++ .../EnvironmentInfo/MonoRuntimeProvider.cs | 45 ------ .../IssueFileVersionAdapter.cs | 52 +++++++ .../VersionAdapters/MacOsVersionAdapter.cs | 69 +++++++++ .../ReleaseFileVersionAdapter.cs | 79 ++++++++++ .../VersionAdapters/SynologyVersionAdapter.cs | 78 ++++++++++ src/NzbDrone.Mono/NzbDrone.Mono.csproj | 6 +- src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs | 4 +- src/NzbDrone.Test.Common/TestBase.cs | 2 +- .../UpdateEngine/DetectApplicationType.cs | 2 +- .../DotNetPlatformInfoFixture.cs | 19 +++ .../WindowsVersionInfoFixture.cs | 23 +++ .../NzbDrone.Windows.Test.csproj | 2 + .../EnvironmentInfo/DotNetPlatformInfo.cs | 57 +++++++ .../EnvironmentInfo/DotNetRuntimeProvider.cs | 16 -- .../EnvironmentInfo/WindowsVersionInfo.cs | 14 ++ src/NzbDrone.Windows/NzbDrone.Windows.csproj | 3 +- src/NzbDrone.sln | 2 +- src/NzbDrone.sln.DotSettings | 2 + 76 files changed, 1125 insertions(+), 473 deletions(-) create mode 100644 src/NzbDrone.Common/EnvironmentInfo/IOperatingSystemVersionInfo.cs create mode 100644 src/NzbDrone.Common/EnvironmentInfo/IOsVersionAdapter.cs create mode 100644 src/NzbDrone.Common/EnvironmentInfo/IPlatformInfo.cs create mode 100644 src/NzbDrone.Common/EnvironmentInfo/OsVersionModel.cs rename src/NzbDrone.Common/EnvironmentInfo/{RuntimeInfoBase.cs => RuntimeInfo.cs} (70%) delete mode 100644 src/NzbDrone.Common/Exceptron/ExceptionExtentions.cs delete mode 100644 src/NzbDrone.Common/Instrumentation/ExceptronTarget.cs create mode 100644 src/NzbDrone.Mono.Test/EnvironmentInfo/MonoPlatformInfoFixture.cs create mode 100644 src/NzbDrone.Mono.Test/EnvironmentInfo/ReleaseFileVersionAdapterFixture.cs create mode 100644 src/NzbDrone.Mono.Test/EnvironmentInfo/VersionAdapters/MacOsVersionAdapterFixture.cs create mode 100644 src/NzbDrone.Mono.Test/EnvironmentInfo/VersionAdapters/ReleaseFileVersionAdapterFixture.cs create mode 100644 src/NzbDrone.Mono.Test/Files/linux/lsb-release create mode 100644 src/NzbDrone.Mono.Test/Files/linux/os-release create mode 100644 src/NzbDrone.Mono.Test/Files/macOS/SystemVersion.plist create mode 100644 src/NzbDrone.Mono.Test/Files/synology/VERSION create mode 100644 src/NzbDrone.Mono/EnvironmentInfo/MonoPlatformInfo.cs delete mode 100644 src/NzbDrone.Mono/EnvironmentInfo/MonoRuntimeProvider.cs create mode 100644 src/NzbDrone.Mono/EnvironmentInfo/VersionAdapters/IssueFileVersionAdapter.cs create mode 100644 src/NzbDrone.Mono/EnvironmentInfo/VersionAdapters/MacOsVersionAdapter.cs create mode 100644 src/NzbDrone.Mono/EnvironmentInfo/VersionAdapters/ReleaseFileVersionAdapter.cs create mode 100644 src/NzbDrone.Mono/EnvironmentInfo/VersionAdapters/SynologyVersionAdapter.cs create mode 100644 src/NzbDrone.Windows.Test/EnvironmentInfo/DotNetPlatformInfoFixture.cs create mode 100644 src/NzbDrone.Windows.Test/EnvironmentInfo/WindowsVersionInfoFixture.cs create mode 100644 src/NzbDrone.Windows/EnvironmentInfo/DotNetPlatformInfo.cs delete mode 100644 src/NzbDrone.Windows/EnvironmentInfo/DotNetRuntimeProvider.cs create mode 100644 src/NzbDrone.Windows/EnvironmentInfo/WindowsVersionInfo.cs diff --git a/src/NzbDrone.Api/Frontend/CacheableSpecification.cs b/src/NzbDrone.Api/Frontend/CacheableSpecification.cs index b427658e9..7995c7da1 100644 --- a/src/NzbDrone.Api/Frontend/CacheableSpecification.cs +++ b/src/NzbDrone.Api/Frontend/CacheableSpecification.cs @@ -14,7 +14,7 @@ namespace NzbDrone.Api.Frontend { public bool IsCacheable(NancyContext context) { - if (!RuntimeInfoBase.IsProduction) + if (!RuntimeInfo.IsProduction) { return false; } diff --git a/src/NzbDrone.Api/Frontend/Mappers/IndexHtmlMapper.cs b/src/NzbDrone.Api/Frontend/Mappers/IndexHtmlMapper.cs index 45d4a89bc..ae66b2aa2 100644 --- a/src/NzbDrone.Api/Frontend/Mappers/IndexHtmlMapper.cs +++ b/src/NzbDrone.Api/Frontend/Mappers/IndexHtmlMapper.cs @@ -74,7 +74,7 @@ namespace NzbDrone.Api.Frontend.Mappers private string GetIndexText() { - if (RuntimeInfoBase.IsProduction && _generatedContent != null) + if (RuntimeInfo.IsProduction && _generatedContent != null) { return _generatedContent; } @@ -106,7 +106,7 @@ namespace NzbDrone.Api.Frontend.Mappers text = text.Replace("APP_BRANCH", _configFileProvider.Branch.ToLower()); text = text.Replace("APP_ANALYTICS", _analyticsService.IsEnabled.ToString().ToLowerInvariant()); text = text.Replace("URL_BASE", URL_BASE); - text = text.Replace("PRODUCTION", RuntimeInfoBase.IsProduction.ToString().ToLowerInvariant()); + text = text.Replace("PRODUCTION", RuntimeInfo.IsProduction.ToString().ToLowerInvariant()); _generatedContent = text; diff --git a/src/NzbDrone.Api/Frontend/Mappers/LoginHtmlMapper.cs b/src/NzbDrone.Api/Frontend/Mappers/LoginHtmlMapper.cs index 523e7cbe2..974e117f9 100644 --- a/src/NzbDrone.Api/Frontend/Mappers/LoginHtmlMapper.cs +++ b/src/NzbDrone.Api/Frontend/Mappers/LoginHtmlMapper.cs @@ -67,7 +67,7 @@ namespace NzbDrone.Api.Frontend.Mappers private string GetLoginText() { - if (RuntimeInfoBase.IsProduction && _generatedContent != null) + if (RuntimeInfo.IsProduction && _generatedContent != null) { return _generatedContent; } diff --git a/src/NzbDrone.Api/Frontend/Mappers/StaticResourceMapperBase.cs b/src/NzbDrone.Api/Frontend/Mappers/StaticResourceMapperBase.cs index c3c069ea3..489d039d0 100644 --- a/src/NzbDrone.Api/Frontend/Mappers/StaticResourceMapperBase.cs +++ b/src/NzbDrone.Api/Frontend/Mappers/StaticResourceMapperBase.cs @@ -21,7 +21,7 @@ namespace NzbDrone.Api.Frontend.Mappers _diskProvider = diskProvider; _logger = logger; - if (!RuntimeInfoBase.IsProduction) + if (!RuntimeInfo.IsProduction) { _caseSensitive = StringComparison.OrdinalIgnoreCase; } diff --git a/src/NzbDrone.Api/NancyBootstrapper.cs b/src/NzbDrone.Api/NancyBootstrapper.cs index 695967025..1415dd4c2 100644 --- a/src/NzbDrone.Api/NancyBootstrapper.cs +++ b/src/NzbDrone.Api/NancyBootstrapper.cs @@ -24,9 +24,9 @@ namespace NzbDrone.Api protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines) { - Logger.Info("Starting NzbDrone API"); + Logger.Info("Starting Web Server"); - if (RuntimeInfoBase.IsProduction) + if (RuntimeInfo.IsProduction) { DiagnosticsHook.Disable(pipelines); } diff --git a/src/NzbDrone.Api/Series/SeriesModule.cs b/src/NzbDrone.Api/Series/SeriesModule.cs index 239598912..274a57bbd 100644 --- a/src/NzbDrone.Api/Series/SeriesModule.cs +++ b/src/NzbDrone.Api/Series/SeriesModule.cs @@ -180,7 +180,7 @@ namespace NzbDrone.Api.Series foreach (var season in resource.Seasons) { - season.Statistics = SeasonStatisticsResourceMapper.ToResource(dictSeasonStats.GetValueOrDefault(season.SeasonNumber)); + season.Statistics = dictSeasonStats.GetValueOrDefault(season.SeasonNumber).ToResource(); } } } diff --git a/src/NzbDrone.Api/System/SystemModule.cs b/src/NzbDrone.Api/System/SystemModule.cs index 2ec787115..c62ed3b9e 100644 --- a/src/NzbDrone.Api/System/SystemModule.cs +++ b/src/NzbDrone.Api/System/SystemModule.cs @@ -13,6 +13,8 @@ namespace NzbDrone.Api.System { private readonly IAppFolderInfo _appFolderInfo; private readonly IRuntimeInfo _runtimeInfo; + private readonly IPlatformInfo _platformInfo; + private readonly IOsInfo _osInfo; private readonly IRouteCacheProvider _routeCacheProvider; private readonly IConfigFileProvider _configFileProvider; private readonly IMainDatabase _database; @@ -20,14 +22,17 @@ namespace NzbDrone.Api.System public SystemModule(IAppFolderInfo appFolderInfo, IRuntimeInfo runtimeInfo, + IPlatformInfo platformInfo, + IOsInfo osInfo, IRouteCacheProvider routeCacheProvider, IConfigFileProvider configFileProvider, IMainDatabase database, - ILifecycleService lifecycleService) - : base("system") + ILifecycleService lifecycleService) : base("system") { _appFolderInfo = appFolderInfo; _runtimeInfo = runtimeInfo; + _platformInfo = platformInfo; + _osInfo = osInfo; _routeCacheProvider = routeCacheProvider; _configFileProvider = configFileProvider; _database = database; @@ -41,27 +46,29 @@ namespace NzbDrone.Api.System private Response GetStatus() { return new - { - Version = BuildInfo.Version.ToString(), - BuildTime = BuildInfo.BuildDateTime, - IsDebug = BuildInfo.IsDebug, - IsProduction = RuntimeInfoBase.IsProduction, - IsAdmin = _runtimeInfo.IsAdmin, - IsUserInteractive = RuntimeInfoBase.IsUserInteractive, - StartupPath = _appFolderInfo.StartUpFolder, - AppData = _appFolderInfo.GetAppDataPath(), - OsVersion = OsInfo.Version.ToString(), - IsMonoRuntime = OsInfo.IsMonoRuntime, - IsMono = OsInfo.IsNotWindows, - IsLinux = OsInfo.IsLinux, - IsOsx = OsInfo.IsOsx, - IsWindows = OsInfo.IsWindows, - Branch = _configFileProvider.Branch, - Authentication = _configFileProvider.AuthenticationMethod, - SqliteVersion = _database.Version, - UrlBase = _configFileProvider.UrlBase, - RuntimeVersion = _runtimeInfo.RuntimeVersion - }.AsResponse(); + { + Version = BuildInfo.Version.ToString(), + BuildTime = BuildInfo.BuildDateTime, + IsDebug = BuildInfo.IsDebug, + IsProduction = RuntimeInfo.IsProduction, + IsAdmin = _runtimeInfo.IsAdmin, + IsUserInteractive = RuntimeInfo.IsUserInteractive, + StartupPath = _appFolderInfo.StartUpFolder, + AppData = _appFolderInfo.GetAppDataPath(), + OsName = _osInfo.Name, + OsVersion = _osInfo.Version, + IsMonoRuntime = PlatformInfo.IsMono, + IsMono = PlatformInfo.IsMono, + IsLinux = OsInfo.IsLinux, + IsOsx = OsInfo.IsOsx, + IsWindows = OsInfo.IsWindows, + Branch = _configFileProvider.Branch, + Authentication = _configFileProvider.AuthenticationMethod, + SqliteVersion = _database.Version, + UrlBase = _configFileProvider.UrlBase, + RuntimeVersion = _platformInfo.Version, + RuntimeName = PlatformInfo.Platform + }.AsResponse(); } private Response GetRoutes() diff --git a/src/NzbDrone.Common.Test/EnvironmentProviderTest.cs b/src/NzbDrone.Common.Test/EnvironmentProviderTest.cs index 362a09376..dd7e8fcf0 100644 --- a/src/NzbDrone.Common.Test/EnvironmentProviderTest.cs +++ b/src/NzbDrone.Common.Test/EnvironmentProviderTest.cs @@ -29,7 +29,7 @@ namespace NzbDrone.Common.Test [Test] public void IsProduction_should_return_false_when_run_within_nunit() { - RuntimeInfoBase.IsProduction.Should().BeFalse("Process name is " + Process.GetCurrentProcess().ProcessName + " Folder is " + Directory.GetCurrentDirectory()); + RuntimeInfo.IsProduction.Should().BeFalse("Process name is " + Process.GetCurrentProcess().ProcessName + " Folder is " + Directory.GetCurrentDirectory()); } [Test] diff --git a/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs b/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs index b9c3c236f..23d65c322 100644 --- a/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs +++ b/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs @@ -9,6 +9,7 @@ using Moq; using NLog; using NUnit.Framework; using NzbDrone.Common.Cache; +using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Http; using NzbDrone.Common.Http.Dispatchers; using NzbDrone.Common.Http.Proxy; @@ -30,6 +31,12 @@ namespace NzbDrone.Common.Test.Http [SetUp] public void SetUp() { + Mocker.GetMock().Setup(c => c.Version).Returns(new Version("1.0.0")); + Mocker.GetMock().Setup(c => c.Name).Returns("TestOS"); + Mocker.GetMock().Setup(c => c.Version).Returns("9.0.0"); + + Mocker.SetConstant(Mocker.Resolve()); + Mocker.SetConstant(Mocker.Resolve()); Mocker.SetConstant(Mocker.Resolve()); Mocker.SetConstant(Mocker.Resolve()); @@ -48,7 +55,7 @@ namespace NzbDrone.Common.Test.Http [Test] public void should_execute_simple_get() { - var request = new HttpRequest(string.Format("http://{0}/get", _httpBinHost)); + var request = new HttpRequest($"http://{_httpBinHost}/get"); var response = Subject.Execute(request); @@ -58,7 +65,7 @@ namespace NzbDrone.Common.Test.Http [Test] public void should_execute_https_get() { - var request = new HttpRequest(string.Format("https://{0}/get", _httpBinHost)); + var request = new HttpRequest($"https://{_httpBinHost}/get"); var response = Subject.Execute(request); @@ -68,7 +75,7 @@ namespace NzbDrone.Common.Test.Http [Test] public void should_execute_typed_get() { - var request = new HttpRequest(string.Format("http://{0}/get", _httpBinHost)); + var request = new HttpRequest($"http://{_httpBinHost}/get"); var response = Subject.Get(request); @@ -80,7 +87,7 @@ namespace NzbDrone.Common.Test.Http { var message = "{ my: 1 }"; - var request = new HttpRequest(string.Format("http://{0}/post", _httpBinHost)); + var request = new HttpRequest($"http://{_httpBinHost}/post"); request.SetContent(message); var response = Subject.Post(request); @@ -91,7 +98,7 @@ namespace NzbDrone.Common.Test.Http [TestCase("gzip")] public void should_execute_get_using_gzip(string compression) { - var request = new HttpRequest(string.Format("http://{0}/{1}", _httpBinHost, compression)); + var request = new HttpRequest($"http://{_httpBinHost}/{compression}"); var response = Subject.Get(request); @@ -107,7 +114,7 @@ namespace NzbDrone.Common.Test.Http [TestCase(HttpStatusCode.BadGateway)] public void should_throw_on_unsuccessful_status_codes(int statusCode) { - var request = new HttpRequest(string.Format("http://{0}/status/{1}", _httpBinHost, statusCode)); + var request = new HttpRequest($"http://{_httpBinHost}/status/{statusCode}"); var exception = Assert.Throws(() => Subject.Get(request)); @@ -119,7 +126,7 @@ namespace NzbDrone.Common.Test.Http [Test] public void should_not_follow_redirects_when_not_in_production() { - var request = new HttpRequest(string.Format("http://{0}/redirect/1", _httpBinHost)); + var request = new HttpRequest($"http://{_httpBinHost}/redirect/1"); Subject.Get(request); @@ -129,7 +136,7 @@ namespace NzbDrone.Common.Test.Http [Test] public void should_follow_redirects() { - var request = new HttpRequest(string.Format("http://{0}/redirect/1", _httpBinHost)); + var request = new HttpRequest($"http://{_httpBinHost}/redirect/1"); request.AllowAutoRedirect = true; Subject.Get(request); @@ -140,7 +147,7 @@ namespace NzbDrone.Common.Test.Http [Test] public void should_send_user_agent() { - var request = new HttpRequest(string.Format("http://{0}/get", _httpBinHost)); + var request = new HttpRequest($"http://{_httpBinHost}/get"); var response = Subject.Get(request); @@ -154,7 +161,7 @@ namespace NzbDrone.Common.Test.Http [TestCase("Accept", "text/xml, text/rss+xml, application/rss+xml")] public void should_send_headers(string header, string value) { - var request = new HttpRequest(string.Format("http://{0}/get", _httpBinHost)); + var request = new HttpRequest($"http://{_httpBinHost}/get"); request.Headers.Add(header, value); var response = Subject.Get(request); @@ -177,7 +184,7 @@ namespace NzbDrone.Common.Test.Http [Test] public void should_send_cookie() { - var request = new HttpRequest(string.Format("http://{0}/get", _httpBinHost)); + var request = new HttpRequest($"http://{_httpBinHost}/get"); request.Cookies["my"] = "cookie"; var response = Subject.Get(request); @@ -194,7 +201,7 @@ namespace NzbDrone.Common.Test.Http var oldRequest = new HttpRequest("http://eu.httpbin.org/get"); oldRequest.Cookies["my"] = "cookie"; - var oldClient = new HttpClient(new IHttpRequestInterceptor[0], Mocker.Resolve(), Mocker.Resolve(), Mocker.Resolve(), Mocker.Resolve()); + var oldClient = new HttpClient(new IHttpRequestInterceptor[0], Mocker.Resolve(), Mocker.Resolve(), Mocker.Resolve(), Mocker.GetMock().Object, Mocker.Resolve()); oldClient.Should().NotBeSameAs(Subject); @@ -234,12 +241,12 @@ namespace NzbDrone.Common.Test.Http [Test] public void should_not_store_response_cookie() { - var requestSet = new HttpRequest(string.Format("http://{0}/cookies/set?my=cookie", _httpBinHost)); + var requestSet = new HttpRequest($"http://{_httpBinHost}/cookies/set?my=cookie"); requestSet.AllowAutoRedirect = false; var responseSet = Subject.Get(requestSet); - var request = new HttpRequest(string.Format("http://{0}/get", _httpBinHost)); + var request = new HttpRequest($"http://{_httpBinHost}/get"); var response = Subject.Get(request); @@ -251,13 +258,13 @@ namespace NzbDrone.Common.Test.Http [Test] public void should_store_response_cookie() { - var requestSet = new HttpRequest(string.Format("http://{0}/cookies/set?my=cookie", _httpBinHost)); + var requestSet = new HttpRequest($"http://{_httpBinHost}/cookies/set?my=cookie"); requestSet.AllowAutoRedirect = false; requestSet.StoreResponseCookie = true; var responseSet = Subject.Get(requestSet); - var request = new HttpRequest(string.Format("http://{0}/get", _httpBinHost)); + var request = new HttpRequest($"http://{_httpBinHost}/get"); var response = Subject.Get(request); @@ -273,14 +280,14 @@ namespace NzbDrone.Common.Test.Http [Test] public void should_overwrite_response_cookie() { - var requestSet = new HttpRequest(string.Format("http://{0}/cookies/set?my=cookie", _httpBinHost)); + var requestSet = new HttpRequest($"http://{_httpBinHost}/cookies/set?my=cookie"); requestSet.AllowAutoRedirect = false; requestSet.StoreResponseCookie = true; requestSet.Cookies["my"] = "oldcookie"; var responseSet = Subject.Get(requestSet); - var request = new HttpRequest(string.Format("http://{0}/get", _httpBinHost)); + var request = new HttpRequest($"http://{_httpBinHost}/get"); var response = Subject.Get(request); @@ -296,7 +303,7 @@ namespace NzbDrone.Common.Test.Http [Test] public void should_throw_on_http429_too_many_requests() { - var request = new HttpRequest(string.Format("http://{0}/status/429", _httpBinHost)); + var request = new HttpRequest($"http://{_httpBinHost}/status/429"); Assert.Throws(() => Subject.Get(request)); @@ -316,7 +323,7 @@ namespace NzbDrone.Common.Test.Http .Setup(v => v.PostResponse(It.IsAny())) .Returns(r => r); - var request = new HttpRequest(string.Format("http://{0}/get", _httpBinHost)); + var request = new HttpRequest($"http://{_httpBinHost}/get"); Subject.Get(request); @@ -338,7 +345,7 @@ namespace NzbDrone.Common.Test.Http { // the date is bad in the below - should be 13-Jul-2026 string malformedCookie = @"__cfduid=d29e686a9d65800021c66faca0a29b4261436890790; expires=Mon, 13-Jul-26 16:19:50 GMT; path=/; HttpOnly"; - var requestSet = new HttpRequestBuilder(string.Format("http://{0}/response-headers", _httpBinHost)) + var requestSet = new HttpRequestBuilder($"http://{_httpBinHost}/response-headers") .AddQueryParam("Set-Cookie", malformedCookie) .Build(); @@ -347,7 +354,7 @@ namespace NzbDrone.Common.Test.Http var responseSet = Subject.Get(requestSet); - var request = new HttpRequest(string.Format("http://{0}/get", _httpBinHost)); + var request = new HttpRequest($"http://{_httpBinHost}/get"); var response = Subject.Get(request); @@ -371,7 +378,7 @@ namespace NzbDrone.Common.Test.Http { try { - string url = string.Format("http://{0}/response-headers?Set-Cookie={1}", _httpBinHost, Uri.EscapeUriString(malformedCookie)); + string url = $"http://{_httpBinHost}/response-headers?Set-Cookie={Uri.EscapeUriString(malformedCookie)}"; var requestSet = new HttpRequest(url); requestSet.AllowAutoRedirect = false; @@ -379,7 +386,7 @@ namespace NzbDrone.Common.Test.Http var responseSet = Subject.Get(requestSet); - var request = new HttpRequest(string.Format("http://{0}/get", _httpBinHost)); + var request = new HttpRequest($"http://{_httpBinHost}/get"); var response = Subject.Get(request); diff --git a/src/NzbDrone.Common/Cloud/SonarrCloudRequestBuilder.cs b/src/NzbDrone.Common/Cloud/SonarrCloudRequestBuilder.cs index 5c3712d85..ed00104a8 100644 --- a/src/NzbDrone.Common/Cloud/SonarrCloudRequestBuilder.cs +++ b/src/NzbDrone.Common/Cloud/SonarrCloudRequestBuilder.cs @@ -20,8 +20,8 @@ namespace NzbDrone.Common.Cloud .CreateFactory(); } - public IHttpRequestBuilderFactory Services { get; private set; } + public IHttpRequestBuilderFactory Services { get; } - public IHttpRequestBuilderFactory SkyHookTvdb { get; private set; } + public IHttpRequestBuilderFactory SkyHookTvdb { get; } } } diff --git a/src/NzbDrone.Common/Disk/DiskProviderBase.cs b/src/NzbDrone.Common/Disk/DiskProviderBase.cs index 9fbb3ff48..41de39866 100644 --- a/src/NzbDrone.Common/Disk/DiskProviderBase.cs +++ b/src/NzbDrone.Common/Disk/DiskProviderBase.cs @@ -16,6 +16,19 @@ namespace NzbDrone.Common.Disk { private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(DiskProviderBase)); + public static StringComparison PathStringComparison + { + get + { + if (OsInfo.IsWindows) + { + return StringComparison.OrdinalIgnoreCase; + } + + return StringComparison.Ordinal; + } + } + public abstract long? GetAvailableSpace(string path); public abstract void InheritFolderPermissions(string filename); public abstract void SetPermissions(string path, string mask, string user, string group); @@ -86,7 +99,7 @@ namespace NzbDrone.Common.Disk public bool FileExists(string path) { Ensure.That(path, () => path).IsValidPath(); - return FileExists(path, OsInfo.PathStringComparison); + return FileExists(path, PathStringComparison); } public bool FileExists(string path, StringComparison stringComparison) diff --git a/src/NzbDrone.Common/EnsureThat/EnsureStringExtensions.cs b/src/NzbDrone.Common/EnsureThat/EnsureStringExtensions.cs index 6532dd593..99f348667 100644 --- a/src/NzbDrone.Common/EnsureThat/EnsureStringExtensions.cs +++ b/src/NzbDrone.Common/EnsureThat/EnsureStringExtensions.cs @@ -101,12 +101,12 @@ namespace NzbDrone.Common.EnsureThat if (param.Value.IsPathValid()) return param; - if (OsInfo.IsNotWindows) + if (OsInfo.IsWindows) { - throw ExceptionFactory.CreateForParamValidation(param.Name, string.Format("value [{0}] is not a valid *nix path. paths must start with /", param.Value)); + throw ExceptionFactory.CreateForParamValidation(param.Name, string.Format("value [{0}] is not a valid Windows path. paths must be a full path eg. C:\\Windows", param.Value)); } - - throw ExceptionFactory.CreateForParamValidation(param.Name, string.Format("value [{0}] is not a valid Windows path. paths must be a full path eg. C:\\Windows", param.Value)); + + throw ExceptionFactory.CreateForParamValidation(param.Name, string.Format("value [{0}] is not a valid *nix path. paths must start with /", param.Value)); } } } diff --git a/src/NzbDrone.Common/EnvironmentInfo/AppFolderInfo.cs b/src/NzbDrone.Common/EnvironmentInfo/AppFolderInfo.cs index 75b75093e..b93d9f870 100644 --- a/src/NzbDrone.Common/EnvironmentInfo/AppFolderInfo.cs +++ b/src/NzbDrone.Common/EnvironmentInfo/AppFolderInfo.cs @@ -41,10 +41,10 @@ namespace NzbDrone.Common.EnvironmentInfo TempFolder = Path.GetTempPath(); } - public string AppDataFolder { get; private set; } + public string AppDataFolder { get; } - public string StartUpFolder { get; private set; } + public string StartUpFolder { get; } - public string TempFolder { get; private set; } + public string TempFolder { get; } } } \ No newline at end of file diff --git a/src/NzbDrone.Common/EnvironmentInfo/IOperatingSystemVersionInfo.cs b/src/NzbDrone.Common/EnvironmentInfo/IOperatingSystemVersionInfo.cs new file mode 100644 index 000000000..e953ed884 --- /dev/null +++ b/src/NzbDrone.Common/EnvironmentInfo/IOperatingSystemVersionInfo.cs @@ -0,0 +1,9 @@ +namespace NzbDrone.Common.EnvironmentInfo +{ + public interface IOperatingSystemVersionInfo + { + string Version { get; } + string Name { get; } + string FullName { get; } + } +} \ No newline at end of file diff --git a/src/NzbDrone.Common/EnvironmentInfo/IOsVersionAdapter.cs b/src/NzbDrone.Common/EnvironmentInfo/IOsVersionAdapter.cs new file mode 100644 index 000000000..ed0cd2e17 --- /dev/null +++ b/src/NzbDrone.Common/EnvironmentInfo/IOsVersionAdapter.cs @@ -0,0 +1,9 @@ +namespace NzbDrone.Common.EnvironmentInfo +{ + + public interface IOsVersionAdapter + { + bool Enabled { get; } + OsVersionModel Read(); + } +} \ No newline at end of file diff --git a/src/NzbDrone.Common/EnvironmentInfo/IPlatformInfo.cs b/src/NzbDrone.Common/EnvironmentInfo/IPlatformInfo.cs new file mode 100644 index 000000000..9b40d82f0 --- /dev/null +++ b/src/NzbDrone.Common/EnvironmentInfo/IPlatformInfo.cs @@ -0,0 +1,37 @@ +using System; + +namespace NzbDrone.Common.EnvironmentInfo +{ + + public enum PlatformType + { + DotNet = 0, + Mono = 1 + } + + public interface IPlatformInfo + { + Version Version { get; } + } + + public abstract class PlatformInfo : IPlatformInfo + { + static PlatformInfo() + { + if (Type.GetType("Mono.Runtime") != null) + { + Platform = PlatformType.Mono; + } + else + { + Platform = PlatformType.DotNet; + } + } + + public static PlatformType Platform { get; } + public static bool IsMono => Platform == PlatformType.Mono; + public static bool IsDotNet => Platform == PlatformType.DotNet; + + public abstract Version Version { get; } + } +} diff --git a/src/NzbDrone.Common/EnvironmentInfo/IRuntimeInfo.cs b/src/NzbDrone.Common/EnvironmentInfo/IRuntimeInfo.cs index 2ef08901b..cb432addc 100644 --- a/src/NzbDrone.Common/EnvironmentInfo/IRuntimeInfo.cs +++ b/src/NzbDrone.Common/EnvironmentInfo/IRuntimeInfo.cs @@ -1,14 +1,14 @@ -namespace NzbDrone.Common.EnvironmentInfo +using System; + +namespace NzbDrone.Common.EnvironmentInfo { public interface IRuntimeInfo { bool IsUserInteractive { get; } bool IsAdmin { get; } bool IsWindowsService { get; } - bool IsConsole { get; } - bool IsRunning { get; set; } + bool IsExiting { get; set; } bool RestartPending { get; set; } string ExecutingApplication { get; } - string RuntimeVersion { get; } } } \ No newline at end of file diff --git a/src/NzbDrone.Common/EnvironmentInfo/OsInfo.cs b/src/NzbDrone.Common/EnvironmentInfo/OsInfo.cs index ad1acd487..cad3d3002 100644 --- a/src/NzbDrone.Common/EnvironmentInfo/OsInfo.cs +++ b/src/NzbDrone.Common/EnvironmentInfo/OsInfo.cs @@ -1,87 +1,95 @@ using System; -using System.Diagnostics; -using System.Globalization; -using System.Runtime.InteropServices; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using NLog; namespace NzbDrone.Common.EnvironmentInfo { - public static class OsInfo + public class OsInfo : IOsInfo { + public static Os Os { get; } + + public static bool IsNotWindows => !IsWindows; + public static bool IsLinux => Os == Os.Linux; + public static bool IsOsx => Os == Os.Osx; + public static bool IsWindows => Os == Os.Windows; + + public string Version { get; } + public string Name { get; } + public string FullName { get; } static OsInfo() { - var platform = (int)Environment.OSVersion.Platform; + var platform = Environment.OSVersion.Platform; - Version = Environment.OSVersion.Version; - - IsMonoRuntime = Type.GetType("Mono.Runtime") != null; - IsNotWindows = (platform == 4) || (platform == 6) || (platform == 128); - IsOsx = IsRunningOnMac(); - IsLinux = IsNotWindows && !IsOsx; - IsWindows = !IsNotWindows; - - FirstDayOfWeek = CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek; - - if (IsWindows) + switch (platform) { - Os = Os.Windows; - PathStringComparison = StringComparison.OrdinalIgnoreCase; + case PlatformID.Win32NT: + { + Os = Os.Windows; + break; + } + case PlatformID.MacOSX: + case PlatformID.Unix: + { + // Sometimes Mac OS reports itself as Unix + if (Directory.Exists("/System/Library/CoreServices/") && + (File.Exists("/System/Library/CoreServices/SystemVersion.plist") || + File.Exists("/System/Library/CoreServices/ServerVersion.plist")) + ) + { + Os = Os.Osx; + } + else + { + Os = Os.Linux; + } + break; + } + } + } + + public OsInfo(IEnumerable versionAdapters, Logger logger) + { + OsVersionModel osInfo = null; + + foreach (var osVersionAdapter in versionAdapters.Where(c => c.Enabled)) + { + try + { + osInfo = osVersionAdapter.Read(); + } + catch (Exception e) + { + logger.Error(e, "Couldn't get OS Version info"); + } + + if (osInfo != null) + { + break; + } + } + + if (osInfo != null) + { + Name = osInfo.Name; + Version = osInfo.Version; + FullName = osInfo.FullName; } else { - Os = IsOsx ? Os.Osx : Os.Linux; - - PathStringComparison = StringComparison.Ordinal; + Name = Os.ToString(); + FullName = Name; } } + } - public static Version Version { get; private set; } - public static bool IsMonoRuntime { get; private set; } - public static bool IsNotWindows { get; private set; } - public static bool IsLinux { get; private set; } - public static bool IsOsx { get; private set; } - public static bool IsWindows { get; private set; } - public static Os Os { get; private set; } - public static DayOfWeek FirstDayOfWeek { get; private set; } - public static StringComparison PathStringComparison { get; private set; } - - //Borrowed from: https://github.com/jpobst/Pinta/blob/master/Pinta.Core/Managers/SystemManager.cs - //From Managed.Windows.Forms/XplatUI - [DllImport("libc")] - static extern int uname(IntPtr buf); - - [DebuggerStepThrough] - static bool IsRunningOnMac() - { - var buf = IntPtr.Zero; - - try - { - buf = Marshal.AllocHGlobal(8192); - // This is a hacktastic way of getting sysname from uname () - if (uname(buf) == 0) - { - var os = Marshal.PtrToStringAnsi(buf); - - if (os == "Darwin") - { - return true; - } - } - } - catch - { - } - finally - { - if (buf != IntPtr.Zero) - { - Marshal.FreeHGlobal(buf); - } - } - - return false; - } + public interface IOsInfo + { + string Version { get; } + string Name { get; } + string FullName { get; } } public enum Os diff --git a/src/NzbDrone.Common/EnvironmentInfo/OsVersionModel.cs b/src/NzbDrone.Common/EnvironmentInfo/OsVersionModel.cs new file mode 100644 index 000000000..f36a27134 --- /dev/null +++ b/src/NzbDrone.Common/EnvironmentInfo/OsVersionModel.cs @@ -0,0 +1,29 @@ +namespace NzbDrone.Common.EnvironmentInfo +{ + public class OsVersionModel + { + + + public OsVersionModel(string name, string version, string fullName = null) + { + Name = Trim(name); + Version = Trim(version); + + if (string.IsNullOrWhiteSpace(fullName)) + { + fullName = $"{Name} {Version}"; + } + + FullName = Trim(fullName); + } + + private static string Trim(string source) + { + return source.Trim().Trim('"', '\''); + } + + public string Name { get; } + public string FullName { get; } + public string Version { get; } + } +} \ No newline at end of file diff --git a/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfoBase.cs b/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs similarity index 70% rename from src/NzbDrone.Common/EnvironmentInfo/RuntimeInfoBase.cs rename to src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs index 2db303551..623c6baeb 100644 --- a/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfoBase.cs +++ b/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs @@ -5,15 +5,14 @@ using System.Reflection; using System.Security.Principal; using System.ServiceProcess; using NLog; -using NzbDrone.Common.Processes; namespace NzbDrone.Common.EnvironmentInfo { - public abstract class RuntimeInfoBase : IRuntimeInfo + public class RuntimeInfo : IRuntimeInfo { private readonly Logger _logger; - public RuntimeInfoBase(IServiceProvider serviceProvider, Logger logger) + public RuntimeInfo(IServiceProvider serviceProvider, Logger logger) { _logger = logger; @@ -31,7 +30,7 @@ namespace NzbDrone.Common.EnvironmentInfo } } - static RuntimeInfoBase() + static RuntimeInfo() { IsProduction = InternalIsProduction(); } @@ -59,31 +58,18 @@ namespace NzbDrone.Common.EnvironmentInfo public bool IsWindowsService { get; private set; } - public bool IsConsole - { - get - { - if (OsInfo.IsWindows) - { - return IsUserInteractive && Process.GetCurrentProcess().ProcessName.Equals(ProcessProvider.NZB_DRONE_CONSOLE_PROCESS_NAME, StringComparison.InvariantCultureIgnoreCase); - } - - return true; - } - } - - public bool IsRunning { get; set; } + public bool IsExiting { get; set; } public bool RestartPending { get; set; } - public string ExecutingApplication { get; private set; } + public string ExecutingApplication { get; } - public abstract string RuntimeVersion { get; } - - public static bool IsProduction { get; private set; } + public static bool IsProduction { get; } private static bool InternalIsProduction() { if (BuildInfo.IsDebug || Debugger.IsAttached) return false; - if (BuildInfo.Version.Revision > 10000) return false; //Official builds will never have such a high revision + + //Official builds will never have such a high revision + if (BuildInfo.Version.Revision > 10000) return false; try { @@ -99,17 +85,17 @@ namespace NzbDrone.Common.EnvironmentInfo } - try - { - var currentAssmeblyLocation = typeof(RuntimeInfoBase).Assembly.Location; - if(currentAssmeblyLocation.ToLower().Contains("_output"))return false; - } - catch - { + try + { + var currentAssemblyLocation = typeof(RuntimeInfo).Assembly.Location; + if (currentAssemblyLocation.ToLower().Contains("_output")) return false; + } + catch + { - } + } - string lowerCurrentDir = Directory.GetCurrentDirectory().ToLower(); + var lowerCurrentDir = Directory.GetCurrentDirectory().ToLower(); if (lowerCurrentDir.Contains("teamcity")) return false; if (lowerCurrentDir.Contains("_output")) return false; diff --git a/src/NzbDrone.Common/Exceptron/ExceptionExtentions.cs b/src/NzbDrone.Common/Exceptron/ExceptionExtentions.cs deleted file mode 100644 index cb3d30b90..000000000 --- a/src/NzbDrone.Common/Exceptron/ExceptionExtentions.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using NzbDrone.Common.EnvironmentInfo; - -namespace NzbDrone.Common.Exceptron -{ - public static class ExceptionExtentions - { - private const string IGNORE_FLAG = "exceptron_ignore"; - - public static Exception ExceptronIgnoreOnMono(this Exception exception) - { - if (OsInfo.IsNotWindows) - { - exception.ExceptronIgnore(); - } - - return exception; - } - - public static Exception ExceptronIgnore(this Exception exception) - { - exception.Data.Add(IGNORE_FLAG, true); - return exception; - } - - public static bool ExceptronShouldIgnore(this Exception exception) - { - return exception.Data.Contains(IGNORE_FLAG); - } - } -} \ No newline at end of file diff --git a/src/NzbDrone.Common/Extensions/PathExtensions.cs b/src/NzbDrone.Common/Extensions/PathExtensions.cs index 7e77f9d7e..e03f0a594 100644 --- a/src/NzbDrone.Common/Extensions/PathExtensions.cs +++ b/src/NzbDrone.Common/Extensions/PathExtensions.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; +using NzbDrone.Common.Disk; using NzbDrone.Common.EnsureThat; using NzbDrone.Common.EnvironmentInfo; @@ -47,7 +48,7 @@ namespace NzbDrone.Common.Extensions { if (!comparison.HasValue) { - comparison = OsInfo.PathStringComparison; + comparison = DiskProviderBase.PathStringComparison; } if (firstPath.Equals(secondPath, comparison.Value)) return true; @@ -93,7 +94,7 @@ namespace NzbDrone.Common.Extensions while (child.Parent != null) { - if (child.Parent.FullName.Equals(parent.FullName, OsInfo.PathStringComparison)) + if (child.Parent.FullName.Equals(parent.FullName, DiskProviderBase.PathStringComparison)) { return true; } diff --git a/src/NzbDrone.Common/Http/Dispatchers/CurlHttpDispatcher.cs b/src/NzbDrone.Common/Http/Dispatchers/CurlHttpDispatcher.cs index 2c456536c..83d6fb1d1 100644 --- a/src/NzbDrone.Common/Http/Dispatchers/CurlHttpDispatcher.cs +++ b/src/NzbDrone.Common/Http/Dispatchers/CurlHttpDispatcher.cs @@ -21,6 +21,7 @@ namespace NzbDrone.Common.Http.Dispatchers private static readonly Regex ExpiryDate = new Regex(@"(expires=)([^;]+)", RegexOptions.IgnoreCase | RegexOptions.Compiled); private readonly IHttpProxySettingsProvider _proxySettingsProvider; + private readonly IUserAgentBuilder _userAgentBuilder; private readonly Logger _logger; private const string _caBundleFileName = "curl-ca-bundle.crt"; @@ -38,9 +39,10 @@ namespace NzbDrone.Common.Http.Dispatchers } } - public CurlHttpDispatcher(IHttpProxySettingsProvider proxySettingsProvider, Logger logger) + public CurlHttpDispatcher(IHttpProxySettingsProvider proxySettingsProvider, IUserAgentBuilder userAgentBuilder, Logger logger) { _proxySettingsProvider = proxySettingsProvider; + _userAgentBuilder = userAgentBuilder; _logger = logger; } @@ -102,9 +104,9 @@ namespace NzbDrone.Common.Http.Dispatchers break; default: - throw new NotSupportedException(string.Format("HttpCurl method {0} not supported", request.Method)); + throw new NotSupportedException($"HttpCurl method {request.Method} not supported"); } - curlEasy.UserAgent = request.UseSimplifiedUserAgent ? UserAgentBuilder.UserAgentSimplified : UserAgentBuilder.UserAgent; ; + curlEasy.UserAgent = _userAgentBuilder.GetUserAgent(request.UseSimplifiedUserAgent); curlEasy.FollowLocation = request.AllowAutoRedirect; if (request.RequestTimeout != TimeSpan.Zero) diff --git a/src/NzbDrone.Common/Http/Dispatchers/FallbackHttpDispatcher.cs b/src/NzbDrone.Common/Http/Dispatchers/FallbackHttpDispatcher.cs index 109d4aec2..707004c9d 100644 --- a/src/NzbDrone.Common/Http/Dispatchers/FallbackHttpDispatcher.cs +++ b/src/NzbDrone.Common/Http/Dispatchers/FallbackHttpDispatcher.cs @@ -10,21 +10,23 @@ namespace NzbDrone.Common.Http.Dispatchers { private readonly ManagedHttpDispatcher _managedDispatcher; private readonly CurlHttpDispatcher _curlDispatcher; + private readonly IPlatformInfo _platformInfo; private readonly Logger _logger; private readonly ICached _curlTLSFallbackCache; - public FallbackHttpDispatcher(ManagedHttpDispatcher managedDispatcher, CurlHttpDispatcher curlDispatcher, ICacheManager cacheManager, Logger logger) + public FallbackHttpDispatcher(ManagedHttpDispatcher managedDispatcher, CurlHttpDispatcher curlDispatcher, ICacheManager cacheManager, IPlatformInfo platformInfo, Logger logger) { _managedDispatcher = managedDispatcher; _curlDispatcher = curlDispatcher; + _platformInfo = platformInfo; _curlTLSFallbackCache = cacheManager.GetCache(GetType(), "curlTLSFallback"); _logger = logger; } public HttpResponse GetResponse(HttpRequest request, CookieContainer cookies) { - if (OsInfo.IsMonoRuntime && request.Url.Scheme == "https") + if (PlatformInfo.IsMono && request.Url.Scheme == "https") { if (!_curlTLSFallbackCache.Find(request.Url.Host)) { diff --git a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs index 6fdef87c1..60231f75e 100644 --- a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs +++ b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs @@ -11,11 +11,13 @@ namespace NzbDrone.Common.Http.Dispatchers { private readonly IHttpProxySettingsProvider _proxySettingsProvider; private readonly ICreateManagedWebProxy _createManagedWebProxy; + private readonly IUserAgentBuilder _userAgentBuilder; - public ManagedHttpDispatcher(IHttpProxySettingsProvider proxySettingsProvider, ICreateManagedWebProxy createManagedWebProxy) + public ManagedHttpDispatcher(IHttpProxySettingsProvider proxySettingsProvider, ICreateManagedWebProxy createManagedWebProxy, IUserAgentBuilder userAgentBuilder) { _proxySettingsProvider = proxySettingsProvider; _createManagedWebProxy = createManagedWebProxy; + _userAgentBuilder = userAgentBuilder; } public HttpResponse GetResponse(HttpRequest request, CookieContainer cookies) @@ -28,7 +30,7 @@ namespace NzbDrone.Common.Http.Dispatchers webRequest.AutomaticDecompression = DecompressionMethods.GZip; webRequest.Method = request.Method.ToString(); - webRequest.UserAgent = request.UseSimplifiedUserAgent ? UserAgentBuilder.UserAgentSimplified : UserAgentBuilder.UserAgent; + webRequest.UserAgent = _userAgentBuilder.GetUserAgent(request.UseSimplifiedUserAgent); webRequest.KeepAlive = request.ConnectionKeepAlive; webRequest.AllowAutoRedirect = request.AllowAutoRedirect; webRequest.CookieContainer = cookies; diff --git a/src/NzbDrone.Common/Http/HttpClient.cs b/src/NzbDrone.Common/Http/HttpClient.cs index 3b81a8298..3a9e883cd 100644 --- a/src/NzbDrone.Common/Http/HttpClient.cs +++ b/src/NzbDrone.Common/Http/HttpClient.cs @@ -30,12 +30,19 @@ namespace NzbDrone.Common.Http private readonly ICached _cookieContainerCache; private readonly List _requestInterceptors; private readonly IHttpDispatcher _httpDispatcher; + private readonly IUserAgentBuilder _userAgentBuilder; - public HttpClient(IEnumerable requestInterceptors, ICacheManager cacheManager, IRateLimitService rateLimitService, IHttpDispatcher httpDispatcher, Logger logger) + public HttpClient(IEnumerable requestInterceptors, + ICacheManager cacheManager, + IRateLimitService rateLimitService, + IHttpDispatcher httpDispatcher, + IUserAgentBuilder userAgentBuilder, + Logger logger) { _requestInterceptors = requestInterceptors.ToList(); _rateLimitService = rateLimitService; _httpDispatcher = httpDispatcher; + _userAgentBuilder = userAgentBuilder; _logger = logger; ServicePointManager.DefaultConnectionLimit = 12; @@ -78,7 +85,7 @@ namespace NzbDrone.Common.Http _logger.Trace("Response content ({0} bytes): {1}", response.ResponseData.Length, response.Content); } - if (!RuntimeInfoBase.IsProduction && + if (!RuntimeInfo.IsProduction && (response.StatusCode == HttpStatusCode.Moved || response.StatusCode == HttpStatusCode.MovedPermanently || response.StatusCode == HttpStatusCode.Found)) @@ -163,7 +170,7 @@ namespace NzbDrone.Common.Http var stopWatch = Stopwatch.StartNew(); var webClient = new GZipWebClient(); - webClient.Headers.Add(HttpRequestHeader.UserAgent, UserAgentBuilder.UserAgent); + webClient.Headers.Add(HttpRequestHeader.UserAgent, _userAgentBuilder.GetUserAgent()); webClient.DownloadFile(url, fileName); stopWatch.Stop(); _logger.Debug("Downloading Completed. took {0:0}s", stopWatch.Elapsed.Seconds); diff --git a/src/NzbDrone.Common/Http/HttpRequest.cs b/src/NzbDrone.Common/Http/HttpRequest.cs index 3de009d0c..8f4b4472b 100644 --- a/src/NzbDrone.Common/Http/HttpRequest.cs +++ b/src/NzbDrone.Common/Http/HttpRequest.cs @@ -15,7 +15,7 @@ namespace NzbDrone.Common.Http AllowAutoRedirect = true; Cookies = new Dictionary(); - if (!RuntimeInfoBase.IsProduction) + if (!RuntimeInfo.IsProduction) { AllowAutoRedirect = false; } diff --git a/src/NzbDrone.Common/Http/UserAgentBuilder.cs b/src/NzbDrone.Common/Http/UserAgentBuilder.cs index fa99d03f4..57b63bd89 100644 --- a/src/NzbDrone.Common/Http/UserAgentBuilder.cs +++ b/src/NzbDrone.Common/Http/UserAgentBuilder.cs @@ -2,19 +2,33 @@ using NzbDrone.Common.EnvironmentInfo; namespace NzbDrone.Common.Http { - public static class UserAgentBuilder + public interface IUserAgentBuilder { - public static string UserAgent { get; private set; } - public static string UserAgentSimplified { get; private set; } + string GetUserAgent(bool simplified = false); + } - static UserAgentBuilder() + public class UserAgentBuilder : IUserAgentBuilder + { + private readonly string _userAgentSimplified; + private readonly string _userAgent; + + public string GetUserAgent(bool simplified) { - UserAgent = string.Format("Sonarr/{0} ({1} {2})", - BuildInfo.Version, - OsInfo.Os, OsInfo.Version.ToString(2)); + if (simplified) + { + return _userAgentSimplified; + } - UserAgentSimplified = string.Format("Sonarr/{0}", - BuildInfo.Version.ToString(2)); + return _userAgent; + } + + public UserAgentBuilder(IOsInfo osInfo) + { + var osName = osInfo.Name.ToLower(); + var osVersion = osInfo.Version.ToLower(); + + _userAgent = $"Sonarr/{BuildInfo.Version} ({osName} {osVersion})"; + _userAgentSimplified = $"Sonarr/{BuildInfo.Version.ToString(2)}"; } } } \ No newline at end of file diff --git a/src/NzbDrone.Common/Instrumentation/ExceptronTarget.cs b/src/NzbDrone.Common/Instrumentation/ExceptronTarget.cs deleted file mode 100644 index 437b48024..000000000 --- a/src/NzbDrone.Common/Instrumentation/ExceptronTarget.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System; -using NLog; -using NLog.Common; -using NLog.Layouts; -using NLog.Targets; -using NzbDrone.Common.EnvironmentInfo; -using NzbDrone.Common.Exceptron; -using NzbDrone.Common.Exceptron.Configuration; - -namespace NzbDrone.Common.Instrumentation -{ - /// - /// target for exceptron. Allows you to automatically report all - /// exceptions logged to Nlog/> - /// - [Target("Exceptron")] - public class ExceptronTarget : Target - { - /// - /// instance that Nlog Target uses to report the exceptions. - /// - public IExceptronClient ExceptronClient { get; internal set; } - - protected override void InitializeTarget() - { - var config = new ExceptronConfiguration - { - ApiKey = "d64e0a72845d495abc625af3a27cf5f5", - IncludeMachineName = true, - }; - - if (RuntimeInfoBase.IsProduction) - { - config.ApiKey = "82c0f66dd2d64d1480cc88b551c9bdd8"; - } - - ExceptronClient = new ExceptronClient(config, BuildInfo.Version); - } - - - /// - /// String that identifies the active user - /// - public Layout UserId { get; set; } - - protected override void Write(LogEventInfo logEvent) - { - if (logEvent == null || logEvent.Exception == null || logEvent.Exception.ExceptronShouldIgnore()) return; - - try - { - var exceptionData = new ExceptionData - { - Exception = logEvent.Exception, - Component = logEvent.LoggerName, - Message = logEvent.FormattedMessage, - }; - - if (UserId != null) - { - exceptionData.UserId = UserId.Render(logEvent); - } - - if (logEvent.Level <= LogLevel.Info) - { - exceptionData.Severity = ExceptionSeverity.None; - } - else if (logEvent.Level <= LogLevel.Warn) - { - exceptionData.Severity = ExceptionSeverity.Warning; - } - else if (logEvent.Level <= LogLevel.Error) - { - exceptionData.Severity = ExceptionSeverity.Error; - } - else if (logEvent.Level <= LogLevel.Fatal) - { - exceptionData.Severity = ExceptionSeverity.Fatal; - } - - ExceptronClient.SubmitException(exceptionData); - } - catch (Exception e) - { - InternalLogger.Warn("Unable to report exception. {0}", e); - } - } - } -} \ No newline at end of file diff --git a/src/NzbDrone.Common/Instrumentation/GlobalExceptionHandlers.cs b/src/NzbDrone.Common/Instrumentation/GlobalExceptionHandlers.cs index 93f66ca6d..05c5fe46c 100644 --- a/src/NzbDrone.Common/Instrumentation/GlobalExceptionHandlers.cs +++ b/src/NzbDrone.Common/Instrumentation/GlobalExceptionHandlers.cs @@ -35,7 +35,7 @@ namespace NzbDrone.Common.Instrumentation return; } - if (OsInfo.IsMonoRuntime) + if (PlatformInfo.IsMono) { if (exception is TypeInitializationException && exception.InnerException is DllNotFoundException || exception is DllNotFoundException) diff --git a/src/NzbDrone.Common/Instrumentation/NzbDroneLogger.cs b/src/NzbDrone.Common/Instrumentation/NzbDroneLogger.cs index 7c672f725..886027a40 100644 --- a/src/NzbDrone.Common/Instrumentation/NzbDroneLogger.cs +++ b/src/NzbDrone.Common/Instrumentation/NzbDroneLogger.cs @@ -48,7 +48,7 @@ namespace NzbDrone.Common.Instrumentation } else { - if (inConsole && (OsInfo.IsNotWindows || RuntimeInfoBase.IsUserInteractive)) + if (inConsole && (OsInfo.IsNotWindows || RuntimeInfo.IsUserInteractive)) { RegisterConsole(); } @@ -152,16 +152,6 @@ namespace NzbDrone.Common.Instrumentation LogManager.Configuration.LoggingRules.Add(loggingRule); } - private static void RegisterExceptron() - { - var exceptronTarget = new ExceptronTarget(); - var rule = new LoggingRule("*", LogLevel.Warn, exceptronTarget); - - LogManager.Configuration.AddTarget("ExceptronTarget", exceptronTarget); - LogManager.Configuration.LoggingRules.Add(rule); - } - - public static Logger GetLogger(Type obj) { return LogManager.GetLogger(obj.Name.Replace("NzbDrone.", "")); diff --git a/src/NzbDrone.Common/NzbDrone.Common.csproj b/src/NzbDrone.Common/NzbDrone.Common.csproj index 9863adf73..c0e0169b2 100644 --- a/src/NzbDrone.Common/NzbDrone.Common.csproj +++ b/src/NzbDrone.Common/NzbDrone.Common.csproj @@ -88,6 +88,9 @@ + + + @@ -118,13 +121,12 @@ - + - @@ -187,7 +189,6 @@ - diff --git a/src/NzbDrone.Common/Processes/ProcessProvider.cs b/src/NzbDrone.Common/Processes/ProcessProvider.cs index 57068c840..79bb16769 100644 --- a/src/NzbDrone.Common/Processes/ProcessProvider.cs +++ b/src/NzbDrone.Common/Processes/ProcessProvider.cs @@ -108,7 +108,7 @@ namespace NzbDrone.Common.Processes public Process Start(string path, string args = null, StringDictionary environmentVariables = null, Action onOutputDataReceived = null, Action onErrorDataReceived = null) { - if (OsInfo.IsMonoRuntime && path.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase)) + if (PlatformInfo.IsMono && path.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase)) { args = GetMonoArgs(path, args); path = "mono"; @@ -174,7 +174,7 @@ namespace NzbDrone.Common.Processes public Process SpawnNewProcess(string path, string args = null, StringDictionary environmentVariables = null) { - if (OsInfo.IsMonoRuntime && path.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase)) + if (PlatformInfo.IsMono && path.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase)) { args = GetMonoArgs(path, args); path = "mono"; diff --git a/src/NzbDrone.Core.Test/Framework/CoreTest.cs b/src/NzbDrone.Core.Test/Framework/CoreTest.cs index 130473091..429388a3e 100644 --- a/src/NzbDrone.Core.Test/Framework/CoreTest.cs +++ b/src/NzbDrone.Core.Test/Framework/CoreTest.cs @@ -1,6 +1,8 @@ -using NUnit.Framework; +using System; +using NUnit.Framework; using NzbDrone.Common.Cache; using NzbDrone.Common.Cloud; +using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Http; using NzbDrone.Common.Http.Dispatchers; using NzbDrone.Common.TPL; @@ -15,12 +17,16 @@ namespace NzbDrone.Core.Test.Framework { protected void UseRealHttp() { + Mocker.GetMock().SetupGet(c => c.Version).Returns(new Version("3.0.0")); + Mocker.GetMock().SetupGet(c=>c.Version).Returns("1.0.0"); + Mocker.GetMock().SetupGet(c=>c.Name).Returns("TestOS"); + Mocker.SetConstant(new HttpProxySettingsProvider(Mocker.Resolve())); Mocker.SetConstant(new ManagedWebProxyFactory(Mocker.Resolve())); - Mocker.SetConstant(new ManagedHttpDispatcher(Mocker.Resolve(), Mocker.Resolve())); - Mocker.SetConstant(new CurlHttpDispatcher(Mocker.Resolve(), Mocker.Resolve())); + Mocker.SetConstant(new ManagedHttpDispatcher(Mocker.Resolve(), Mocker.Resolve(), Mocker.Resolve())); + Mocker.SetConstant(new CurlHttpDispatcher(Mocker.Resolve(), Mocker.Resolve(), Mocker.Resolve())); Mocker.SetConstant(new HttpProvider(TestLogger)); - Mocker.SetConstant(new HttpClient(new IHttpRequestInterceptor[0], Mocker.Resolve(), Mocker.Resolve(), Mocker.Resolve(), TestLogger)); + Mocker.SetConstant(new HttpClient(new IHttpRequestInterceptor[0], Mocker.Resolve(), Mocker.Resolve(), Mocker.Resolve(), Mocker.Resolve(), TestLogger)); Mocker.SetConstant(new SonarrCloudRequestBuilder()); } } diff --git a/src/NzbDrone.Core.Test/HealthCheck/Checks/MonoVersionCheckFixture.cs b/src/NzbDrone.Core.Test/HealthCheck/Checks/MonoVersionCheckFixture.cs index 420e0268a..baca51b08 100644 --- a/src/NzbDrone.Core.Test/HealthCheck/Checks/MonoVersionCheckFixture.cs +++ b/src/NzbDrone.Core.Test/HealthCheck/Checks/MonoVersionCheckFixture.cs @@ -1,4 +1,5 @@ -using NUnit.Framework; +using System; +using NUnit.Framework; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Core.HealthCheck.Checks; using NzbDrone.Core.Test.Framework; @@ -8,17 +9,13 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks [TestFixture] public class MonoVersionCheckFixture : CoreTest { - [SetUp] - public void Setup() - { - MonoOnly(); - } - private void GivenOutput(string version) { - Mocker.GetMock() - .SetupGet(s => s.RuntimeVersion) - .Returns(string.Format("{0} (tarball Wed Sep 25 16:35:44 CDT 2013)", version)); + MonoOnly(); + + Mocker.GetMock() + .SetupGet(s => s.Version) + .Returns(new Version(version)); } [TestCase("3.10")] diff --git a/src/NzbDrone.Core.Test/UpdateTests/UpdatePackageProviderFixture.cs b/src/NzbDrone.Core.Test/UpdateTests/UpdatePackageProviderFixture.cs index ff2ae0699..1a2f757ca 100644 --- a/src/NzbDrone.Core.Test/UpdateTests/UpdatePackageProviderFixture.cs +++ b/src/NzbDrone.Core.Test/UpdateTests/UpdatePackageProviderFixture.cs @@ -2,6 +2,7 @@ using System; using System.Linq; using FluentAssertions; using NUnit.Framework; +using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Update; @@ -10,6 +11,12 @@ namespace NzbDrone.Core.Test.UpdateTests { public class UpdatePackageProviderFixture : CoreTest { + [SetUp] + public void Setup() + { + Mocker.GetMock().SetupGet(c => c.Version).Returns(new Version("9.9.9")); + } + [Test] public void no_update_when_version_higher() { diff --git a/src/NzbDrone.Core/Analytics/AnalyticsService.cs b/src/NzbDrone.Core/Analytics/AnalyticsService.cs index 0ddb9813d..6e2d43382 100644 --- a/src/NzbDrone.Core/Analytics/AnalyticsService.cs +++ b/src/NzbDrone.Core/Analytics/AnalyticsService.cs @@ -17,6 +17,6 @@ namespace NzbDrone.Core.Analytics _configFileProvider = configFileProvider; } - public bool IsEnabled => _configFileProvider.AnalyticsEnabled && RuntimeInfoBase.IsProduction; + public bool IsEnabled => _configFileProvider.AnalyticsEnabled && RuntimeInfo.IsProduction; } } \ No newline at end of file diff --git a/src/NzbDrone.Core/Configuration/ConfigService.cs b/src/NzbDrone.Core/Configuration/ConfigService.cs index 4eae607ae..8563e1eb1 100644 --- a/src/NzbDrone.Core/Configuration/ConfigService.cs +++ b/src/NzbDrone.Core/Configuration/ConfigService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using NLog; using NzbDrone.Common.EnsureThat; @@ -246,7 +247,7 @@ namespace NzbDrone.Core.Configuration public int FirstDayOfWeek { - get { return GetValueInt("FirstDayOfWeek", (int)OsInfo.FirstDayOfWeek); } + get { return GetValueInt("FirstDayOfWeek", (int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek); } set { SetValue("FirstDayOfWeek", value); } } diff --git a/src/NzbDrone.Core/HealthCheck/Checks/MonoVersionCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/MonoVersionCheck.cs index f74156cb3..2033b9d87 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/MonoVersionCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/MonoVersionCheck.cs @@ -1,7 +1,6 @@ using System; using System.Linq; using System.Reflection; -using System.Text.RegularExpressions; using NLog; using NzbDrone.Common.EnvironmentInfo; @@ -9,50 +8,43 @@ namespace NzbDrone.Core.HealthCheck.Checks { public class MonoVersionCheck : HealthCheckBase { - private readonly IRuntimeInfo _runtimeInfo; + private readonly IPlatformInfo _platformInfo; private readonly Logger _logger; - private static readonly Regex VersionRegex = new Regex(@"(?<=\W|^)(?\d+\.\d+(\.\d+)?(\.\d+)?)(?=\W)", RegexOptions.Compiled | RegexOptions.IgnoreCase); - public MonoVersionCheck(IRuntimeInfo runtimeInfo, Logger logger) + public MonoVersionCheck(IPlatformInfo platformInfo, Logger logger) { - _runtimeInfo = runtimeInfo; + _platformInfo = platformInfo; _logger = logger; } public override HealthCheck Check() { - if (OsInfo.IsWindows) + if (!PlatformInfo.IsMono) { return new HealthCheck(GetType()); } - var versionString = _runtimeInfo.RuntimeVersion; - var versionMatch = VersionRegex.Match(versionString); + var monoVersion = _platformInfo.Version; - if (versionMatch.Success) + if (monoVersion == new Version("3.4.0") && HasMonoBug18599()) { - var version = new Version(versionMatch.Groups["version"].Value); - - if (version == new Version(3, 4, 0) && HasMonoBug18599()) - { - _logger.Debug("mono version 3.4.0, checking for mono bug #18599 returned positive."); - return new HealthCheck(GetType(), HealthCheckResult.Error, "your mono version 3.4.0 has a critical bug, you should upgrade to a higher version"); - } - - if (version == new Version(4, 4, 0) || version == new Version(4, 4, 1)) - { - _logger.Debug("mono version {0}", version); - return new HealthCheck(GetType(), HealthCheckResult.Error, $"your mono version {version} has a bug that causes issues connecting to indexers/download clients"); - } - - if (version >= new Version(3, 10)) - { - _logger.Debug("mono version is 3.10 or better: {0}", version.ToString()); - return new HealthCheck(GetType()); - } + _logger.Debug("Mono version 3.4.0, checking for Mono bug #18599 returned positive."); + return new HealthCheck(GetType(), HealthCheckResult.Error, "You are running an old and unsupported version of Mono with a known bug. You should upgrade to a higher version"); } - return new HealthCheck(GetType(), HealthCheckResult.Warning, "mono version is less than 3.10, upgrade for improved stability"); + if (monoVersion == new Version("4.4.0") || monoVersion == new Version("4.4.1")) + { + _logger.Debug("Mono version {0}", monoVersion); + return new HealthCheck(GetType(), HealthCheckResult.Error, $"Your Mono version {monoVersion} has a bug that causes issues connecting to indexers/download clients. You should upgrade to a higher version"); + } + + if (monoVersion >= new Version("3.10")) + { + _logger.Debug("Mono version is 3.10 or better: {0}", monoVersion); + return new HealthCheck(GetType()); + } + + return new HealthCheck(GetType(), HealthCheckResult.Warning, "You are running an old and unsupported version of Mono. Please upgrade Mono for improved stability."); } public override bool CheckOnConfigChange => false; @@ -70,7 +62,8 @@ namespace NzbDrone.Core.HealthCheck.Checks return false; } - var fieldInfo = numberFormatterType.GetField("userFormatProvider", BindingFlags.Static | BindingFlags.NonPublic); + var fieldInfo = numberFormatterType.GetField("userFormatProvider", + BindingFlags.Static | BindingFlags.NonPublic); if (fieldInfo == null) { @@ -87,4 +80,4 @@ namespace NzbDrone.Core.HealthCheck.Checks return false; } } -} +} \ No newline at end of file diff --git a/src/NzbDrone.Core/Lifecycle/ApplicationShutdownRequested.cs b/src/NzbDrone.Core/Lifecycle/ApplicationShutdownRequested.cs index 50446ed1d..42d2f411e 100644 --- a/src/NzbDrone.Core/Lifecycle/ApplicationShutdownRequested.cs +++ b/src/NzbDrone.Core/Lifecycle/ApplicationShutdownRequested.cs @@ -4,13 +4,9 @@ namespace NzbDrone.Core.Lifecycle { public class ApplicationShutdownRequested : IEvent { - public bool Restarting { get; set; } + public bool Restarting { get; } - public ApplicationShutdownRequested() - { - } - - public ApplicationShutdownRequested(bool restarting) + public ApplicationShutdownRequested(bool restarting = false) { Restarting = restarting; } diff --git a/src/NzbDrone.Core/MediaFiles/UpdateEpisodeFileService.cs b/src/NzbDrone.Core/MediaFiles/UpdateEpisodeFileService.cs index 67b415c20..cd68be94b 100644 --- a/src/NzbDrone.Core/MediaFiles/UpdateEpisodeFileService.cs +++ b/src/NzbDrone.Core/MediaFiles/UpdateEpisodeFileService.cs @@ -164,7 +164,6 @@ namespace NzbDrone.Core.MediaFiles catch (Exception ex) { - ex.ExceptronIgnoreOnMono(); _logger.Warn(ex, "Unable to set date of file [" + filePath + "]"); } } diff --git a/src/NzbDrone.Core/Rest/RestClientFactory.cs b/src/NzbDrone.Core/Rest/RestClientFactory.cs index 0c92590f6..f0259e54e 100644 --- a/src/NzbDrone.Core/Rest/RestClientFactory.cs +++ b/src/NzbDrone.Core/Rest/RestClientFactory.cs @@ -7,12 +7,11 @@ namespace NzbDrone.Core.Rest { public static RestClient BuildClient(string baseUrl) { - var restClient = new RestClient(baseUrl); + var restClient = new RestClient(baseUrl) + { + UserAgent = $"Sonarr/{BuildInfo.Version} ({OsInfo.Os})" + }; - restClient.UserAgent = string.Format("Sonarr/{0} (RestSharp/{1}; {2}/{3})", - BuildInfo.Version, - restClient.GetType().Assembly.GetName().Version, - OsInfo.Os, OsInfo.Version.ToString(2)); return restClient; } diff --git a/src/NzbDrone.Core/Update/UpdateCheckService.cs b/src/NzbDrone.Core/Update/UpdateCheckService.cs index 807250780..71f5c3d46 100644 --- a/src/NzbDrone.Core/Update/UpdateCheckService.cs +++ b/src/NzbDrone.Core/Update/UpdateCheckService.cs @@ -1,5 +1,4 @@ -using NLog; -using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Core.Configuration; namespace NzbDrone.Core.Update @@ -14,16 +13,12 @@ namespace NzbDrone.Core.Update private readonly IUpdatePackageProvider _updatePackageProvider; private readonly IConfigFileProvider _configFileProvider; - private readonly Logger _logger; - public CheckUpdateService(IUpdatePackageProvider updatePackageProvider, - IConfigFileProvider configFileProvider, - Logger logger) + IConfigFileProvider configFileProvider) { _updatePackageProvider = updatePackageProvider; _configFileProvider = configFileProvider; - _logger = logger; } public UpdatePackage AvailableUpdate() diff --git a/src/NzbDrone.Core/Update/UpdatePackageProvider.cs b/src/NzbDrone.Core/Update/UpdatePackageProvider.cs index 5abb55726..cbcab70dc 100644 --- a/src/NzbDrone.Core/Update/UpdatePackageProvider.cs +++ b/src/NzbDrone.Core/Update/UpdatePackageProvider.cs @@ -15,11 +15,13 @@ namespace NzbDrone.Core.Update public class UpdatePackageProvider : IUpdatePackageProvider { private readonly IHttpClient _httpClient; + private readonly IPlatformInfo _platformInfo; private readonly IHttpRequestBuilderFactory _requestBuilder; - public UpdatePackageProvider(IHttpClient httpClient, ISonarrCloudRequestBuilder requestBuilder) + public UpdatePackageProvider(IHttpClient httpClient, ISonarrCloudRequestBuilder requestBuilder, IPlatformInfo platformInfo) { _httpClient = httpClient; + _platformInfo = platformInfo; _requestBuilder = requestBuilder.Services; } @@ -29,6 +31,7 @@ namespace NzbDrone.Core.Update .Resource("/update/{branch}") .AddQueryParam("version", currentVersion) .AddQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant()) + .AddQueryParam("runtimeVer", _platformInfo.Version) .SetSegment("branch", branch) .Build(); @@ -45,6 +48,7 @@ namespace NzbDrone.Core.Update .Resource("/update/{branch}/changes") .AddQueryParam("version", currentVersion) .AddQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant()) + .AddQueryParam("runtimeVer", _platformInfo.Version) .SetSegment("branch", branch) .Build(); diff --git a/src/NzbDrone.Host/AccessControl/UrlAclAdapter.cs b/src/NzbDrone.Host/AccessControl/UrlAclAdapter.cs index 9493dd276..fd483479b 100644 --- a/src/NzbDrone.Host/AccessControl/UrlAclAdapter.cs +++ b/src/NzbDrone.Host/AccessControl/UrlAclAdapter.cs @@ -20,6 +20,7 @@ namespace NzbDrone.Host.AccessControl private readonly INetshProvider _netshProvider; private readonly IConfigFileProvider _configFileProvider; private readonly IRuntimeInfo _runtimeInfo; + private readonly IOsInfo _osInfo; private readonly Logger _logger; public List Urls @@ -30,19 +31,21 @@ namespace NzbDrone.Host.AccessControl } } - private List InternalUrls { get; set; } - private List RegisteredUrls { get; set; } + private List InternalUrls { get; } + private List RegisteredUrls { get; } private static readonly Regex UrlAclRegex = new Regex(@"(?https?)\:\/\/(?
.+?)\:(?\d+)/(?.+)?", RegexOptions.Compiled | RegexOptions.IgnoreCase); public UrlAclAdapter(INetshProvider netshProvider, IConfigFileProvider configFileProvider, IRuntimeInfo runtimeInfo, + IOsInfo osInfo, Logger logger) { _netshProvider = netshProvider; _configFileProvider = configFileProvider; _runtimeInfo = runtimeInfo; + _osInfo = osInfo; _logger = logger; InternalUrls = new List(); @@ -105,7 +108,8 @@ namespace NzbDrone.Host.AccessControl private void RefreshRegistration() { - if (OsInfo.Version.Major < 6) return; + var osVersion = new Version(_osInfo.Version); + if (osVersion.Major < 6) return; foreach (var urlAcl in InternalUrls) { diff --git a/src/NzbDrone.Host/ApplicationServer.cs b/src/NzbDrone.Host/ApplicationServer.cs index fdd3c3683..29d56304e 100644 --- a/src/NzbDrone.Host/ApplicationServer.cs +++ b/src/NzbDrone.Host/ApplicationServer.cs @@ -51,7 +51,7 @@ namespace NzbDrone.Host Console.CancelKeyPress += (sender, eventArgs) => LogManager.Configuration = null; } - _runtimeInfo.IsRunning = true; + _runtimeInfo.IsExiting = false; _hostController.StartServer(); if (!_startupContext.Flags.Contains(StartupContext.NO_BROWSER) @@ -76,7 +76,7 @@ namespace NzbDrone.Host _logger.Info("Attempting to stop application."); _hostController.StopServer(); _logger.Info("Application has finished stop routine."); - _runtimeInfo.IsRunning = false; + _runtimeInfo.IsExiting = true; } public void Handle(ApplicationShutdownRequested message) diff --git a/src/NzbDrone.Host/SpinService.cs b/src/NzbDrone.Host/SpinService.cs index e2c4e6933..16bde2e15 100644 --- a/src/NzbDrone.Host/SpinService.cs +++ b/src/NzbDrone.Host/SpinService.cs @@ -1,6 +1,5 @@ using System.Threading; using NLog; -using NLog.Common; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Processes; @@ -28,7 +27,7 @@ namespace NzbDrone.Host public void Spin() { - while (_runtimeInfo.IsRunning) + while (!_runtimeInfo.IsExiting) { Thread.Sleep(1000); } diff --git a/src/NzbDrone.Integration.Test/IntegrationTest.cs b/src/NzbDrone.Integration.Test/IntegrationTest.cs index bd36562c8..e97287afd 100644 --- a/src/NzbDrone.Integration.Test/IntegrationTest.cs +++ b/src/NzbDrone.Integration.Test/IntegrationTest.cs @@ -25,7 +25,7 @@ namespace NzbDrone.Integration.Test protected override void InitializeTestTarget() { // Add Wombles - var wombles = Indexers.Post(new Api.Indexers.IndexerResource + Indexers.Post(new Api.Indexers.IndexerResource { EnableRss = true, ConfigContract = "NullConfig", diff --git a/src/NzbDrone.Mono.Test/EnvironmentInfo/MonoPlatformInfoFixture.cs b/src/NzbDrone.Mono.Test/EnvironmentInfo/MonoPlatformInfoFixture.cs new file mode 100644 index 000000000..3e0c17794 --- /dev/null +++ b/src/NzbDrone.Mono.Test/EnvironmentInfo/MonoPlatformInfoFixture.cs @@ -0,0 +1,20 @@ +using System; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Mono.EnvironmentInfo; +using NzbDrone.Test.Common; + +namespace NzbDrone.Mono.Test.EnvironmentInfo +{ + [TestFixture] + [Platform("Mono")] + public class MonoPlatformInfoFixture : TestBase + { + [Test] + public void should_get_framework_version() + { + Subject.Version.Major.Should().Be(4); + Subject.Version.Minor.Should().BeOneOf(0, 5, 6); + } + } +} diff --git a/src/NzbDrone.Mono.Test/EnvironmentInfo/ReleaseFileVersionAdapterFixture.cs b/src/NzbDrone.Mono.Test/EnvironmentInfo/ReleaseFileVersionAdapterFixture.cs new file mode 100644 index 000000000..c2772e215 --- /dev/null +++ b/src/NzbDrone.Mono.Test/EnvironmentInfo/ReleaseFileVersionAdapterFixture.cs @@ -0,0 +1,29 @@ +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Common.Disk; +using NzbDrone.Mono.Disk; +using NzbDrone.Mono.EnvironmentInfo.VersionAdapters; +using NzbDrone.Test.Common; + +namespace NzbDrone.Mono.Test.EnvironmentInfo +{ + [TestFixture] + [Platform("Mono")] + public class ReleaseFileVersionAdapterFixture : TestBase + { + [SetUp] + public void Setup() + { + Mocker.SetConstant(Mocker.Resolve()); + } + + [Test] + public void should_get_version_info() + { + var info = Subject.Read(); + info.FullName.Should().NotBeNullOrWhiteSpace(); + info.Name.Should().NotBeNullOrWhiteSpace(); + info.Version.Should().NotBeNullOrWhiteSpace(); + } + } +} \ No newline at end of file diff --git a/src/NzbDrone.Mono.Test/EnvironmentInfo/VersionAdapters/MacOsVersionAdapterFixture.cs b/src/NzbDrone.Mono.Test/EnvironmentInfo/VersionAdapters/MacOsVersionAdapterFixture.cs new file mode 100644 index 000000000..6ca90eb90 --- /dev/null +++ b/src/NzbDrone.Mono.Test/EnvironmentInfo/VersionAdapters/MacOsVersionAdapterFixture.cs @@ -0,0 +1,77 @@ +using System; +using System.IO; +using FluentAssertions; +using Moq; +using NUnit.Framework; +using NzbDrone.Common.Disk; +using NzbDrone.Mono.EnvironmentInfo.VersionAdapters; +using NzbDrone.Test.Common; + +namespace NzbDrone.Mono.Test.EnvironmentInfo.VersionAdapters +{ + [TestFixture] + public class MacOsVersionAdapterFixture : TestBase + { + [TestCase("10.8.0")] + [TestCase("10.8")] + [TestCase("10.8.1")] + [TestCase("10.11.20")] + public void should_get_version_info(string versionString) + { + var fileContent = File.ReadAllText(GetTestPath("Files/macOS/SystemVersion.plist")).Replace("10.0.0", versionString); + + const string plistPath = "/System/Library/CoreServices/SystemVersion.plist"; + + Mocker.GetMock() + .Setup(c => c.FolderExists("/System/Library/CoreServices/")).Returns(true); + + Mocker.GetMock() + .Setup(c => c.GetFiles("/System/Library/CoreServices/", SearchOption.TopDirectoryOnly)) + .Returns(new[] { plistPath }); + + Mocker.GetMock() + .Setup(c => c.ReadAllText(plistPath)) + .Returns(fileContent); + + var versionName = Subject.Read(); + versionName.Version.Should().Be(versionString); + versionName.Name.Should().Be("macOS"); + versionName.FullName.Should().Be("macOS " + versionString); + } + + + [TestCase] + public void should_detect_server() + { + var fileContent = File.ReadAllText(GetTestPath("Files/macOS/SystemVersion.plist")); + + const string plistPath = "/System/Library/CoreServices/ServerVersion.plist"; + + Mocker.GetMock() + .Setup(c => c.FolderExists("/System/Library/CoreServices/")).Returns(true); + + Mocker.GetMock() + .Setup(c => c.GetFiles("/System/Library/CoreServices/", SearchOption.TopDirectoryOnly)) + .Returns(new[] { plistPath }); + + Mocker.GetMock() + .Setup(c => c.ReadAllText(plistPath)) + .Returns(fileContent); + + var versionName = Subject.Read(); + versionName.Name.Should().Be("macOS Server"); + } + + [TestCase] + public void should_return_null_if_folder_doesnt_exist() + { + Mocker.GetMock() + .Setup(c => c.FolderExists("/System/Library/CoreServices/")).Returns(false); + + Subject.Read().Should().BeNull(); + + Mocker.GetMock() + .Verify(c => c.GetFiles(It.IsAny(), SearchOption.TopDirectoryOnly), Times.Never()); + } + } +} \ No newline at end of file diff --git a/src/NzbDrone.Mono.Test/EnvironmentInfo/VersionAdapters/ReleaseFileVersionAdapterFixture.cs b/src/NzbDrone.Mono.Test/EnvironmentInfo/VersionAdapters/ReleaseFileVersionAdapterFixture.cs new file mode 100644 index 000000000..2979b1544 --- /dev/null +++ b/src/NzbDrone.Mono.Test/EnvironmentInfo/VersionAdapters/ReleaseFileVersionAdapterFixture.cs @@ -0,0 +1,82 @@ +using System.IO; +using FluentAssertions; +using Moq; +using NUnit.Framework; +using NzbDrone.Common.Disk; +using NzbDrone.Mono.Disk; +using NzbDrone.Mono.EnvironmentInfo.VersionAdapters; +using NzbDrone.Test.Common; +using NzbDrone.Test.Common.Categories; + +namespace NzbDrone.Mono.Test.EnvironmentInfo.VersionAdapters +{ + [TestFixture] + public class ReleaseFileVersionAdapterFixture : TestBase + { + [Test] + [IntegrationTest] + [Platform("Mono")] + public void should_get_version_info_from_actual_linux() + { + Mocker.SetConstant(Mocker.Resolve()); + var info = Subject.Read(); + info.FullName.Should().NotBeNullOrWhiteSpace(); + info.Name.Should().NotBeNullOrWhiteSpace(); + info.Version.Should().NotBeNullOrWhiteSpace(); + } + + [Test] + public void should_return_null_if_etc_doestn_exist() + { + Mocker.GetMock().Setup(c => c.FolderExists("/etc/")).Returns(false); + Subject.Read().Should().BeNull(); + + Mocker.GetMock() + .Verify(c => c.GetFiles(It.IsAny(), SearchOption.TopDirectoryOnly), Times.Never()); + + Subject.Read().Should().BeNull(); + } + + + [Test] + public void should_return_null_if_release_file_doestn_exist() + { + Mocker.GetMock().Setup(c => c.FolderExists("/etc/")).Returns(true); + Subject.Read().Should().BeNull(); + + Mocker.GetMock() + .Setup(c => c.GetFiles(It.IsAny(), SearchOption.TopDirectoryOnly)).Returns(new string[0]); + + Subject.Read().Should().BeNull(); + } + + [Test] + public void should_detect_version() + { + Mocker.GetMock().Setup(c => c.FolderExists("/etc/")).Returns(true); + Subject.Read().Should().BeNull(); + + Mocker.GetMock() + .Setup(c => c.GetFiles(It.IsAny(), SearchOption.TopDirectoryOnly)).Returns(new[] + { + "/etc/lsb-release", + "/etc/os-release" + }); + + Mocker.GetMock() + .Setup(c => c.ReadAllText("/etc/lsb-release")) + .Returns(File.ReadAllText(GetTestPath("Files/linux/lsb-release"))); + + Mocker.GetMock() + .Setup(c => c.ReadAllText("/etc/os-release")) + .Returns(File.ReadAllText(GetTestPath("Files/linux/os-release"))); + + var version = Subject.Read(); + version.Should().NotBeNull(); + version.Name.Should().Be("ubuntu"); + version.Version.Should().Be("14.04"); + version.FullName.Should().Be("Ubuntu 14.04.5 LTS"); + + } + } +} \ No newline at end of file diff --git a/src/NzbDrone.Mono.Test/Files/linux/lsb-release b/src/NzbDrone.Mono.Test/Files/linux/lsb-release new file mode 100644 index 000000000..55eb268d5 --- /dev/null +++ b/src/NzbDrone.Mono.Test/Files/linux/lsb-release @@ -0,0 +1,4 @@ +DISTRIB_ID=Ubuntu +DISTRIB_RELEASE=14.04 +DISTRIB_CODENAME=trusty +DISTRIB_DESCRIPTION="Ubuntu 14.04.5 LTS" \ No newline at end of file diff --git a/src/NzbDrone.Mono.Test/Files/linux/os-release b/src/NzbDrone.Mono.Test/Files/linux/os-release new file mode 100644 index 000000000..724f6a79f --- /dev/null +++ b/src/NzbDrone.Mono.Test/Files/linux/os-release @@ -0,0 +1,9 @@ +NAME="Ubuntu" +VERSION="14.04.5 LTS, Trusty Tahr" +ID=ubuntu +ID_LIKE=debian +PRETTY_NAME="Ubuntu 14.04.5 LTS" +VERSION_ID="14.04" +HOME_URL="http://www.ubuntu.com/" +SUPPORT_URL="http://help.ubuntu.com/" +BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/" \ No newline at end of file diff --git a/src/NzbDrone.Mono.Test/Files/macOS/SystemVersion.plist b/src/NzbDrone.Mono.Test/Files/macOS/SystemVersion.plist new file mode 100644 index 000000000..253dd5075 --- /dev/null +++ b/src/NzbDrone.Mono.Test/Files/macOS/SystemVersion.plist @@ -0,0 +1,16 @@ + + + + + ProductBuildVersion + 16C68 + ProductCopyright + 1983-2016 Apple Inc. + ProductName + Mac OS X + ProductUserVisibleVersion + 10.0.0 + ProductVersion + 10.0.0 + + diff --git a/src/NzbDrone.Mono.Test/Files/synology/VERSION b/src/NzbDrone.Mono.Test/Files/synology/VERSION new file mode 100644 index 000000000..029234d3c --- /dev/null +++ b/src/NzbDrone.Mono.Test/Files/synology/VERSION @@ -0,0 +1,8 @@ +majorversion="6" +minorversion="0" +productversion="6.0.2" +buildphase="hotfix" +buildnumber="8451" +smallfixnumber="7" +builddate="2016/12/20" +buildtime="05:11:44" \ No newline at end of file diff --git a/src/NzbDrone.Mono.Test/NzbDrone.Mono.Test.csproj b/src/NzbDrone.Mono.Test/NzbDrone.Mono.Test.csproj index ad038409c..33eb1bbea 100644 --- a/src/NzbDrone.Mono.Test/NzbDrone.Mono.Test.csproj +++ b/src/NzbDrone.Mono.Test/NzbDrone.Mono.Test.csproj @@ -81,10 +81,17 @@ + + + + + + Always + @@ -116,6 +123,19 @@ + + + Always + + + + + Always + + + + +