using System.Text;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using TeleWave.Application.Broadcast.Bumpers;
using TeleWave.Application.Broadcast.Scheduling;
using TeleWave.Application.Common.Interfaces;
using TeleWave.Application.Streaming;
using TeleWave.Domain.Broadcast.Scheduling;
using TeleWave.Infrastructure.Broadcast;
using TeleWave.Infrastructure.Identity;
using TeleWave.Infrastructure.Media;
using TeleWave.Infrastructure.Persistence;
using TeleWave.Infrastructure.Settings;
using TeleWave.Infrastructure.Streaming;
namespace TeleWave.Infrastructure;
///
/// Регистрация сервисов инфраструктуры: EF Core (PostgreSQL), Identity/JWT-аутентификация.
///
public static class DependencyInjection
{
public static IServiceCollection AddInfrastructure(
this IServiceCollection services,
IConfiguration configuration
)
{
services.AddDbContext(options =>
options.UseNpgsql(
configuration["ConnectionStrings:Default"]
?? throw new InvalidOperationException(
"Строка подключения 'ConnectionStrings:Default' не сконфигурирована."
)
)
);
services.AddScoped(sp => sp.GetRequiredService());
services
.AddIdentityCore(options =>
{
options.User.RequireUniqueEmail = false;
options.Password.RequiredLength = 8;
options.Password.RequireDigit = true;
options.Password.RequireUppercase = true;
options.Password.RequireNonAlphanumeric = false;
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
options.Lockout.AllowedForNewUsers = true;
})
.AddRoles()
.AddEntityFrameworkStores()
.AddSignInManager()
.AddDefaultTokenProviders();
services.Configure(configuration.GetSection(JwtOptions.SectionName));
services.Configure(
configuration.GetSection(AdminSeedOptions.SectionName)
);
var jwtOptions =
configuration.GetSection(JwtOptions.SectionName).Get()
?? throw new InvalidOperationException("Секция конфигурации 'Jwt' не задана.");
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = jwtOptions.Issuer,
ValidateAudience = true,
ValidAudience = jwtOptions.Audience,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(jwtOptions.SigningKey)
),
ValidateLifetime = true,
ClockSkew = TimeSpan.FromSeconds(30),
};
});
services.AddAuthorization();
services.AddScoped();
services.AddScoped();
services.AddScoped();
services.AddScoped();
services.AddScoped();
services.AddScoped();
services.AddScoped();
AddMedia(services, configuration);
AddBroadcast(services, configuration);
return services;
}
/// Планировщик расписания: генератор, источник случайности и фоновый сервис горизонта.
private static void AddBroadcast(IServiceCollection services, IConfiguration configuration)
{
services.Configure(configuration.GetSection(SchedulerOptions.SectionName));
services.Configure(configuration.GetSection(StreamingOptions.SectionName));
services.Configure(configuration.GetSection(BumperOptions.SectionName));
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddScoped();
services.AddHostedService();
}
/// Хранилище медиа, обработка ffmpeg, очередь и фоновые сервисы (очередь + inbox-сканер).
private static void AddMedia(IServiceCollection services, IConfiguration configuration)
{
services.Configure(configuration.GetSection(StorageOptions.SectionName));
services.Configure(configuration.GetSection(MediaOptions.SectionName));
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddHostedService();
services.AddHostedService();
}
}