using System; using System.Threading.Tasks; namespace ProjectI.Sessions { public sealed class SessionLifecycle { private Func pendingCleanup; private Func cleanupAlreadyRemoved; private Func finishLocalNetwork; private Func terminalCleanupError; public bool Busy { get; private set; } public bool ConnectionLossPending { get; private set; } public bool HasPendingCleanup => pendingCleanup != null; public void BeginOperation() { if (Busy) throw new InvalidOperationException("A session operation is already pending."); Busy = true; } public void RequestConnectionLoss() { ConnectionLossPending = true; } public bool EndOperation() { Busy = false; bool lost = ConnectionLossPending; ConnectionLossPending = false; return lost; } public void PreserveCleanup(Func cleanup, Func alreadyRemoved = null, Func finishNetwork = null, Func isTerminalError = null) { pendingCleanup = cleanup; cleanupAlreadyRemoved = alreadyRemoved; finishLocalNetwork = finishNetwork; terminalCleanupError = isTerminalError; } public async Task RetryCleanupAsync() { var cleanup = pendingCleanup; if (cleanup == null) return; var alreadyRemoved = cleanupAlreadyRemoved; var finishNetwork = finishLocalNetwork; var isTerminalError = terminalCleanupError; bool completeLocally = alreadyRemoved?.Invoke() ?? false; if (!completeLocally) { try { await cleanup(); } catch (Exception exception) when ((alreadyRemoved?.Invoke() ?? false) || (isTerminalError?.Invoke(exception) ?? false)) { // The remote game/membership is gone; retrying a cloud leave cannot restore it. completeLocally = true; } } if (completeLocally && finishNetwork != null) await finishNetwork(); if (pendingCleanup == cleanup) { pendingCleanup = null; cleanupAlreadyRemoved = null; finishLocalNetwork = null; terminalCleanupError = null; } } } }