using System.Net; using Data.Models.Configuration.General; using Data.Models.Arr; using Infrastructure.Health; using Infrastructure.Http; using Infrastructure.Verticals.DownloadClient.Deluge; using Infrastructure.Verticals.DownloadClient.QBittorrent; using Infrastructure.Verticals.DownloadClient.Transmission; using Infrastructure.Verticals.DownloadRemover.Consumers; using Infrastructure.Verticals.Notifications.Consumers; using Infrastructure.Verticals.Notifications.Models; using MassTransit; using Polly; using Polly.Extensions.Http; namespace Executable.DependencyInjection; public static class MainDI { public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration) => services .AddLogging(builder => builder.ClearProviders().AddConsole()) .AddHttpClients(configuration) .AddMemoryCache(options => { options.ExpirationScanFrequency = TimeSpan.FromMinutes(1); }) .AddServices() .AddDownloadClientServices() .AddHealthServices() .AddQuartzServices(configuration) .AddNotifications(configuration) .AddMassTransit(config => { config.AddConsumer>(); config.AddConsumer>(); config.AddConsumer>(); config.AddConsumer>(); config.AddConsumer>(); config.AddConsumer>(); config.AddConsumer>(); config.AddConsumer>(); config.UsingInMemory((context, cfg) => { cfg.ReceiveEndpoint("download-remover-queue", e => { e.ConfigureConsumer>(context); e.ConfigureConsumer>(context); e.ConcurrentMessageLimit = 1; e.PrefetchCount = 1; }); cfg.ReceiveEndpoint("notification-queue", e => { e.ConfigureConsumer>(context); e.ConfigureConsumer>(context); e.ConfigureConsumer>(context); e.ConfigureConsumer>(context); e.ConfigureConsumer>(context); e.ConfigureConsumer>(context); e.ConcurrentMessageLimit = 1; e.PrefetchCount = 1; }); }); }); private static IServiceCollection AddHttpClients(this IServiceCollection services, IConfiguration configuration) { // add default HttpClient services.AddHttpClient(); // add dynamic HTTP client provider services.AddSingleton(); // var configManager = services.BuildServiceProvider().GetRequiredService(); // HttpConfig config = configManager.GetConfiguration("http.json") ?? new(); // config.Validate(); // // // add retry HttpClient // services // .AddHttpClient(Constants.HttpClientWithRetryName, x => // { // x.Timeout = TimeSpan.FromSeconds(config.Timeout); // }) // .ConfigurePrimaryHttpMessageHandler(provider => // { // CertificateValidationService service = provider.GetRequiredService(); // // return new HttpClientHandler // { // ServerCertificateCustomValidationCallback = service.ShouldByPassValidationError // }; // }) // .AddRetryPolicyHandler(config); // // // Note: We're no longer configuring specific named HttpClients for each download service // // Instead, we use the DynamicHttpClientProvider to create HttpClients as needed based on client configurations return services; } private static IHttpClientBuilder AddRetryPolicyHandler(this IHttpClientBuilder builder, GeneralConfig config) => builder.AddPolicyHandler( HttpPolicyExtensions .HandleTransientHttpError() // do not retry on Unauthorized .OrResult(response => !response.IsSuccessStatusCode && response.StatusCode != HttpStatusCode.Unauthorized) .WaitAndRetryAsync(config.HttpMaxRetries, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))) ); private static IServiceCollection AddDownloadClientServices(this IServiceCollection services) => services // Register all download client service types // The factory will create instances as needed based on the client configuration .AddTransient() .AddTransient() .AddTransient(); /// /// Adds health check services to the service collection /// private static IServiceCollection AddHealthServices(this IServiceCollection services) => services // Register the health check service .AddSingleton() // Register the background service for periodic health checks .AddHostedService(); }