using ErsatzTV.Core; using ErsatzTV.Core.Interfaces.Locking; using ErsatzTV.Core.Interfaces.Plex; using ErsatzTV.Core.Interfaces.Repositories; using ErsatzTV.Core.Interfaces.Search; namespace ErsatzTV.Application.Plex; public class SignOutOfPlexHandler : IRequestHandler> { private readonly IEntityLocker _entityLocker; private readonly IMediaSourceRepository _mediaSourceRepository; private readonly IPlexSecretStore _plexSecretStore; private readonly ISearchIndex _searchIndex; public SignOutOfPlexHandler( IMediaSourceRepository mediaSourceRepository, IPlexSecretStore plexSecretStore, IEntityLocker entityLocker, ISearchIndex searchIndex) { _mediaSourceRepository = mediaSourceRepository; _plexSecretStore = plexSecretStore; _entityLocker = entityLocker; _searchIndex = searchIndex; } public async Task> Handle(SignOutOfPlex request, CancellationToken cancellationToken) { // Terminal handler (no lock handoff): release the Plex lock on EVERY exit via finally so a throw // from any awaited dependency (repo delete, search-index commit, secret store) cannot wedge Plex // locked at 409 until restart (#202 §C6 / finding 7). This is the UNCONDITIONAL-finally case — // contrast the pin-flow handlers, which hand the lock off and must NOT use a blanket finally. try { List ids = await _mediaSourceRepository.DeleteAllPlex(); await _searchIndex.RemoveItems(ids); _searchIndex.Commit(); await _plexSecretStore.DeleteAll(); return Unit.Default; } finally { _entityLocker.UnlockPlex(); } } }