using System.Net; using Catalog.Communication.Abstractions; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; namespace Catalog.Communication.DependencyInjection; public static class CatalogCommunicationServiceCollectionExtensions { public static IServiceCollection AddCatalogCommunication(this IServiceCollection services, Action configure) { ArgumentNullException.ThrowIfNull(services); ArgumentNullException.ThrowIfNull(configure); services .AddOptions() .Configure(configure) .Validate(o => o.BaseUri is not null, "CatalogCommunicationOptions.BaseUri is required.") .Validate(o => !string.IsNullOrWhiteSpace(o.AdminPageBasePath), "AdminPageBasePath is required.") .Validate(o => !string.IsNullOrWhiteSpace(o.ReceiveFilePath), "ReceiveFilePath is required.") .Validate(o => o.RequestTimeout > TimeSpan.Zero, "RequestTimeout must be greater than zero.") .Validate(o => o.RetryCount >= 0 && o.RetryCount <= 10, "RetryCount must be between 0 and 10.") .Validate(o => o.RetryBaseDelay > TimeSpan.Zero, "RetryBaseDelay must be greater than zero."); services.TryAddSingleton(); // Create the HttpClient only when the communication client is requested. // This avoids constructing the DefaultHttpClientFactory (and its background cleanup timer) // if the race-upload feature is never used. services.AddTransient(sp => { var options = sp.GetRequiredService>().Value; var logger = sp.GetService>() ?? NullLogger.Instance; var cookieContainer = sp.GetRequiredService(); var handler = new HttpClientHandler { UseCookies = true, CookieContainer = cookieContainer, AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate | DecompressionMethods.Brotli, }; var httpClient = new HttpClient(handler, disposeHandler: true) { BaseAddress = options.BaseUri, Timeout = options.RequestTimeout, }; return new RaceUploadCommunicationClient(httpClient, sp.GetRequiredService>(), logger); }); return services; } }