using System.Buffers;
using System.IO;
using System.Net.Http;
using System.Net;
using System.Threading.Tasks;
namespace Sandbox.Utility;
///
/// Provides progress information for operations that process blocks of data,
/// such as file uploads, downloads, or large data transfers.
///
public struct DataProgress
{
///
/// The number of bytes processed so far.
///
public long ProgressBytes { get; set; }
///
/// The total number of bytes to process.
///
public long TotalBytes { get; set; }
///
/// The number of bytes processed since the last progress update.
///
public long DeltaBytes { get; set; }
///
/// Progress as a fraction from 0.0 to 1.0.
///
public float ProgressDelta => (float)((double)ProgressBytes / (double)TotalBytes).Clamp( 0.0, 1.0 );
///
/// Callback delegate for receiving progress updates.
///
public delegate void Callback( DataProgress progress );
///
/// HTTP content wrapper that reports upload progress through DataProgress callbacks.
/// Used internally for tracking file upload progress.
///
internal class HttpContentStream : HttpContent
{
private readonly Stream stream;
private readonly int bufferSize;
private readonly long length;
///
/// Callback invoked as data is being uploaded.
///
public Callback Progress { get; set; }
///
/// Creates a new HTTP content stream with progress tracking.
///
/// The source stream to upload
/// Size of buffer for chunked uploads (default 256KB)
public HttpContentStream( Stream stream, int bufferSize = 1024 * 256 )
{
this.stream = stream;
this.bufferSize = bufferSize;
this.length = stream.Length;
}
protected override async Task SerializeToStreamAsync( Stream stream, TransportContext context )
{
var buffer = new byte[bufferSize];
int bytesRead;
long bytesTransferred = 0;
while ( (bytesRead = await this.stream.ReadAsync( buffer, 0, buffer.Length )) > 0 )
{
await stream.WriteAsync( buffer, 0, bytesRead );
bytesTransferred += bytesRead;
Progress?.Invoke( new DataProgress { TotalBytes = length, ProgressBytes = bytesTransferred, DeltaBytes = bytesRead } );
}
}
protected override bool TryComputeLength( out long length )
{
length = this.length;
return true;
}
}
}