Files
TeleWave/backend/src/TeleWave.Infrastructure/DependencyInjection.cs
T

133 lines
5.9 KiB
C#

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;
/// <summary>
/// Регистрация сервисов инфраструктуры: EF Core (PostgreSQL), Identity/JWT-аутентификация.
/// </summary>
public static class DependencyInjection
{
public static IServiceCollection AddInfrastructure(
this IServiceCollection services,
IConfiguration configuration
)
{
services.AddDbContext<AppDbContext>(options =>
options.UseNpgsql(
configuration["ConnectionStrings:Default"]
?? throw new InvalidOperationException(
"Строка подключения 'ConnectionStrings:Default' не сконфигурирована."
)
)
);
services.AddScoped<IAppDbContext>(sp => sp.GetRequiredService<AppDbContext>());
services
.AddIdentityCore<AppUser>(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<AppRole>()
.AddEntityFrameworkStores<AppDbContext>()
.AddSignInManager()
.AddDefaultTokenProviders();
services.Configure<JwtOptions>(configuration.GetSection(JwtOptions.SectionName));
services.Configure<AdminSeedOptions>(
configuration.GetSection(AdminSeedOptions.SectionName)
);
var jwtOptions =
configuration.GetSection(JwtOptions.SectionName).Get<JwtOptions>()
?? 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<IIdentityService, IdentityService>();
services.AddScoped<IJwtTokenService, JwtTokenService>();
services.AddScoped<IRefreshTokenService, RefreshTokenService>();
services.AddScoped<IRoleService, RoleService>();
services.AddScoped<ICurrentUser, CurrentUser>();
services.AddScoped<ISiteSettings, SiteSettings>();
services.AddScoped<DbInitializer>();
AddMedia(services, configuration);
AddBroadcast(services, configuration);
return services;
}
/// <summary>Планировщик расписания: генератор, источник случайности и фоновый сервис горизонта.</summary>
private static void AddBroadcast(IServiceCollection services, IConfiguration configuration)
{
services.Configure<SchedulerOptions>(configuration.GetSection(SchedulerOptions.SectionName));
services.Configure<StreamingOptions>(configuration.GetSection(StreamingOptions.SectionName));
services.Configure<BumperOptions>(configuration.GetSection(BumperOptions.SectionName));
services.AddSingleton<IRandomSource, SystemRandomSource>();
services.AddSingleton<StreamTokenService>();
services.AddSingleton<IBumperRenderer, FfmpegBumperRenderer>();
services.AddScoped<ScheduleGenerator>();
services.AddHostedService<SchedulingBackgroundService>();
}
/// <summary>Хранилище медиа, обработка ffmpeg, очередь и фоновые сервисы (очередь + inbox-сканер).</summary>
private static void AddMedia(IServiceCollection services, IConfiguration configuration)
{
services.Configure<StorageOptions>(configuration.GetSection(StorageOptions.SectionName));
services.Configure<MediaOptions>(configuration.GetSection(MediaOptions.SectionName));
services.AddSingleton<MediaPathResolver>();
services.AddSingleton<IMediaStorage, FileSystemMediaStorage>();
services.AddSingleton<IBumperTemplateStorage, BumperTemplateStorage>();
services.AddSingleton<IMediaProcessor, FfmpegMediaProcessor>();
services.AddSingleton<IMediaProcessingQueue, MediaProcessingQueue>();
services.AddHostedService<MediaProcessingBackgroundService>();
services.AddHostedService<InboxScannerBackgroundService>();
}
}