diff --git a/src/NzbDrone.Api/Frontend/CacheableSpecification.cs b/src/NzbDrone.Api/Frontend/CacheableSpecification.cs index b427658e9..3affedbf0 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; } @@ -46,4 +46,4 @@ namespace NzbDrone.Api.Frontend return true; } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Api/Frontend/Mappers/IndexHtmlMapper.cs b/src/NzbDrone.Api/Frontend/Mappers/IndexHtmlMapper.cs index c6b77cc9f..46b5d9c37 100644 --- a/src/NzbDrone.Api/Frontend/Mappers/IndexHtmlMapper.cs +++ b/src/NzbDrone.Api/Frontend/Mappers/IndexHtmlMapper.cs @@ -79,7 +79,7 @@ namespace NzbDrone.Api.Frontend.Mappers private string GetIndexText() { - if (RuntimeInfoBase.IsProduction && _generatedContent != null) + if (RuntimeInfo.IsProduction && _generatedContent != null) { return _generatedContent; } @@ -111,7 +111,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 78ac15d6e..4ac5fa6c1 100644 --- a/src/NzbDrone.Api/NancyBootstrapper.cs +++ b/src/NzbDrone.Api/NancyBootstrapper.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using Nancy.Bootstrapper; using Nancy.Diagnostics; using NLog; @@ -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/System/SystemModule.cs b/src/NzbDrone.Api/System/SystemModule.cs index 2ec787115..fc1f27238 100644 --- a/src/NzbDrone.Api/System/SystemModule.cs +++ b/src/NzbDrone.Api/System/SystemModule.cs @@ -1,4 +1,4 @@ -using Nancy; +using Nancy; using Nancy.Routing; using NzbDrone.Api.Extensions; using NzbDrone.Common.EnvironmentInfo; @@ -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.Api/app.config b/src/NzbDrone.Api/app.config index cbff67135..18c0498d6 100644 --- a/src/NzbDrone.Api/app.config +++ b/src/NzbDrone.Api/app.config @@ -4,7 +4,7 @@ - + diff --git a/src/NzbDrone.Automation.Test/app.config b/src/NzbDrone.Automation.Test/app.config index c7d36b5e3..077a6a061 100644 --- a/src/NzbDrone.Automation.Test/app.config +++ b/src/NzbDrone.Automation.Test/app.config @@ -4,7 +4,7 @@ - + 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 07b45c222..b6d3edb00 100644 --- a/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs +++ b/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Globalization; using System.IO; @@ -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,13 @@ 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 +56,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 +66,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 +76,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 +88,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 +99,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 +115,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 +127,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 +137,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; var response = Subject.Get(request); @@ -182,7 +190,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); @@ -196,7 +204,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); @@ -219,7 +227,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); @@ -236,7 +244,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); @@ -329,7 +337,7 @@ 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; requestSet.StoreRequestCookie = false; requestSet.StoreResponseCookie.Should().BeFalse(); @@ -348,7 +356,7 @@ 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.StoreRequestCookie = false; requestSet.StoreResponseCookie = true; @@ -527,7 +535,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)); @@ -547,7 +555,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); @@ -569,7 +577,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(); @@ -578,7 +586,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); @@ -602,7 +610,8 @@ 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; @@ -610,7 +619,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.Test/Http/UserAgentBuilderFixture.cs b/src/NzbDrone.Common.Test/Http/UserAgentBuilderFixture.cs new file mode 100644 index 000000000..1ff5db390 --- /dev/null +++ b/src/NzbDrone.Common.Test/Http/UserAgentBuilderFixture.cs @@ -0,0 +1,30 @@ +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Common.Http; +using NzbDrone.Test.Common; + +namespace NzbDrone.Common.Test.Http +{ + [TestFixture] + public class UserAgentBuilderFixture : TestBase + { + [Test] + public void should_get_user_agent_if_os_version_is_null() + { + Mocker.GetMock().SetupGet(c => c.Version).Returns((string)null); + Mocker.GetMock().SetupGet(c => c.Name).Returns("TestOS"); + + Subject.GetUserAgent(false).Should().NotBeNullOrWhiteSpace(); + } + + [Test] + public void should_get_use_os_family_if_name_is_null() + { + Mocker.GetMock().SetupGet(c => c.Version).Returns((string)null); + Mocker.GetMock().SetupGet(c => c.Name).Returns((string)null); + + Subject.GetUserAgent(false).Should().NotBeNullOrWhiteSpace(); + } + } +} diff --git a/src/NzbDrone.Common.Test/NzbDrone.Common.Test.csproj b/src/NzbDrone.Common.Test/NzbDrone.Common.Test.csproj index f82363128..f1840e5c7 100644 --- a/src/NzbDrone.Common.Test/NzbDrone.Common.Test.csproj +++ b/src/NzbDrone.Common.Test/NzbDrone.Common.Test.csproj @@ -92,6 +92,7 @@ + diff --git a/src/NzbDrone.Common/Composition/ContainerBuilderBase.cs b/src/NzbDrone.Common/Composition/ContainerBuilderBase.cs index 5a473fd74..8e0e67967 100644 --- a/src/NzbDrone.Common/Composition/ContainerBuilderBase.cs +++ b/src/NzbDrone.Common/Composition/ContainerBuilderBase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -13,12 +13,15 @@ namespace NzbDrone.Common.Composition { private readonly List _loadedTypes; - public IContainer Container { get; private set; } + protected IContainer Container { get; } - protected ContainerBuilderBase(IStartupContext args, params string[] assemblies) + protected ContainerBuilderBase(IStartupContext args, List assemblies) { _loadedTypes = new List(); + assemblies.Add(OsInfo.IsWindows ? "NzbDrone.Windows" : "NzbDrone.Mono"); + assemblies.Add("NzbDrone.Common"); + foreach (var assembly in assemblies) { _loadedTypes.AddRange(Assembly.Load(assembly).GetTypes()); diff --git a/src/NzbDrone.Common/Disk/DiskProviderBase.cs b/src/NzbDrone.Common/Disk/DiskProviderBase.cs index aaae3f032..c039f4f15 100644 --- a/src/NzbDrone.Common/Disk/DiskProviderBase.cs +++ b/src/NzbDrone.Common/Disk/DiskProviderBase.cs @@ -17,6 +17,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); @@ -87,7 +100,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..972eba39b 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/IOperatingSystemVersionInfo.cs b/src/NzbDrone.Common/EnvironmentInfo/IOperatingSystemVersionInfo.cs new file mode 100644 index 000000000..c0b4b6290 --- /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; } + } +} diff --git a/src/NzbDrone.Common/EnvironmentInfo/IOsVersionAdapter.cs b/src/NzbDrone.Common/EnvironmentInfo/IOsVersionAdapter.cs new file mode 100644 index 000000000..25a3cbf1f --- /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(); + } +} diff --git a/src/NzbDrone.Common/EnvironmentInfo/IPlatformInfo.cs b/src/NzbDrone.Common/EnvironmentInfo/IPlatformInfo.cs new file mode 100644 index 000000000..5136f90d2 --- /dev/null +++ b/src/NzbDrone.Common/EnvironmentInfo/IPlatformInfo.cs @@ -0,0 +1,50 @@ +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 static string PlatformName + { + get + { + if (IsDotNet) + { + return ".NET"; + } + + return "Mono"; + } + } + + public abstract Version Version { get; } + } +} diff --git a/src/NzbDrone.Common/EnvironmentInfo/IRuntimeInfo.cs b/src/NzbDrone.Common/EnvironmentInfo/IRuntimeInfo.cs index 2ef08901b..d387001ef 100644 --- a/src/NzbDrone.Common/EnvironmentInfo/IRuntimeInfo.cs +++ b/src/NzbDrone.Common/EnvironmentInfo/IRuntimeInfo.cs @@ -1,14 +1,13 @@ -namespace NzbDrone.Common.EnvironmentInfo +namespace NzbDrone.Common.EnvironmentInfo { public interface IRuntimeInfo { bool IsUserInteractive { get; } bool IsAdmin { get; } bool IsWindowsService { get; } - bool IsConsole { get; } - bool IsRunning { get; set; } + bool IsWindowsTray { get; } + 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..9df06528e 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; +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 @@ -90,4 +98,4 @@ namespace NzbDrone.Common.EnvironmentInfo Linux, Osx } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Common/EnvironmentInfo/OsVersionModel.cs b/src/NzbDrone.Common/EnvironmentInfo/OsVersionModel.cs new file mode 100644 index 000000000..c20865813 --- /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; } + } +} 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..d9908cb97 100644 --- a/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfoBase.cs +++ b/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; using System.IO; using System.Reflection; @@ -9,11 +9,11 @@ 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; @@ -28,10 +28,11 @@ namespace NzbDrone.Common.EnvironmentInfo if (entry != null) { ExecutingApplication = entry.Location; + IsWindowsTray = entry.ManifestModule.Name == $"{ProcessProvider.NZB_DRONE_PROCESS_NAME}.exe"; } } - static RuntimeInfoBase() + static RuntimeInfo() { IsProduction = InternalIsProduction(); } @@ -59,31 +60,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,21 +87,23 @@ namespace NzbDrone.Common.EnvironmentInfo } - try - { - var currentAssmeblyLocation = typeof(RuntimeInfoBase).Assembly.Location; - if(currentAssmeblyLocation.ToLower().Contains("_output"))return false; - } - catch - { + try + { + var currentAssmeblyLocation = typeof(RuntimeInfo).Assembly.Location; + if (currentAssmeblyLocation.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; return true; } + + public bool IsWindowsTray { get; private set; } } } 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 63dc57884..34fc833f7 100644 --- a/src/NzbDrone.Common/Extensions/PathExtensions.cs +++ b/src/NzbDrone.Common/Extensions/PathExtensions.cs @@ -1,7 +1,8 @@ -using System; +using System; 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; } @@ -275,4 +276,4 @@ namespace NzbDrone.Common.Extensions return Path.Combine(appFolderInfo.StartUpFolder, NLOG_CONFIG_FILE); } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Common/Http/Dispatchers/CurlHttpDispatcher.cs b/src/NzbDrone.Common/Http/Dispatchers/CurlHttpDispatcher.cs index 233e9a81f..ab8d5f09d 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; } 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 660daad5a..26d92d55c 100644 --- a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs +++ b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs @@ -13,22 +13,35 @@ 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) { - HttpWebResponse httpWebResponse = null; - HttpWebRequest webRequest = null; - try + var webRequest = (HttpWebRequest)WebRequest.Create((Uri)request.Url); + + // Deflate is not a standard and could break depending on implementation. + // we should just stick with the more compatible Gzip + //http://stackoverflow.com/questions/8490718/how-to-decompress-stream-deflated-with-java-util-zip-deflater-in-net + webRequest.AutomaticDecompression = DecompressionMethods.GZip; + + webRequest.Method = request.Method.ToString(); + webRequest.UserAgent = _userAgentBuilder.GetUserAgent(request.UseSimplifiedUserAgent); + webRequest.KeepAlive = request.ConnectionKeepAlive; + webRequest.AllowAutoRedirect = false; + webRequest.CookieContainer = cookies; + + if (request.RequestTimeout != TimeSpan.Zero) { webRequest = (HttpWebRequest) WebRequest.Create((Uri) request.Url); - if (OsInfo.IsMonoRuntime) + if (PlatformInfo.IsMonoRuntime) { // On Mono GZipStream/DeflateStream leaks memory if an exception is thrown, use an intermediate buffer in that case. webRequest.AutomaticDecompression = DecompressionMethods.None; @@ -98,7 +111,7 @@ namespace NzbDrone.Common.Http.Dispatchers { data = responseStream.ToBytes(); - if (OsInfo.IsMonoRuntime && httpWebResponse.ContentEncoding == "gzip") + if (PlatformInfo.IsMonoRuntime && httpWebResponse.ContentEncoding == "gzip") { using (var compressedStream = new MemoryStream(data)) using (var gzip = new GZipStream(compressedStream, CompressionMode.Decompress)) diff --git a/src/NzbDrone.Common/Http/HttpClient.cs b/src/NzbDrone.Common/Http/HttpClient.cs index 1c234c427..3189f3539 100644 --- a/src/NzbDrone.Common/Http/HttpClient.cs +++ b/src/NzbDrone.Common/Http/HttpClient.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -31,12 +31,14 @@ 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; @@ -71,7 +73,7 @@ namespace NzbDrone.Common.Http while (response.HasHttpRedirect); } - if (response.HasHttpRedirect && !RuntimeInfoBase.IsProduction) + if (response.HasHttpRedirect && !RuntimeInfo.IsProduction) { _logger.Error("Server requested a redirect to [{0}] while in developer mode. Update the request URL to avoid this redirect.", response.Headers["Location"]); } diff --git a/src/NzbDrone.Common/Http/HttpRequest.cs b/src/NzbDrone.Common/Http/HttpRequest.cs index f0f2d053c..61b46e53f 100644 --- a/src/NzbDrone.Common/Http/HttpRequest.cs +++ b/src/NzbDrone.Common/Http/HttpRequest.cs @@ -17,7 +17,7 @@ namespace NzbDrone.Common.Http IgnorePersistentCookies = false; 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 f0cff30e9..9626cd9f7 100644 --- a/src/NzbDrone.Common/Http/UserAgentBuilder.cs +++ b/src/NzbDrone.Common/Http/UserAgentBuilder.cs @@ -2,19 +2,39 @@ 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("Radarr/{0} ({1} {2})", - BuildInfo.Version, - OsInfo.Os, OsInfo.Version.ToString(2)); + if (simplified) + { + return _userAgentSimplified; + } - UserAgentSimplified = string.Format("Radarr/{0}", - BuildInfo.Version.ToString(2)); + return _userAgent; + } + + public UserAgentBuilder(IOsInfo osInfo) + { + var osName = OsInfo.Os.ToString(); + + if (!string.IsNullOrWhiteSpace(osInfo.Name)) + { + osName = osInfo.Name.ToLower(); + } + + var osVersion = osInfo.Version?.ToLower(); + + _userAgent = $"Radarr/{BuildInfo.Version} ({osName} {osVersion})"; + _userAgentSimplified = $"Radarr/{BuildInfo.Version.ToString(2)}"; } } } 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 2fee91f56..99032f010 100644 --- a/src/NzbDrone.Common/Instrumentation/GlobalExceptionHandlers.cs +++ b/src/NzbDrone.Common/Instrumentation/GlobalExceptionHandlers.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading.Tasks; using NLog; using NzbDrone.Common.EnvironmentInfo; @@ -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) @@ -51,4 +51,4 @@ namespace NzbDrone.Common.Instrumentation Logger.Fatal(exception, "EPIC FAIL: " + exception.Message); } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Common/Instrumentation/NzbDroneLogger.cs b/src/NzbDrone.Common/Instrumentation/NzbDroneLogger.cs index 8d319a77a..35d8d0e87 100644 --- a/src/NzbDrone.Common/Instrumentation/NzbDroneLogger.cs +++ b/src/NzbDrone.Common/Instrumentation/NzbDroneLogger.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; using System.IO; using LogentriesNLog; @@ -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 87b7a0c01..960fc5f2d 100644 --- a/src/NzbDrone.Common/NzbDrone.Common.csproj +++ b/src/NzbDrone.Common/NzbDrone.Common.csproj @@ -94,6 +94,10 @@ + + + + @@ -125,13 +129,12 @@ - + - @@ -194,7 +197,6 @@ - diff --git a/src/NzbDrone.Common/Processes/ProcessProvider.cs b/src/NzbDrone.Common/Processes/ProcessProvider.cs index a6a837f8c..83a42ac5d 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"; @@ -192,7 +192,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.Common/app.config b/src/NzbDrone.Common/app.config index 81a0194c8..b69f873e9 100644 --- a/src/NzbDrone.Common/app.config +++ b/src/NzbDrone.Common/app.config @@ -4,7 +4,7 @@ - + diff --git a/src/NzbDrone.Core.Test/Framework/CoreTest.cs b/src/NzbDrone.Core.Test/Framework/CoreTest.cs index dd9221b02..67b6f6e39 100644 --- a/src/NzbDrone.Core.Test/Framework/CoreTest.cs +++ b/src/NzbDrone.Core.Test/Framework/CoreTest.cs @@ -1,9 +1,9 @@ -using System.Collections.Specialized; -using System.Security.AccessControl; using Moq; +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; @@ -24,12 +24,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 RadarrCloudRequestBuilder()); } diff --git a/src/NzbDrone.Core.Test/HealthCheck/Checks/MonoVersionCheckFixture.cs b/src/NzbDrone.Core.Test/HealthCheck/Checks/MonoVersionCheckFixture.cs index 420e0268a..052d4f609 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,12 @@ 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 0f1c4a5d9..cfe4bf9df 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/App.config b/src/NzbDrone.Core/App.config index 9458f19c1..acb53b6de 100644 --- a/src/NzbDrone.Core/App.config +++ b/src/NzbDrone.Core/App.config @@ -5,7 +5,7 @@ - + diff --git a/src/NzbDrone.Core/Configuration/ConfigService.cs b/src/NzbDrone.Core/Configuration/ConfigService.cs index e107a107a..b79750ff3 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; @@ -373,7 +374,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..f2688e2f9 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; 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) { diff --git a/src/NzbDrone.Core/Lifecycle/ApplicationShutdownRequested.cs b/src/NzbDrone.Core/Lifecycle/ApplicationShutdownRequested.cs index 50446ed1d..535df3d9f 100644 --- a/src/NzbDrone.Core/Lifecycle/ApplicationShutdownRequested.cs +++ b/src/NzbDrone.Core/Lifecycle/ApplicationShutdownRequested.cs @@ -1,18 +1,14 @@ -using NzbDrone.Common.Messaging; +using NzbDrone.Common.Messaging; 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; } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Core/MediaFiles/UpdateMovieFileService.cs b/src/NzbDrone.Core/MediaFiles/UpdateMovieFileService.cs index b7b9c7d00..851ad8076 100644 --- a/src/NzbDrone.Core/MediaFiles/UpdateMovieFileService.cs +++ b/src/NzbDrone.Core/MediaFiles/UpdateMovieFileService.cs @@ -189,7 +189,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 545c00258..ce28b10c9 100644 --- a/src/NzbDrone.Core/Rest/RestClientFactory.cs +++ b/src/NzbDrone.Core/Rest/RestClientFactory.cs @@ -7,12 +7,10 @@ namespace NzbDrone.Core.Rest { public static RestClient BuildClient(string baseUrl) { - var restClient = new RestClient(baseUrl); - - restClient.UserAgent = string.Format("Radarr/{0} (RestSharp/{1}; {2}/{3})", - BuildInfo.Version, - restClient.GetType().Assembly.GetName().Version, - OsInfo.Os, OsInfo.Version.ToString(2)); + var restClient = new RestClient(baseUrl) + { + UserAgent = $"Radarr/{BuildInfo.Version} ({OsInfo.Os})" + }; return restClient; } diff --git a/src/NzbDrone.Core/Update/UpdateCheckService.cs b/src/NzbDrone.Core/Update/UpdateCheckService.cs index 807250780..46e4b6b63 100644 --- a/src/NzbDrone.Core/Update/UpdateCheckService.cs +++ b/src/NzbDrone.Core/Update/UpdateCheckService.cs @@ -1,4 +1,3 @@ -using NLog; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Core.Configuration; @@ -14,16 +13,11 @@ 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() @@ -31,4 +25,4 @@ namespace NzbDrone.Core.Update return _updatePackageProvider.GetLatestUpdate(_configFileProvider.Branch, BuildInfo.Version); } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Core/Update/UpdatePackageProvider.cs b/src/NzbDrone.Core/Update/UpdatePackageProvider.cs index 96959e5af..84d0c5057 100644 --- a/src/NzbDrone.Core/Update/UpdatePackageProvider.cs +++ b/src/NzbDrone.Core/Update/UpdatePackageProvider.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using NzbDrone.Common.Cloud; using NzbDrone.Common.EnvironmentInfo; @@ -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, IRadarrCloudRequestBuilder requestBuilder) + public UpdatePackageProvider(IHttpClient httpClient, IRadarrCloudRequestBuilder 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(); @@ -53,4 +57,4 @@ namespace NzbDrone.Core.Update return updates.Resource; } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Host/AccessControl/UrlAclAdapter.cs b/src/NzbDrone.Host/AccessControl/UrlAclAdapter.cs index 7c61f4320..ff365c0a4 100644 --- a/src/NzbDrone.Host/AccessControl/UrlAclAdapter.cs +++ b/src/NzbDrone.Host/AccessControl/UrlAclAdapter.cs @@ -20,6 +20,7 @@ namespace Radarr.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,7 +31,7 @@ namespace Radarr.Host.AccessControl } } - private List InternalUrls { get; set; } + private List InternalUrls { get; } private List RegisteredUrls { get; set; } private static readonly Regex UrlAclRegex = new Regex(@"(?https?)\:\/\/(?
.+?)\:(?\d+)/(?.+)?", RegexOptions.Compiled | RegexOptions.IgnoreCase); @@ -38,19 +39,26 @@ namespace Radarr.Host.AccessControl 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(); - RegisteredUrls = GetRegisteredUrls(); + RegisteredUrls = new List(); } public void ConfigureUrls() { + if (RegisteredUrls.Empty()) + { + GetRegisteredUrls(); + } + var localHostHttpUrls = BuildUrlAcls("http", "localhost", _configFileProvider.Port); var interfaceHttpUrls = BuildUrlAcls("http", _configFileProvider.BindAddress, _configFileProvider.Port); @@ -105,7 +113,8 @@ namespace Radarr.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) { @@ -124,19 +133,24 @@ namespace Radarr.Host.AccessControl c.UrlBase == urlAcl.UrlBase); } - private List GetRegisteredUrls() + private void GetRegisteredUrls() { if (OsInfo.IsNotWindows) { - return new List(); + return; + } + + if (RegisteredUrls.Any()) + { + return; } var arguments = string.Format("http show urlacl"); var output = _netshProvider.Run(arguments); - if (output == null || !output.Standard.Any()) return new List(); + if (output == null || !output.Standard.Any()) return; - return output.Standard.Select(line => + RegisteredUrls = output.Standard.Select(line => { var match = UrlAclRegex.Match(line.Content); diff --git a/src/NzbDrone.Host/ApplicationServer.cs b/src/NzbDrone.Host/ApplicationServer.cs index 5027b6be5..55717e798 100644 --- a/src/NzbDrone.Host/ApplicationServer.cs +++ b/src/NzbDrone.Host/ApplicationServer.cs @@ -58,7 +58,7 @@ namespace Radarr.Host //_cancelHandler = new CancelHandler(); } - _runtimeInfo.IsRunning = true; + _runtimeInfo.IsExiting = false; DbFactory.RegisterDatabase(_container); _hostController.StartServer(); @@ -87,7 +87,7 @@ namespace Radarr.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/MainAppContainerBuilder.cs b/src/NzbDrone.Host/MainAppContainerBuilder.cs index a82d3d836..e14560c38 100644 --- a/src/NzbDrone.Host/MainAppContainerBuilder.cs +++ b/src/NzbDrone.Host/MainAppContainerBuilder.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Nancy.Bootstrapper; using NzbDrone.Api; using NzbDrone.Common.Composition; @@ -15,26 +15,15 @@ namespace Radarr.Host var assemblies = new List { "Radarr.Host", - "NzbDrone.Common", "NzbDrone.Core", "NzbDrone.Api", "NzbDrone.SignalR" }; - if (OsInfo.IsWindows) - { - assemblies.Add("NzbDrone.Windows"); - } - - else - { - assemblies.Add("NzbDrone.Mono"); - } - - return new MainAppContainerBuilder(args, assemblies.ToArray()).Container; + return new MainAppContainerBuilder(args, assemblies).Container; } - private MainAppContainerBuilder(StartupContext args, string[] assemblies) + private MainAppContainerBuilder(StartupContext args, List assemblies) : base(args, assemblies) { AutoRegisterImplementations(); @@ -43,4 +32,4 @@ namespace Radarr.Host Container.Register(); } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Host/Router.cs b/src/NzbDrone.Host/Router.cs index 8009ccb70..cfc925929 100644 --- a/src/NzbDrone.Host/Router.cs +++ b/src/NzbDrone.Host/Router.cs @@ -1,5 +1,6 @@ -using NLog; +using NLog; using NzbDrone.Common; +using NzbDrone.Common.EnvironmentInfo; namespace Radarr.Host { @@ -8,14 +9,16 @@ namespace Radarr.Host private readonly INzbDroneServiceFactory _nzbDroneServiceFactory; private readonly IServiceProvider _serviceProvider; private readonly IConsoleService _consoleService; + private readonly IRuntimeInfo _runtimeInfo; private readonly Logger _logger; public Router(INzbDroneServiceFactory nzbDroneServiceFactory, IServiceProvider serviceProvider, - IConsoleService consoleService, Logger logger) + IConsoleService consoleService, IRuntimeInfo runtimeInfo, Logger logger) { _nzbDroneServiceFactory = nzbDroneServiceFactory; _serviceProvider = serviceProvider; _consoleService = consoleService; + _runtimeInfo = runtimeInfo; _logger = logger; } @@ -34,7 +37,7 @@ namespace Radarr.Host case ApplicationModes.Interactive: { - _logger.Debug("Console selected"); + _logger.Debug(_runtimeInfo.IsWindowsTray ? "Tray selected" : "Console selected"); _nzbDroneServiceFactory.Start(); break; } diff --git a/src/NzbDrone.Host/SpinService.cs b/src/NzbDrone.Host/SpinService.cs index ae35590fd..0604134b2 100644 --- a/src/NzbDrone.Host/SpinService.cs +++ b/src/NzbDrone.Host/SpinService.cs @@ -1,4 +1,4 @@ -using System.Threading; +using System.Threading; using NLog; using NLog.Common; using NzbDrone.Common.EnvironmentInfo; @@ -28,7 +28,7 @@ namespace Radarr.Host public void Spin() { - while (_runtimeInfo.IsRunning) + while (!_runtimeInfo.IsExiting) { Thread.Sleep(1000); } diff --git a/src/NzbDrone.Host/app.config b/src/NzbDrone.Host/app.config index d2e101ccc..3e7fd958a 100644 --- a/src/NzbDrone.Host/app.config +++ b/src/NzbDrone.Host/app.config @@ -14,7 +14,7 @@ - + diff --git a/src/NzbDrone.Libraries.Test/app.config b/src/NzbDrone.Libraries.Test/app.config index c7d36b5e3..077a6a061 100644 --- a/src/NzbDrone.Libraries.Test/app.config +++ b/src/NzbDrone.Libraries.Test/app.config @@ -4,7 +4,7 @@ - + diff --git a/src/NzbDrone.Mono.Test/EnvironmentInfo/MonoPlatformInfoFixture.cs b/src/NzbDrone.Mono.Test/EnvironmentInfo/MonoPlatformInfoFixture.cs new file mode 100644 index 000000000..a1bcfd1cd --- /dev/null +++ b/src/NzbDrone.Mono.Test/EnvironmentInfo/MonoPlatformInfoFixture.cs @@ -0,0 +1,23 @@ +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().BeOneOf(4, 5); + if (Subject.Version.Major == 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..383db510b --- /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(); + } + } +} 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..56fe88bc0 --- /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()); + } + } +} 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..798b99d8f --- /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"); + + } + } +} 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 d65cd8916..74d464503 100644 --- a/src/NzbDrone.Mono.Test/NzbDrone.Mono.Test.csproj +++ b/src/NzbDrone.Mono.Test/NzbDrone.Mono.Test.csproj @@ -82,10 +82,26 @@ + + + + + + Always + + + Always + + + Always + + + Always + diff --git a/src/NzbDrone.Mono.Test/app.config b/src/NzbDrone.Mono.Test/app.config index 366f30bc3..182ee5626 100644 --- a/src/NzbDrone.Mono.Test/app.config +++ b/src/NzbDrone.Mono.Test/app.config @@ -8,7 +8,7 @@ - + diff --git a/src/NzbDrone.Mono/EnvironmentInfo/MonoPlatformInfo.cs b/src/NzbDrone.Mono/EnvironmentInfo/MonoPlatformInfo.cs new file mode 100644 index 000000000..d1a228b65 --- /dev/null +++ b/src/NzbDrone.Mono/EnvironmentInfo/MonoPlatformInfo.cs @@ -0,0 +1,46 @@ +using System; +using System.Reflection; +using System.Text.RegularExpressions; +using NLog; +using NzbDrone.Common.EnvironmentInfo; + +namespace NzbDrone.Mono.EnvironmentInfo +{ + public class MonoPlatformInfo : PlatformInfo + { + private static readonly Regex VersionRegex = new Regex(@"(?<=\W|^)(?\d+\.\d+(\.\d+)?(\.\d+)?)(?=\W)", RegexOptions.Compiled | RegexOptions.IgnoreCase); + public override Version Version { get; } + + public MonoPlatformInfo(Logger logger) + { + var runTimeVersion = new Version(); + + try + { + var type = Type.GetType("Mono.Runtime"); + + if (type != null) + { + var displayNameMethod = type.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static); + if (displayNameMethod != null) + { + var displayName = displayNameMethod.Invoke(null, null).ToString(); + var versionMatch = VersionRegex.Match(displayName); + + if (versionMatch.Success) + { + runTimeVersion = new Version(versionMatch.Groups["version"].Value); + } + } + } + } + catch (Exception ex) + { + logger.Error(ex, "Unable to get mono version"); + } + + + Version = runTimeVersion; + } + } +} diff --git a/src/NzbDrone.Mono/EnvironmentInfo/MonoRuntimeProvider.cs b/src/NzbDrone.Mono/EnvironmentInfo/MonoRuntimeProvider.cs deleted file mode 100644 index b9884df77..000000000 --- a/src/NzbDrone.Mono/EnvironmentInfo/MonoRuntimeProvider.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Reflection; -using NLog; -using NzbDrone.Common.EnvironmentInfo; - -namespace NzbDrone.Mono.EnvironmentInfo -{ - public class MonoRuntimeProvider : RuntimeInfoBase - { - private readonly Logger _logger; - - public MonoRuntimeProvider(Common.IServiceProvider serviceProvider, Logger logger) - :base(serviceProvider, logger) - { - _logger = logger; - } - - public override string RuntimeVersion - { - get - { - try - { - var type = Type.GetType("Mono.Runtime"); - - if (type != null) - { - var displayName = type.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static); - - if (displayName != null) - { - return displayName.Invoke(null, null).ToString(); - } - } - } - catch (Exception ex) - { - _logger.Error(ex, "Unable to get mono version: " + ex.Message); - } - - return string.Empty; - } - } - } -} diff --git a/src/NzbDrone.Mono/EnvironmentInfo/VersionAdapters/IssueFileVersionAdapter.cs b/src/NzbDrone.Mono/EnvironmentInfo/VersionAdapters/IssueFileVersionAdapter.cs new file mode 100644 index 000000000..7410a76d0 --- /dev/null +++ b/src/NzbDrone.Mono/EnvironmentInfo/VersionAdapters/IssueFileVersionAdapter.cs @@ -0,0 +1,52 @@ +using System.IO; +using System.Linq; +using NzbDrone.Common.Disk; +using NzbDrone.Common.EnvironmentInfo; + +namespace NzbDrone.Mono.EnvironmentInfo.VersionAdapters +{ + public class IssueFileVersionAdapter : IOsVersionAdapter + { + private readonly IDiskProvider _diskProvider; + + public IssueFileVersionAdapter(IDiskProvider diskProvider) + { + _diskProvider = diskProvider; + } + + public OsVersionModel Read() + { + if (!_diskProvider.FolderExists("/etc/")) + { + return null; + } + + var issueFile = _diskProvider.GetFiles("/etc/", SearchOption.TopDirectoryOnly).SingleOrDefault(c => c.EndsWith("/issue")); + + if (issueFile == null) + { + return null; + } + + var fileContent = _diskProvider.ReadAllText(issueFile); + + + // Ubuntu 14.04.5 LTS \n \l + // Ubuntu 16.04.1 LTS \n \l + + // Fedora/Centos + // Kernel \r on an \m (\l) + + // Arch Linux \r (\l) + // Debian GNU/Linux 8 \n \l + if (fileContent.Contains("Arch Linux")) + { + return new OsVersionModel("Arch", "1.0", "Arch Linux"); + } + + return null; + } + + public bool Enabled => OsInfo.IsLinux; + } +} diff --git a/src/NzbDrone.Mono/EnvironmentInfo/VersionAdapters/MacOsVersionAdapter.cs b/src/NzbDrone.Mono/EnvironmentInfo/VersionAdapters/MacOsVersionAdapter.cs new file mode 100644 index 000000000..c9521588e --- /dev/null +++ b/src/NzbDrone.Mono/EnvironmentInfo/VersionAdapters/MacOsVersionAdapter.cs @@ -0,0 +1,69 @@ +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using NLog; +using NzbDrone.Common.Disk; +using NzbDrone.Common.EnvironmentInfo; + +namespace NzbDrone.Mono.EnvironmentInfo.VersionAdapters +{ + public class MacOsVersionAdapter : IOsVersionAdapter + { + private static readonly Regex DarwinVersionRegex = new Regex("(?10\\.\\d{1,2}\\.?\\d{0,2}?)<\\/string>", + RegexOptions.Compiled | + RegexOptions.IgnoreCase + ); + + private const string PLIST_DIR = "/System/Library/CoreServices/"; + + + private readonly IDiskProvider _diskProvider; + private readonly Logger _logger; + + public MacOsVersionAdapter(IDiskProvider diskProvider, Logger logger) + { + _diskProvider = diskProvider; + _logger = logger; + } + + public OsVersionModel Read() + { + var version = "10.0"; + + if (!_diskProvider.FolderExists(PLIST_DIR)) + { + _logger.Debug("Directory {0} doesn't exist", PLIST_DIR); + return null; + } + + var allFiles = _diskProvider.GetFiles(PLIST_DIR, SearchOption.TopDirectoryOnly); + + var versionFile = allFiles.SingleOrDefault(c => + c.EndsWith("SystemVersion.plist") || + c.EndsWith("ServerVersion.plist") + ); + + if (string.IsNullOrWhiteSpace(versionFile)) + { + _logger.Debug("Couldn't find version plist file in {0}", PLIST_DIR); + return null; + } + + var text = _diskProvider.ReadAllText(versionFile); + var match = DarwinVersionRegex.Match(text); + + + + if (match.Success) + { + version = match.Groups["version"].Value; + } + + var name = versionFile.Contains("Server") ? "macOS Server" : "macOS"; + + return new OsVersionModel(name, version); + } + + public bool Enabled => OsInfo.IsOsx; + } +} diff --git a/src/NzbDrone.Mono/EnvironmentInfo/VersionAdapters/ReleaseFileVersionAdapter.cs b/src/NzbDrone.Mono/EnvironmentInfo/VersionAdapters/ReleaseFileVersionAdapter.cs new file mode 100644 index 000000000..d0b5cb3be --- /dev/null +++ b/src/NzbDrone.Mono/EnvironmentInfo/VersionAdapters/ReleaseFileVersionAdapter.cs @@ -0,0 +1,79 @@ +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using NzbDrone.Common.Disk; +using NzbDrone.Common.EnvironmentInfo; + +namespace NzbDrone.Mono.EnvironmentInfo.VersionAdapters +{ + public class ReleaseFileVersionAdapter : IOsVersionAdapter + { + private readonly IDiskProvider _diskProvider; + + public ReleaseFileVersionAdapter(IDiskProvider diskProvider) + { + _diskProvider = diskProvider; + } + + public OsVersionModel Read() + { + if (!_diskProvider.FolderExists("/etc/")) + { + return null; + } + + var releaseFiles = _diskProvider.GetFiles("/etc/", SearchOption.TopDirectoryOnly).Where(c => c.EndsWith("release")).ToList(); + + var name = "Linux"; + var fullName = ""; + var version = ""; + + bool success = false; + + foreach (var releaseFile in releaseFiles) + { + var fileContent = _diskProvider.ReadAllText(releaseFile); + var lines = Regex.Split(fileContent, "\r\n|\r|\n"); ; + + foreach (var line in lines) + { + var parts = line.Split('='); + if (parts.Length >= 2) + { + var key = parts[0]; + var value = parts[1]; + + if (!string.IsNullOrWhiteSpace(value)) + { + switch (key) + { + case "ID": + success = true; + name = value; + break; + case "PRETTY_NAME": + success = true; + fullName = value; + break; + case "VERSION_ID": + success = true; + version = value; + break; + } + } + } + } + } + + if (!success) + { + return null; + } + + return new OsVersionModel(name, version, fullName); + + } + + public bool Enabled => OsInfo.IsLinux; + } +} diff --git a/src/NzbDrone.Mono/EnvironmentInfo/VersionAdapters/SynologyVersionAdapter.cs b/src/NzbDrone.Mono/EnvironmentInfo/VersionAdapters/SynologyVersionAdapter.cs new file mode 100644 index 000000000..02bba34b1 --- /dev/null +++ b/src/NzbDrone.Mono/EnvironmentInfo/VersionAdapters/SynologyVersionAdapter.cs @@ -0,0 +1,78 @@ +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using NzbDrone.Common.Disk; +using NzbDrone.Common.EnvironmentInfo; + +namespace NzbDrone.Mono.EnvironmentInfo.VersionAdapters +{ + public class SynologyVersionAdapter : IOsVersionAdapter + { + private readonly IDiskProvider _diskProvider; + private const string NAME = "DSM"; + private const string FULL_NAME = "Synology DSM"; + + + public SynologyVersionAdapter(IDiskProvider diskProvider) + { + _diskProvider = diskProvider; + } + + public OsVersionModel Read() + { + if (!_diskProvider.FolderExists("/etc.defaults/")) + { + return null; + } + + var versionFile = _diskProvider.GetFiles("/etc.defaults/", SearchOption.TopDirectoryOnly).SingleOrDefault(c => c.EndsWith("VERSION")); + + if (versionFile == null) + { + return null; + } + + var version = ""; + var major = ""; + var minor = "0"; + + var fileContent = _diskProvider.ReadAllText(versionFile); + var lines = Regex.Split(fileContent, "\r\n|\r|\n"); ; + + foreach (var line in lines) + { + var parts = line.Split('='); + if (parts.Length >= 2) + { + var key = parts[0]; + var value = parts[1].Trim('"'); + + if (!string.IsNullOrWhiteSpace(value)) + { + switch (key) + { + case "productversion": + version = value; + break; + case "majorversion": + major = value; + break; + case "minorversion": + minor = value; + break; + } + } + } + } + + if (string.IsNullOrWhiteSpace(version) && !string.IsNullOrWhiteSpace(major)) + { + version = $"{major}.{minor}"; + } + + return new OsVersionModel(NAME, version, $"{FULL_NAME} {version}"); + } + + public bool Enabled => OsInfo.IsLinux; + } +} diff --git a/src/NzbDrone.Mono/NzbDrone.Mono.csproj b/src/NzbDrone.Mono/NzbDrone.Mono.csproj index 4acbbbfc0..f44d33c11 100644 --- a/src/NzbDrone.Mono/NzbDrone.Mono.csproj +++ b/src/NzbDrone.Mono/NzbDrone.Mono.csproj @@ -79,9 +79,13 @@ - + + + + + @@ -92,6 +96,7 @@ + diff --git a/src/NzbDrone.Mono/app.config b/src/NzbDrone.Mono/app.config new file mode 100644 index 000000000..041b35da6 --- /dev/null +++ b/src/NzbDrone.Mono/app.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/NzbDrone.SignalR/app.config b/src/NzbDrone.SignalR/app.config index cbff67135..18c0498d6 100644 --- a/src/NzbDrone.SignalR/app.config +++ b/src/NzbDrone.SignalR/app.config @@ -4,7 +4,7 @@ - + diff --git a/src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs b/src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs index 98faebac2..c78a27e40 100644 --- a/src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs +++ b/src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs @@ -1,5 +1,3 @@ - - using System; using System.Collections.Generic; using System.Diagnostics; @@ -151,7 +149,7 @@ namespace NzbDrone.Test.Common.AutoMoq private Mock TheRegisteredMockForThisType(Type type) where T : class { - return (Mock)_registeredMocks.Where(x => x.Key == type).First().Value; + return (Mock)_registeredMocks.First(x => x.Key == type).Value; } private void CreateANewMockAndRegisterIt(Type type, MockBehavior behavior) where T : class @@ -190,4 +188,4 @@ namespace NzbDrone.Test.Common.AutoMoq #endregion } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Test.Common/TestBase.cs b/src/NzbDrone.Test.Common/TestBase.cs index 7efe432e9..14310f7f3 100644 --- a/src/NzbDrone.Test.Common/TestBase.cs +++ b/src/NzbDrone.Test.Common/TestBase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Threading; using FluentAssertions; @@ -133,7 +133,7 @@ namespace NzbDrone.Test.Common protected void MonoOnly() { - if (OsInfo.IsWindows) + if (!PlatformInfo.IsMono) { throw new IgnoreException("mono specific test"); } diff --git a/src/NzbDrone.Update/UpdateContainerBuilder.cs b/src/NzbDrone.Update/UpdateContainerBuilder.cs index aeaa130ad..47fcbe598 100644 --- a/src/NzbDrone.Update/UpdateContainerBuilder.cs +++ b/src/NzbDrone.Update/UpdateContainerBuilder.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using NzbDrone.Common.Composition; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Http.Dispatchers; @@ -7,7 +7,7 @@ namespace NzbDrone.Update { public class UpdateContainerBuilder : ContainerBuilderBase { - private UpdateContainerBuilder(IStartupContext startupContext, string[] assemblies) + private UpdateContainerBuilder(IStartupContext startupContext, List assemblies) : base(startupContext, assemblies) { Container.Register(); @@ -17,22 +17,10 @@ namespace NzbDrone.Update { var assemblies = new List { - "Radarr.Update", - "NzbDrone.Common" + "Radarr.Update" }; - if (OsInfo.IsWindows) - { - assemblies.Add("NzbDrone.Windows"); - } - - else - { - assemblies.Add("NzbDrone.Mono"); - } - - return new UpdateContainerBuilder(startupContext, assemblies.ToArray()).Container; + return new UpdateContainerBuilder(startupContext, assemblies).Container; } } } - \ No newline at end of file diff --git a/src/NzbDrone.Update/UpdateEngine/DetectApplicationType.cs b/src/NzbDrone.Update/UpdateEngine/DetectApplicationType.cs index e7507b25d..9d2df5af2 100644 --- a/src/NzbDrone.Update/UpdateEngine/DetectApplicationType.cs +++ b/src/NzbDrone.Update/UpdateEngine/DetectApplicationType.cs @@ -24,7 +24,7 @@ namespace NzbDrone.Update.UpdateEngine { if (OsInfo.IsNotWindows) { - //Tehcnically its the console, but its been renamed for mono (Linux/OS X) + //Tehcnically it is the console, but it has been renamed for mono (Linux/OS X) return AppType.Normal; } @@ -42,4 +42,4 @@ namespace NzbDrone.Update.UpdateEngine return AppType.Normal; } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Update/app.config b/src/NzbDrone.Update/app.config index 988bbe69b..6186eb4b4 100644 --- a/src/NzbDrone.Update/app.config +++ b/src/NzbDrone.Update/app.config @@ -11,7 +11,7 @@ - + diff --git a/src/NzbDrone.Windows.Test/EnvironmentInfo/DotNetPlatformInfoFixture.cs b/src/NzbDrone.Windows.Test/EnvironmentInfo/DotNetPlatformInfoFixture.cs new file mode 100644 index 000000000..2cc9856f3 --- /dev/null +++ b/src/NzbDrone.Windows.Test/EnvironmentInfo/DotNetPlatformInfoFixture.cs @@ -0,0 +1,19 @@ +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Test.Common; +using NzbDrone.Windows.EnvironmentInfo; + +namespace NzbDrone.Windows.Test.EnvironmentInfo +{ + [TestFixture] + [Platform("Win")] + public class DotNetPlatformInfoFixture : 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.Windows.Test/EnvironmentInfo/WindowsVersionInfoFixture.cs b/src/NzbDrone.Windows.Test/EnvironmentInfo/WindowsVersionInfoFixture.cs new file mode 100644 index 000000000..28ad1728d --- /dev/null +++ b/src/NzbDrone.Windows.Test/EnvironmentInfo/WindowsVersionInfoFixture.cs @@ -0,0 +1,23 @@ +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Test.Common; +using NzbDrone.Windows.EnvironmentInfo; + +namespace NzbDrone.Windows.Test.EnvironmentInfo +{ + [TestFixture] + [Platform("Win")] + public class WindowsVersionInfoFixture : TestBase + { + [Test] + public void should_get_windows_version() + { + var info = Subject.Read(); + info.Version.Should().NotBeNullOrWhiteSpace(); + info.Name.Should().Contain("Windows"); + info.FullName.Should().Contain("Windows"); + info.FullName.Should().Contain("NT"); + info.FullName.Should().Contain(info.Version); + } + } +} diff --git a/src/NzbDrone.Windows.Test/NzbDrone.Windows.Test.csproj b/src/NzbDrone.Windows.Test/NzbDrone.Windows.Test.csproj index 71bc3cbd6..1b2a5e6ab 100644 --- a/src/NzbDrone.Windows.Test/NzbDrone.Windows.Test.csproj +++ b/src/NzbDrone.Windows.Test/NzbDrone.Windows.Test.csproj @@ -75,6 +75,8 @@ + + diff --git a/src/NzbDrone.Windows.Test/app.config b/src/NzbDrone.Windows.Test/app.config index 366f30bc3..182ee5626 100644 --- a/src/NzbDrone.Windows.Test/app.config +++ b/src/NzbDrone.Windows.Test/app.config @@ -8,7 +8,7 @@ - + diff --git a/src/NzbDrone.Windows/EnvironmentInfo/DotNetPlatformInfo.cs b/src/NzbDrone.Windows/EnvironmentInfo/DotNetPlatformInfo.cs new file mode 100644 index 000000000..929ad2f03 --- /dev/null +++ b/src/NzbDrone.Windows/EnvironmentInfo/DotNetPlatformInfo.cs @@ -0,0 +1,70 @@ +using System; +using Microsoft.Win32; +using NLog; +using NzbDrone.Common.EnvironmentInfo; + +namespace NzbDrone.Windows.EnvironmentInfo +{ + public class DotNetPlatformInfo : PlatformInfo + { + private readonly Logger _logger; + + public DotNetPlatformInfo(Logger logger) + { + _logger = logger; + var version = GetFrameworkVersion(); + Environment.SetEnvironmentVariable("RUNTIME_VERSION", version.ToString()); + Version = version; + } + + public override Version Version { get; } + + private Version GetFrameworkVersion() + { + try + { + const string subkey = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\"; + using (var ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(subkey)) + { + if (ndpKey == null) + { + return new Version(4, 0); + } + + var releaseKey = (int)ndpKey.GetValue("Release"); + + if (releaseKey >= 394802) + { + return new Version(4, 6, 2); + } + if (releaseKey >= 394254) + { + return new Version(4, 6, 1); + } + if (releaseKey >= 393295) + { + return new Version(4, 6); + } + if (releaseKey >= 379893) + { + return new Version(4, 5, 2); + } + if (releaseKey >= 378675) + { + return new Version(4, 5, 1); + } + if (releaseKey >= 378389) + { + return new Version(4, 5); + } + } + } + catch (Exception e) + { + _logger.Error(e, "Couldnt get .NET framework version"); + } + + return new Version(4, 0); + } + } +} diff --git a/src/NzbDrone.Windows/EnvironmentInfo/DotNetRuntimeProvider.cs b/src/NzbDrone.Windows/EnvironmentInfo/DotNetRuntimeProvider.cs deleted file mode 100644 index 8e0330f1f..000000000 --- a/src/NzbDrone.Windows/EnvironmentInfo/DotNetRuntimeProvider.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using NLog; -using NzbDrone.Common.EnvironmentInfo; - -namespace NzbDrone.Windows.EnvironmentInfo -{ - public class DotNetRuntimeProvider : RuntimeInfoBase - { - public DotNetRuntimeProvider(Common.IServiceProvider serviceProvider, Logger logger) - : base(serviceProvider, logger) - { - } - - public override string RuntimeVersion => Environment.Version.ToString(); - } -} diff --git a/src/NzbDrone.Windows/EnvironmentInfo/WindowsVersionInfo.cs b/src/NzbDrone.Windows/EnvironmentInfo/WindowsVersionInfo.cs new file mode 100644 index 000000000..17b37c091 --- /dev/null +++ b/src/NzbDrone.Windows/EnvironmentInfo/WindowsVersionInfo.cs @@ -0,0 +1,49 @@ +using System; +using Microsoft.Win32; +using NLog; +using NzbDrone.Common.EnvironmentInfo; + +namespace NzbDrone.Windows.EnvironmentInfo +{ + public class WindowsVersionInfo : IOsVersionAdapter + { + private readonly Logger _logger; + public bool Enabled => OsInfo.IsWindows; + + public WindowsVersionInfo(Logger logger) + { + _logger = logger; + } + + public OsVersionModel Read() + { + var windowsServer = IsServer(); + var osName = windowsServer ? "Windows Server" : "Windows"; + return new OsVersionModel(osName, Environment.OSVersion.Version.ToString(), Environment.OSVersion.VersionString); + } + + private bool IsServer() + { + try + { + const string subkey = @"Software\Microsoft\Windows NT\CurrentVersion"; + var openSubKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(subkey); + if (openSubKey != null) + { + var productName = openSubKey.GetValue("ProductName").ToString(); + + if (productName.ToLower().Contains("server")) + { + return true; + } + } + } + catch (Exception e) + { + _logger.Error(e, "Couldn't detect if running Windows Server"); + } + + return false; + } + } +} diff --git a/src/NzbDrone.Windows/NzbDrone.Windows.csproj b/src/NzbDrone.Windows/NzbDrone.Windows.csproj index f05276acb..d5b19d02a 100644 --- a/src/NzbDrone.Windows/NzbDrone.Windows.csproj +++ b/src/NzbDrone.Windows/NzbDrone.Windows.csproj @@ -73,7 +73,8 @@ - + + @@ -83,6 +84,7 @@ + diff --git a/src/NzbDrone.Windows/app.config b/src/NzbDrone.Windows/app.config new file mode 100644 index 000000000..afbead3a0 --- /dev/null +++ b/src/NzbDrone.Windows/app.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tools/desktop.ini b/tools/desktop.ini new file mode 100644 index 000000000..ab17096ea --- /dev/null +++ b/tools/desktop.ini @@ -0,0 +1,4 @@ +[ViewState] +Mode= +Vid= +FolderType=Documents