Files
SnowcloakClient/MareSynchronos/WebAPI/Files/Models/ProgressableStreamContent.cs
2025-08-22 02:19:48 +01:00

93 lines
2.4 KiB
C#

using System.Net;
namespace MareSynchronos.WebAPI.Files.Models;
public class ProgressableStreamContent : StreamContent
{
private const int _defaultBufferSize = 4096;
private readonly int _bufferSize;
private readonly IProgress<UploadProgress>? _progress;
private readonly Stream _streamToWrite;
private bool _contentConsumed;
public ProgressableStreamContent(Stream streamToWrite, IProgress<UploadProgress>? downloader)
: this(streamToWrite, _defaultBufferSize, downloader)
{
}
public ProgressableStreamContent(Stream streamToWrite, int bufferSize, IProgress<UploadProgress>? progress)
: base(streamToWrite, bufferSize)
{
if (streamToWrite == null)
{
throw new ArgumentNullException(nameof(streamToWrite));
}
if (bufferSize <= 0)
{
throw new ArgumentOutOfRangeException(nameof(bufferSize));
}
_streamToWrite = streamToWrite;
_bufferSize = bufferSize;
_progress = progress;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_streamToWrite.Dispose();
}
base.Dispose(disposing);
}
protected override async Task SerializeToStreamAsync(Stream stream, TransportContext? context)
{
PrepareContent();
var buffer = new byte[_bufferSize];
var size = _streamToWrite.Length;
var uploaded = 0;
using (_streamToWrite)
{
while (true)
{
var length = await _streamToWrite.ReadAsync(buffer).ConfigureAwait(false);
if (length <= 0)
{
break;
}
uploaded += length;
_progress?.Report(new UploadProgress(uploaded, size));
await stream.WriteAsync(buffer.AsMemory(0, length)).ConfigureAwait(false);
}
}
}
protected override bool TryComputeLength(out long length)
{
length = _streamToWrite.Length;
return true;
}
private void PrepareContent()
{
if (_contentConsumed)
{
if (_streamToWrite.CanSeek)
{
_streamToWrite.Position = 0;
}
else
{
throw new InvalidOperationException("The stream has already been read.");
}
}
_contentConsumed = true;
}
}