From 081856e19ee3ed124649de01a5c28d2c636a4c88 Mon Sep 17 00:00:00 2001 From: Robert Dailey Date: Thu, 3 Nov 2022 20:08:54 -0500 Subject: [PATCH] refactor: Generalize compatibility check logic Previously, only Sonarr had compatibility checking logic, which also consequently meant that version information was obtained and logged for Sonarr services. However, Radarr had no such checks because compatibility has not yet been an issue. However, we still would like to see version information printed when running Radarr instances. --- src/Recyclarr/Command/RadarrCommand.cs | 7 ++++ src/Recyclarr/CompositionRoot.cs | 2 ++ .../Sonarr/SonarrCompatibilityTest.cs | 18 ++++++----- .../Services/Radarr/RadarrAutofacModule.cs | 1 + .../Services/Radarr/RadarrCapabilities.cs | 8 +++++ .../Services/Radarr/RadarrCompatibility.cs | 17 ++++++++++ .../Services/Sonarr/Api/ISonarrApi.cs | 2 -- src/TrashLib/Services/Sonarr/Api/SonarrApi.cs | 9 ------ .../Services/Sonarr/SonarrCompatibility.cs | 21 +++--------- .../Services/System/Dto/SystemStatus.cs | 6 ++++ .../Services/System/ISystemApiService.cs | 8 +++++ .../Services/System/ServiceCompatibility.cs | 32 +++++++++++++++++++ .../Services/System/SystemApiService.cs | 25 +++++++++++++++ .../System/SystemServiceAutofacModule.cs | 12 +++++++ 14 files changed, 133 insertions(+), 35 deletions(-) create mode 100644 src/TrashLib/Services/Radarr/RadarrCapabilities.cs create mode 100644 src/TrashLib/Services/Radarr/RadarrCompatibility.cs create mode 100644 src/TrashLib/Services/System/Dto/SystemStatus.cs create mode 100644 src/TrashLib/Services/System/ISystemApiService.cs create mode 100644 src/TrashLib/Services/System/ServiceCompatibility.cs create mode 100644 src/TrashLib/Services/System/SystemApiService.cs create mode 100644 src/TrashLib/Services/System/SystemServiceAutofacModule.cs diff --git a/src/Recyclarr/Command/RadarrCommand.cs b/src/Recyclarr/Command/RadarrCommand.cs index 906c76ce..1a1a007d 100644 --- a/src/Recyclarr/Command/RadarrCommand.cs +++ b/src/Recyclarr/Command/RadarrCommand.cs @@ -1,3 +1,4 @@ +using System.Reactive.Linq; using Autofac; using CliFx.Attributes; using JetBrains.Annotations; @@ -61,6 +62,12 @@ internal class RadarrCommand : ServiceCommand log.Information("Processing server {Url}", FlurlLogging.SanitizeUrl(config.BaseUrl)); + // There's no actual compatibility checks to perform yet. We directly access the RadarrCompatibility class, + // as opposed to a IRadarrVersionEnforcement object (like Sonarr does), simply to force the API invocation + // in Radarr to acquire and log version information. + var compatibility = scope.Resolve(); + await compatibility.Capabilities.LastAsync(); + // ReSharper disable InvertIf if (config.QualityDefinition != null) diff --git a/src/Recyclarr/CompositionRoot.cs b/src/Recyclarr/CompositionRoot.cs index 6a9d3329..70de5324 100644 --- a/src/Recyclarr/CompositionRoot.cs +++ b/src/Recyclarr/CompositionRoot.cs @@ -18,6 +18,7 @@ using TrashLib.Services.Common; using TrashLib.Services.CustomFormat; using TrashLib.Services.Radarr; using TrashLib.Services.Sonarr; +using TrashLib.Services.System; using TrashLib.Startup; using VersionControl; using YamlDotNet.Serialization; @@ -44,6 +45,7 @@ public static class CompositionRoot builder.RegisterModule(); builder.RegisterModule(); builder.RegisterModule(); + builder.RegisterModule(); // Needed for Autofac.Extras.Ordering builder.RegisterSource(); diff --git a/src/TrashLib.Tests/Sonarr/SonarrCompatibilityTest.cs b/src/TrashLib.Tests/Sonarr/SonarrCompatibilityTest.cs index d8411486..b375125c 100644 --- a/src/TrashLib.Tests/Sonarr/SonarrCompatibilityTest.cs +++ b/src/TrashLib.Tests/Sonarr/SonarrCompatibilityTest.cs @@ -14,6 +14,8 @@ using TrashLib.Services.Sonarr; using TrashLib.Services.Sonarr.Api; using TrashLib.Services.Sonarr.Api.Objects; using TrashLib.Services.Sonarr.Config; +using TrashLib.Services.System; +using TrashLib.Services.System.Dto; using TrashLib.Startup; namespace TrashLib.Tests.Sonarr; @@ -119,11 +121,11 @@ public class SonarrCompatibilityTest [Test, AutoMockData] public async Task Failure_when_release_profiles_used_with_sonarr_v4( - [Frozen] ISonarrApi api, + [Frozen] ISystemApiService api, [Frozen(Matching.ImplementedInterfaces)] SonarrCompatibility compatibility, SonarrVersionEnforcement enforcement) { - api.GetVersion().Returns(new Version(4, 0)); + api.GetStatus().Returns(new SystemStatus("Sonarr", "4.0")); var config = new SonarrConfiguration { @@ -137,11 +139,11 @@ public class SonarrCompatibilityTest [Test, AutoMockData] public async Task No_failure_when_release_profiles_used_with_sonarr_v3( - [Frozen] ISonarrApi api, + [Frozen] ISystemApiService api, [Frozen(Matching.ImplementedInterfaces)] SonarrCompatibility compatibility, SonarrVersionEnforcement enforcement) { - api.GetVersion().Returns(new Version(3, 9)); + api.GetStatus().Returns(new SystemStatus("Sonarr", "3.9")); var config = new SonarrConfiguration { @@ -155,11 +157,11 @@ public class SonarrCompatibilityTest [Test, AutoMockData] public async Task Failure_when_custom_formats_used_with_sonarr_v3( - [Frozen] ISonarrApi api, + [Frozen] ISystemApiService api, [Frozen(Matching.ImplementedInterfaces)] SonarrCompatibility compatibility, SonarrVersionEnforcement enforcement) { - api.GetVersion().Returns(new Version(3, 9)); + api.GetStatus().Returns(new SystemStatus("Sonarr", "3.9")); var config = new SonarrConfiguration { @@ -173,11 +175,11 @@ public class SonarrCompatibilityTest [Test, AutoMockData] public async Task No_failure_when_custom_formats_used_with_sonarr_v4( - [Frozen] ISonarrApi api, + [Frozen] ISystemApiService api, [Frozen(Matching.ImplementedInterfaces)] SonarrCompatibility compatibility, SonarrVersionEnforcement enforcement) { - api.GetVersion().Returns(new Version(4, 0)); + api.GetStatus().Returns(new SystemStatus("Sonarr", "4.0")); var config = new SonarrConfiguration { diff --git a/src/TrashLib/Services/Radarr/RadarrAutofacModule.cs b/src/TrashLib/Services/Radarr/RadarrAutofacModule.cs index 50554127..af6dcce9 100644 --- a/src/TrashLib/Services/Radarr/RadarrAutofacModule.cs +++ b/src/TrashLib/Services/Radarr/RadarrAutofacModule.cs @@ -15,5 +15,6 @@ public class RadarrAutofacModule : Module builder.RegisterType().As(); builder.RegisterType().As(); builder.RegisterType().As(); + builder.RegisterType(); } } diff --git a/src/TrashLib/Services/Radarr/RadarrCapabilities.cs b/src/TrashLib/Services/Radarr/RadarrCapabilities.cs new file mode 100644 index 00000000..8ec32a51 --- /dev/null +++ b/src/TrashLib/Services/Radarr/RadarrCapabilities.cs @@ -0,0 +1,8 @@ +namespace TrashLib.Services.Radarr; + +public record RadarrCapabilities(Version Version) +{ + public RadarrCapabilities() : this(new Version()) + { + } +} diff --git a/src/TrashLib/Services/Radarr/RadarrCompatibility.cs b/src/TrashLib/Services/Radarr/RadarrCompatibility.cs new file mode 100644 index 00000000..6467b2a9 --- /dev/null +++ b/src/TrashLib/Services/Radarr/RadarrCompatibility.cs @@ -0,0 +1,17 @@ +using Serilog; +using TrashLib.Services.System; + +namespace TrashLib.Services.Radarr; + +public class RadarrCompatibility : ServiceCompatibility +{ + public RadarrCompatibility(ISystemApiService api, ILogger log) + : base(api, log) + { + } + + protected override RadarrCapabilities BuildCapabilitiesObject(Version version) + { + return new RadarrCapabilities(version); + } +} diff --git a/src/TrashLib/Services/Sonarr/Api/ISonarrApi.cs b/src/TrashLib/Services/Sonarr/Api/ISonarrApi.cs index e1284e35..02708039 100644 --- a/src/TrashLib/Services/Sonarr/Api/ISonarrApi.cs +++ b/src/TrashLib/Services/Sonarr/Api/ISonarrApi.cs @@ -10,6 +10,4 @@ public interface ISonarrApi Task> UpdateQualityDefinition( IReadOnlyCollection newQuality); - - Task GetVersion(); } diff --git a/src/TrashLib/Services/Sonarr/Api/SonarrApi.cs b/src/TrashLib/Services/Sonarr/Api/SonarrApi.cs index cea30f5a..df1e270a 100644 --- a/src/TrashLib/Services/Sonarr/Api/SonarrApi.cs +++ b/src/TrashLib/Services/Sonarr/Api/SonarrApi.cs @@ -14,15 +14,6 @@ public class SonarrApi : ISonarrApi _serverInfo = serverInfo; } - public async Task GetVersion() - { - var response = await BaseUrl() - .AppendPathSegment("system/status") - .GetJsonAsync(); - - return new Version(response.version); - } - public async Task> GetTags() { return await BaseUrl() diff --git a/src/TrashLib/Services/Sonarr/SonarrCompatibility.cs b/src/TrashLib/Services/Sonarr/SonarrCompatibility.cs index 31316290..9e615154 100644 --- a/src/TrashLib/Services/Sonarr/SonarrCompatibility.cs +++ b/src/TrashLib/Services/Sonarr/SonarrCompatibility.cs @@ -1,30 +1,19 @@ -using System.Reactive.Concurrency; -using System.Reactive.Linq; using Serilog; -using TrashLib.Services.Sonarr.Api; +using TrashLib.Services.System; namespace TrashLib.Services.Sonarr; -public class SonarrCompatibility : ISonarrCompatibility +public class SonarrCompatibility : ServiceCompatibility, ISonarrCompatibility { - private readonly ILogger _log; - - public SonarrCompatibility(ISonarrApi api, ILogger log) + public SonarrCompatibility(ISystemApiService api, ILogger log) + : base(api, log) { - _log = log; - Capabilities = Observable.FromAsync(async () => await api.GetVersion(), NewThreadScheduler.Default) - .Timeout(TimeSpan.FromSeconds(15)) - .Select(BuildCapabilitiesObject) - .Replay(1) - .AutoConnect(); } - public IObservable Capabilities { get; } public Version MinimumVersion => new("3.0.4.1098"); - private SonarrCapabilities BuildCapabilitiesObject(Version version) + protected override SonarrCapabilities BuildCapabilitiesObject(Version version) { - _log.Debug("Sonarr Version: {Version}", version); return new SonarrCapabilities(version) { SupportsNamedReleaseProfiles = diff --git a/src/TrashLib/Services/System/Dto/SystemStatus.cs b/src/TrashLib/Services/System/Dto/SystemStatus.cs new file mode 100644 index 00000000..8abeff3d --- /dev/null +++ b/src/TrashLib/Services/System/Dto/SystemStatus.cs @@ -0,0 +1,6 @@ +namespace TrashLib.Services.System.Dto; + +public record SystemStatus( + string AppName, + string Version +); diff --git a/src/TrashLib/Services/System/ISystemApiService.cs b/src/TrashLib/Services/System/ISystemApiService.cs new file mode 100644 index 00000000..2e3e7546 --- /dev/null +++ b/src/TrashLib/Services/System/ISystemApiService.cs @@ -0,0 +1,8 @@ +using TrashLib.Services.System.Dto; + +namespace TrashLib.Services.System; + +public interface ISystemApiService +{ + Task GetStatus(); +} diff --git a/src/TrashLib/Services/System/ServiceCompatibility.cs b/src/TrashLib/Services/System/ServiceCompatibility.cs new file mode 100644 index 00000000..38ac711a --- /dev/null +++ b/src/TrashLib/Services/System/ServiceCompatibility.cs @@ -0,0 +1,32 @@ +using System.Reactive.Concurrency; +using System.Reactive.Linq; +using Serilog; +using TrashLib.Services.System.Dto; + +namespace TrashLib.Services.System; + +public abstract class ServiceCompatibility where T : new() +{ + private readonly ILogger _log; + + protected ServiceCompatibility(ISystemApiService api, ILogger log) + { + _log = log; + Capabilities = Observable.FromAsync(async () => await api.GetStatus(), NewThreadScheduler.Default) + .Timeout(TimeSpan.FromSeconds(15)) + .Do(LogServiceInfo) + .Select(x => new Version(x.Version)) + .Select(BuildCapabilitiesObject) + .Replay(1) + .AutoConnect(); + } + + public IObservable Capabilities { get; } + + private void LogServiceInfo(SystemStatus status) + { + _log.Debug("{Service} Version: {Version}", status.AppName, status.Version); + } + + protected abstract T BuildCapabilitiesObject(Version version); +} diff --git a/src/TrashLib/Services/System/SystemApiService.cs b/src/TrashLib/Services/System/SystemApiService.cs new file mode 100644 index 00000000..78ae3449 --- /dev/null +++ b/src/TrashLib/Services/System/SystemApiService.cs @@ -0,0 +1,25 @@ +using Flurl; +using Flurl.Http; +using TrashLib.Config.Services; +using TrashLib.Services.System.Dto; + +namespace TrashLib.Services.System; + +public class SystemApiService : ISystemApiService +{ + private readonly IServerInfo _serverInfo; + + public SystemApiService(IServerInfo serverInfo) + { + _serverInfo = serverInfo; + } + + public async Task GetStatus() + { + return await BaseUrl() + .AppendPathSegment("system/status") + .GetJsonAsync(); + } + + private Url BaseUrl() => _serverInfo.BuildRequest(); +} diff --git a/src/TrashLib/Services/System/SystemServiceAutofacModule.cs b/src/TrashLib/Services/System/SystemServiceAutofacModule.cs new file mode 100644 index 00000000..7b1e9d39 --- /dev/null +++ b/src/TrashLib/Services/System/SystemServiceAutofacModule.cs @@ -0,0 +1,12 @@ +using Autofac; + +namespace TrashLib.Services.System; + +public class SystemServiceAutofacModule : Module +{ + protected override void Load(ContainerBuilder builder) + { + base.Load(builder); + builder.RegisterType().As(); + } +}