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);
}
}