using Beam.Abstractions; using Beam.Models; using Microsoft.Extensions.Logging; namespace Beam.Downloaders { public class SequentialDownloader : IAsyncEnumerator { public OutType Current { get; protected set; } public DownloadContext Context { get; } public ILogger? Logger { get; set; } public int LastOrder { get; set; } = 0; protected IEnumerator LinksEnumerator; public Func> GetUnitDownloader { get; set; } public SequentialDownloader(DownloadContext context, Func, IUnitDownloader> getUnitDownloader, ILogger? logger = null) { Context = context; Logger = logger; LinksEnumerator = Context.Links.GetEnumerator(); try { LinksEnumerator.Reset(); } catch (NotSupportedException) { Logger?.LogWarning("Enumerator of type {} does not support resets. This may cause buggy behavior", LinksEnumerator.GetType()); } Current = default(OutType); GetUnitDownloader = () => getUnitDownloader(Context); } public ValueTask DisposeAsync() { GC.SuppressFinalize(this); return ValueTask.CompletedTask; } public async ValueTask MoveNextAsync() { if (!LinksEnumerator.MoveNext()) return false; //Logger?.LogInformation("MoveNextAsync()"); var unit = GetUnitDownloader(); // safe to instantiate per request. var idealLinkCount = unit.LinksPerDownload; List> links = []; //Logger?.LogInformation("MoveNextAsync() \n\t -> Links.Current = {} ", LinksEnumerator.Current.Link.AbsoluteUri); links.Add(new Ordered(LinksEnumerator.Current, LastOrder++)); while (links.Count < idealLinkCount && LinksEnumerator.MoveNext()) { if (string.IsNullOrWhiteSpace(LinksEnumerator.Current)) { return false; } links.Add(new Ordered(LinksEnumerator.Current, LastOrder++)); } //Logger?.LogInformation("MoveNextAsync() \n\t -> links.Count = {} ", links.Count); if (links.Count == 0) { Logger?.LogInformation("Out of links!"); return false; } if (links.Any((x) => string.IsNullOrWhiteSpace(x.Data))) return false; var (result, downloadedT) = await unit.TryDownload( links.ToArray(), Context.CancellationToken, downProgress: Context.DownloadReporter, tryProgress: Context.RetryReporter); if (!result) { Logger?.LogWarning("Failed to download Unit<{}>", typeof(OutType).Name); return false; // unit download failed } if (downloadedT is null) { Logger?.LogWarning("Failed to download Unit<{}>", typeof(OutType).Name); return false; // unit download failed } Current = downloadedT; return true; } } }