in src/build/Infra/ArtifactsApi.cs [134:186]
public static async Task<(bool wasAlreadyPresent, string localPath)> FetchArtifact(
BuildContext ctx, ArtifactPackage ap, bool forceSwitch,
Action<long, long> fetchProgress = null, Action<long> fetchComplete = null)
{
var localPath = Path.Combine(ctx.InDir, ap.FileName);
if (!forceSwitch && File.Exists(localPath))
return (true, localPath);
if (!ap.IsDownloadable)
throw new Exception($"{ap.FileName} is missing {nameof(ap.Url)}");
localPath = Path.Combine(ctx.InDir, Path.GetFileName(ap.Url));
Directory.CreateDirectory(ctx.InDir);
using var http = new HttpClient();
using var stm = await http.GetStreamAsync(ap.Url);
using var fs = File.Open(localPath, FileMode.Create, FileAccess.Write);
// Buffer size just shy of one that would get onto LOH
// (hopefully ArrayPool will oblige...)
var bytes = ArrayPool<byte>.Shared.Rent(81920);
try
{
int bytesRead = 0;
long bytesReadTotal = 0;
while (true)
{
if ((bytesRead = await stm.ReadAsync(bytes, 0, bytes.Length)) <= 0)
break;
bytesReadTotal += bytesRead;
var writeTask = fs.WriteAsync(bytes, 0, bytesRead);
fetchProgress?.Invoke(bytesRead, bytesReadTotal);
await writeTask;
}
fetchComplete?.Invoke(bytesReadTotal);
}
finally
{
if (bytes != null)
ArrayPool<byte>.Shared.Return(bytes);
}
return (false, localPath);
}