using System.Linq; using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; using ErsatzTV.Application.MediaSources.Commands; using ErsatzTV.Core; using ErsatzTV.Core.Domain; using ErsatzTV.Core.Interfaces.Locking; using ErsatzTV.Infrastructure.Data; using LanguageExt; using MediatR; using Microsoft.EntityFrameworkCore; using static ErsatzTV.Application.Libraries.Mapper; using static LanguageExt.Prelude; namespace ErsatzTV.Application.Libraries.Commands { public class CreateLocalLibraryHandler : LocalLibraryHandlerBase, IRequestHandler> { private readonly ChannelWriter _workerChannel; private readonly IEntityLocker _entityLocker; private readonly IDbContextFactory _dbContextFactory; public CreateLocalLibraryHandler( ChannelWriter workerChannel, IEntityLocker entityLocker, IDbContextFactory dbContextFactory) { _workerChannel = workerChannel; _entityLocker = entityLocker; _dbContextFactory = dbContextFactory; } public async Task> Handle( CreateLocalLibrary request, CancellationToken cancellationToken) { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); Validation validation = await Validate(dbContext, request); return await validation.Apply(localLibrary => PersistLocalLibrary(dbContext, localLibrary)); } private async Task PersistLocalLibrary( TvContext dbContext, LocalLibrary localLibrary) { await dbContext.LocalLibraries.AddAsync(localLibrary); await dbContext.SaveChangesAsync(); if (_entityLocker.LockLibrary(localLibrary.Id)) { await _workerChannel.WriteAsync(new ForceScanLocalLibrary(localLibrary.Id)); } return ProjectToViewModel(localLibrary); } private static Task> Validate( TvContext dbContext, CreateLocalLibrary request) => MediaSourceMustExist(dbContext, request) .BindT(localLibrary => NameMustBeValid(request, localLibrary)) .BindT(localLibrary => PathsMustBeValid(dbContext, localLibrary)); private static Task> MediaSourceMustExist( TvContext dbContext, CreateLocalLibrary request) => dbContext.LocalMediaSources .OrderBy(lms => lms.Id) .FirstOrDefaultAsync() .Map(Optional) .MapT( lms => new LocalLibrary { Name = request.Name, Paths = request.Paths.Map(p => new LibraryPath { Path = p }).ToList(), MediaKind = request.MediaKind, MediaSourceId = lms.Id }) .Map(o => o.ToValidation("LocalMediaSource does not exist.")); } }