using System;
using System.Management.Automation;
using System.Threading;
using System.Threading.Tasks;
namespace Kubectl {
///
/// Base class for Cmdlets that run asynchronously.
///
///
/// Inherit from this class if your Cmdlet needs to use async / await functionality.
///
public abstract class AsyncCmdlet
: PSCmdlet, IDisposable {
///
/// The source for cancellation tokens that can be used to cancel the operation.
///
readonly CancellationTokenSource _cancellationSource = new CancellationTokenSource();
///
/// Initialise the .
///
protected AsyncCmdlet() {
}
///
/// Finaliser for .
///
~AsyncCmdlet() {
Dispose(false);
}
///
/// Dispose of resources being used by the Cmdlet.
///
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
///
/// Dispose of resources being used by the Cmdlet.
///
///
/// Explicit disposal?
///
protected virtual void Dispose(bool disposing) {
if (disposing)
_cancellationSource.Dispose();
}
///
/// Asynchronously perform Cmdlet pre-processing.
///
///
/// A representing the asynchronous operation.
///
protected virtual Task BeginProcessingAsync() {
return BeginProcessingAsync(_cancellationSource.Token);
}
///
/// Asynchronously perform Cmdlet pre-processing.
///
///
/// A that can be used to cancel the asynchronous operation.
///
///
/// A representing the asynchronous operation.
///
protected virtual Task BeginProcessingAsync(CancellationToken cancellationToken) {
return Task.CompletedTask;
}
///
/// Asynchronously perform Cmdlet processing.
///
///
/// A representing the asynchronous operation.
///
protected virtual Task ProcessRecordAsync() {
return ProcessRecordAsync(_cancellationSource.Token);
}
///
/// Asynchronously perform Cmdlet processing.
///
///
/// A that can be used to cancel the asynchronous operation.
///
///
/// A representing the asynchronous operation.
///
protected virtual Task ProcessRecordAsync(CancellationToken cancellationToken) {
return Task.CompletedTask;
}
///
/// Asynchronously perform Cmdlet post-processing.
///
///
/// A representing the asynchronous operation.
///
protected virtual Task EndProcessingAsync() {
return EndProcessingAsync(_cancellationSource.Token);
}
///
/// Asynchronously perform Cmdlet post-processing.
///
///
/// A that can be used to cancel the asynchronous operation.
///
///
/// A representing the asynchronous operation.
///
protected virtual Task EndProcessingAsync(CancellationToken cancellationToken) {
return Task.CompletedTask;
}
///
/// Perform Cmdlet pre-processing.
///
protected sealed override void BeginProcessing() {
ThreadAffinitiveSynchronizationContext.RunSynchronized(
() => BeginProcessingAsync()
);
}
///
/// Perform Cmdlet processing.
///
protected sealed override void ProcessRecord() {
ThreadAffinitiveSynchronizationContext.RunSynchronized(
() => ProcessRecordAsync()
);
}
///
/// Perform Cmdlet post-processing.
///
protected sealed override void EndProcessing() {
ThreadAffinitiveSynchronizationContext.RunSynchronized(
() => EndProcessingAsync()
);
}
///
/// Interrupt Cmdlet processing (if possible).
///
protected sealed override void StopProcessing() {
_cancellationSource.Cancel();
base.StopProcessing();
}
///
/// Write a progress record to the output stream, and as a verbose message.
///
///
/// The progress record to write.
///
protected void WriteVerboseProgress(ProgressRecord progressRecord) {
if (progressRecord == null)
throw new ArgumentNullException(nameof(progressRecord));
WriteProgress(progressRecord);
WriteVerbose(progressRecord.StatusDescription);
}
///
/// Write a progress record to the output stream, and as a verbose message.
///
///
/// The progress record to write.
///
///
/// The message or message-format specifier.
///
///
/// Optional format arguments.
///
protected void WriteVerboseProgress(ProgressRecord progressRecord, string messageOrFormat, params object[] formatArguments) {
if (progressRecord == null)
throw new ArgumentNullException(nameof(progressRecord));
if (String.IsNullOrWhiteSpace(messageOrFormat))
throw new ArgumentException("Argument cannot be null, empty, or composed entirely of whitespace: 'messageOrFormat'.", nameof(messageOrFormat));
if (formatArguments == null)
throw new ArgumentNullException(nameof(formatArguments));
progressRecord.StatusDescription = String.Format(messageOrFormat, formatArguments);
WriteVerboseProgress(progressRecord);
}
///
/// Write a completed progress record to the output stream.
///
///
/// The progress record to complete.
///
///
/// The completion message or message-format specifier.
///
///
/// Optional format arguments.
///
protected void WriteProgressCompletion(ProgressRecord progressRecord, string completionMessageOrFormat, params object[] formatArguments) {
if (progressRecord == null)
throw new ArgumentNullException(nameof(progressRecord));
if (String.IsNullOrWhiteSpace(completionMessageOrFormat))
throw new ArgumentException("Argument cannot be null, empty, or composed entirely of whitespace: 'completionMessageOrFormat'.", nameof(completionMessageOrFormat));
if (formatArguments == null)
throw new ArgumentNullException(nameof(formatArguments));
progressRecord.StatusDescription = String.Format(completionMessageOrFormat, formatArguments);
progressRecord.PercentComplete = 100;
progressRecord.RecordType = ProgressRecordType.Completed;
WriteProgress(progressRecord);
WriteVerbose(progressRecord.StatusDescription);
}
}
}