using ErsatzTV.Core; using ErsatzTV.Core.Domain; using ErsatzTV.Core.Emby; using ErsatzTV.Core.Interfaces.Emby; using ErsatzTV.Core.Interfaces.Repositories; using Microsoft.Extensions.Caching.Memory; namespace ErsatzTV.Application.Emby; public class GetEmbyConnectionParametersHandler : IRequestHandler> { private readonly IEmbySecretStore _embySecretStore; private readonly IMediaSourceRepository _mediaSourceRepository; private readonly IMemoryCache _memoryCache; public GetEmbyConnectionParametersHandler( IMemoryCache memoryCache, IMediaSourceRepository mediaSourceRepository, IEmbySecretStore embySecretStore) { _memoryCache = memoryCache; _mediaSourceRepository = mediaSourceRepository; _embySecretStore = embySecretStore; } public async Task> Handle( GetEmbyConnectionParameters request, CancellationToken cancellationToken) { if (_memoryCache.TryGetValue(request, out EmbyConnectionParametersViewModel parameters)) { return parameters; } Either maybeParameters = await Validate() .MapT(cp => new EmbyConnectionParametersViewModel(cp.ActiveConnection.Address, cp.ApiKey)) .Map(v => v.ToEither()); return maybeParameters.Match( p => { _memoryCache.Set(request, p, TimeSpan.FromHours(1)); return maybeParameters; }, error => error); } private Task> Validate() => EmbyMediaSourceMustExist() .BindT(MediaSourceMustHaveActiveConnection) .BindT(MediaSourceMustHaveApiKey); private Task> EmbyMediaSourceMustExist() => _mediaSourceRepository.GetAllEmby().Map(list => list.HeadOrNone()) .Map( v => v.ToValidation( "Emby media source does not exist.")); private Validation MediaSourceMustHaveActiveConnection( EmbyMediaSource embyMediaSource) { Option maybeConnection = embyMediaSource.Connections.FirstOrDefault(); return maybeConnection.Map(connection => new ConnectionParameters(embyMediaSource, connection)) .ToValidation("Emby media source requires an active connection"); } private async Task> MediaSourceMustHaveApiKey( ConnectionParameters connectionParameters) { EmbySecrets secrets = await _embySecretStore.ReadSecrets(); return Optional(secrets.Address == connectionParameters.ActiveConnection.Address) .Where(match => match) .Map(_ => connectionParameters with { ApiKey = secrets.ApiKey }) .ToValidation("Emby media source requires an api key"); } private sealed record ConnectionParameters( EmbyMediaSource EmbyMediaSource, EmbyConnection ActiveConnection) { public string ApiKey { get; set; } } }