using System; using System.Threading; using System.Threading.Tasks; using Duplicati.Library.Interface; using Duplicati.Library.Main.Operation.Common; using Duplicati.Library.Utility; namespace Duplicati.Library.Main.Backend; #nullable enable partial class BackendManager { /// /// Execution context for the backend manager /// /// A progress handler /// The stat writer /// The database collector /// The task reader /// The options private sealed record ExecuteContext( Action HandleProgress, IBackendWriter Statwriter, DatabaseCollector Database, ITaskReader TaskReader, Options Options); /// /// A base non-generic pending operation /// private abstract class PendingOperationBase { /// /// The execution context /// public ExecuteContext Context { get; } /// /// Whether to wait for the operation to complete. /// If false, the operation is queued and the task is returned after the operation is queued. /// public bool WaitForComplete { get; } /// /// The cancellation token /// public CancellationToken CancelToken { get; set; } /// /// The type of operation the pending operation represents /// public abstract BackendActionType Operation { get; } /// /// The remote filename, if any /// public virtual string RemoteFilename => string.Empty; /// /// The remote size, if any /// public virtual long Size => -1L; /// /// Sets the operation as cancelled /// public abstract void SetCancelled(); /// /// Sets the operation as failed /// /// The exception public abstract void SetFailed(Exception ex); /// /// Creates a new pending operation /// /// The execution context /// Whether to wait for the operation to complete /// The cancellation token public PendingOperationBase(ExecuteContext context, bool waitForComplete, CancellationToken cancelToken) { Context = context; WaitForComplete = waitForComplete; CancelToken = cancelToken; } } /// /// The basic queued backend operation /// /// /// Creates a new pending operation /// /// The execution context /// Whether to wait for the operation to complete /// The cancellation token private abstract class PendingOperation(ExecuteContext context, bool waitForComplete, CancellationToken cancelToken) : PendingOperationBase(context, waitForComplete, cancelToken) { /// /// A signal for the task completion /// private readonly TaskCompletionSource taskCompleteSignal = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); /// /// The task that is completed when the operation is done /// public Task GetResult() => taskCompleteSignal.Task; /// /// Sets the operation as complete /// public void SetComplete(TResult result) { taskCompleteSignal.TrySetResult(result); } /// /// Sets the operation as failed /// /// The exception public override void SetFailed(Exception ex) { taskCompleteSignal.TrySetException(ex); } /// /// Sets the operation as cancelled /// public override void SetCancelled() { taskCompleteSignal.TrySetCanceled(); } /// /// Executes the operation /// /// The backend to execute the operation on /// The cancellation token /// An awaitable task public abstract Task ExecuteAsync(IBackend backend, CancellationToken cancelToken); } }