public override async Task <PageReadResult> MovePreviousAsync(CancellationToken cancellationToken) { int page; lock (_pageLock) { page = CurrentPage - 1; if (page < 1) { return(new PageReadResult(PagedFeed.GetUriForPage(page), new List <ScrapedSong>(), null, null, 0, new IndexOutOfRangeException($"Page {page} is below the minimum of 1."), PageErrorType.PageOutOfRange)); } CurrentPage--; } if (cancellationToken.IsCancellationRequested) { return(PageReadResult.CancelledResult(PagedFeed.GetUriForPage(page))); } Task <PageReadResult> pageTask; PageReadResult? result = null; if (TryGetCachedPage(page, out Task <PageReadResult>?cachedTask) && cachedTask != null) { if (cachedTask.IsCompleted) { return(await cachedTask.ConfigureAwait(false)); } else { using (CancellationTokenSource? tcs = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken)) { bool completed = await Utilities.WaitUntil(() => cachedTask.IsCompleted, tcs.Token).ConfigureAwait(false); if (completed) { result = await cachedTask.ConfigureAwait(false); } else { return(PageReadResult.CancelledResult(PagedFeed.GetUriForPage(page))); } } } } else { if (cancellationToken.IsCancellationRequested) { return(PageReadResult.CancelledResult(PagedFeed.GetUriForPage(page))); } Uri uri = PagedFeed.GetUriForPage(page); pageTask = PagedFeed.GetSongsAsync(uri, cancellationToken); if (EnablePageCache && CachedPages != null) { CachedPages.TryAdd(page, pageTask); } result = await pageTask.ConfigureAwait(false); } return(result); }
public override async Task <PageReadResult> MoveNextAsync(CancellationToken cancellationToken) { PageReadResult?result = null; Uri? pageUri = null; FeedDate feedDate = default; bool criticalFailure = false; try { await _semaphore.WaitAsync(cancellationToken); feedDate = new FeedDate(CurrentEarliest, DateDirection.Before); pageUri = DatedFeed.GetUriForDate(feedDate); if (pageUri == LastFetchedUri) { criticalFailure = true; throw new FeedReaderException($"URL '{pageUri}' was previously read, aborting to avoid possible infinite loop."); } result = await DatedFeed.GetSongsAsync(pageUri, cancellationToken).ConfigureAwait(false); LastFetchedUri = pageUri; } catch (OperationCanceledException ex) { result = PageReadResult.CancelledResult(pageUri, ex); } catch (Exception ex) { if (criticalFailure) { throw; } result = new PageReadResult(pageUri, null, null, null, 0, ex, PageErrorType.Unknown); } finally { ProcessResult(result, feedDate.Direction); _semaphore.Release(); } return(result); }
public override async Task <PageReadResult> MoveNextAsync(CancellationToken cancellationToken) { int page; lock (_pageLock) { CurrentPage++; page = CurrentPage; } if (cancellationToken.IsCancellationRequested) { return(PageReadResult.CancelledResult(PagedFeed.GetUriForPage(page))); } Task <PageReadResult> pageTask; PageReadResult? result = null; if (TryGetCachedPage(page, out Task <PageReadResult>?cachedTask) && cachedTask != null) { if (cachedTask.IsCompleted) { return(await cachedTask.ConfigureAwait(false)); } else { using (CancellationTokenSource? tcs = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken)) { bool completed = await Utilities.WaitUntil(() => cachedTask.IsCompleted, tcs.Token).ConfigureAwait(false); if (completed) { result = await cachedTask.ConfigureAwait(false); } else { return(PageReadResult.CancelledResult(PagedFeed.GetUriForPage(page))); } } } } else { if (cancellationToken.IsCancellationRequested) { return(PageReadResult.CancelledResult(PagedFeed.GetUriForPage(page))); } Uri uri = PagedFeed.GetUriForPage(page); pageTask = PagedFeed.GetSongsAsync(uri, cancellationToken); if (EnablePageCache && CachedPages != null) { CachedPages.TryAdd(page, pageTask); } result = await pageTask.ConfigureAwait(false); } if (result.IsLastPage) { CanMoveNext = false; LastPage = Math.Min(LastPage, page); } return(result); }