using ErsatzTV.Core; using ErsatzTV.Core.Domain; using ErsatzTV.Core.Interfaces.Plex; using ErsatzTV.Core.Interfaces.Repositories; using ErsatzTV.Core.Plex; using Microsoft.Extensions.Caching.Memory; namespace ErsatzTV.Application.Plex; public class GetPlexConnectionParametersHandler : IRequestHandler> { private readonly IMediaSourceRepository _mediaSourceRepository; private readonly IMemoryCache _memoryCache; private readonly IPlexSecretStore _plexSecretStore; public GetPlexConnectionParametersHandler( IMemoryCache memoryCache, IMediaSourceRepository mediaSourceRepository, IPlexSecretStore plexSecretStore) { _memoryCache = memoryCache; _mediaSourceRepository = mediaSourceRepository; _plexSecretStore = plexSecretStore; } public async Task> Handle( GetPlexConnectionParameters request, CancellationToken cancellationToken) { if (_memoryCache.TryGetValue(request, out PlexConnectionParametersViewModel parameters)) { return parameters; } Either maybeParameters = await Validate(request) .MapT( cp => new PlexConnectionParametersViewModel( new Uri(cp.ActiveConnection.Uri), cp.PlexServerAuthToken.AuthToken)) .Map(v => v.ToEither()); return maybeParameters.Match( p => { _memoryCache.Set(request, p, TimeSpan.FromHours(1)); return maybeParameters; }, error => error); } private Task> Validate(GetPlexConnectionParameters request) => PlexMediaSourceMustExist(request) .BindT(MediaSourceMustHaveActiveConnection) .BindT(MediaSourceMustHaveToken); private Task> PlexMediaSourceMustExist( GetPlexConnectionParameters request) => _mediaSourceRepository.GetPlex(request.PlexMediaSourceId) .Map( v => v.ToValidation( $"Plex media source {request.PlexMediaSourceId} does not exist.")); private Validation MediaSourceMustHaveActiveConnection( PlexMediaSource plexMediaSource) { Option maybeConnection = plexMediaSource.Connections.SingleOrDefault(c => c.IsActive); return maybeConnection.Map(connection => new ConnectionParameters(plexMediaSource, connection)) .ToValidation("Plex media source requires an active connection"); } private async Task> MediaSourceMustHaveToken( ConnectionParameters connectionParameters) { Option maybeToken = await _plexSecretStore.GetServerAuthToken(connectionParameters.PlexMediaSource.ClientIdentifier); return maybeToken.Map(token => connectionParameters with { PlexServerAuthToken = token }) .ToValidation("Plex media source requires a token"); } private sealed record ConnectionParameters(PlexMediaSource PlexMediaSource, PlexConnection ActiveConnection) { public PlexServerAuthToken PlexServerAuthToken { get; set; } } }