Added identifier and fetch time product listings; Added persistence to AdafruitShop.

Implemented in AdafruitShop.

AdafruitShop Product listing data now persisted.

AdafruitShop configuration now persisted.
This commit is contained in:
2021-08-09 13:32:16 -05:00
parent 38ffb3c7e1
commit 0b507b90a1
28 changed files with 251 additions and 349 deletions

View File

@@ -1,6 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Props.Shop.Framework;
using Xunit;

View File

@@ -11,31 +11,29 @@ namespace Props.Shop.Adafruit.Tests.Api
{
public class FakeProductListingManager : IProductListingManager
{
private Timer refreshTimer;
private bool disposedValue;
private volatile Task<IDictionary<string, IList<ProductListing>>> activeListings;
private DateTime? lastDownload;
private ProductListingsParser parser = new ProductListingsParser();
private readonly ConcurrentDictionary<string, ProductListing> activeProductListingUrls = new ConcurrentDictionary<string, ProductListing>();
public Task<IDictionary<string, IList<ProductListing>>> ProductListings => activeListings;
public Task<IReadOnlyDictionary<string, IList<ProductListing>>> ProductListings { get; private set; }
public async Task<ProductListing> GetProductListingFromUrl(string url)
public async Task<ProductListing> GetProductListingFromIdentifier(string url)
{
if (disposedValue) throw new ObjectDisposedException("ProductListingManager");
await activeListings;
await ProductListings;
return activeProductListingUrls[url];
}
public void RefreshProductListings()
{
if (disposedValue) throw new ObjectDisposedException("ProductListingManager");
if ((lastDownload != null && DateTime.UtcNow - lastDownload <= TimeSpan.FromMilliseconds(5 * 60 * 1000)) || (activeListings != null && !activeListings.IsCompleted)) return;
activeListings = DownloadListings();
if ((lastDownload != null && DateTime.UtcNow - lastDownload <= TimeSpan.FromMilliseconds(5 * 60 * 1000)) || (ProductListings != null && !ProductListings.IsCompleted)) return;
ProductListings = DownloadListings();
}
private Task<IDictionary<string, IList<ProductListing>>> DownloadListings() {
private Task<IReadOnlyDictionary<string, IList<ProductListing>>> DownloadListings() {
if (disposedValue) throw new ObjectDisposedException("ProductListingManager");
lastDownload = DateTime.UtcNow;
parser.BuildProductListings(File.OpenRead("./Assets/products.json"));
@@ -52,24 +50,16 @@ namespace Props.Shop.Adafruit.Tests.Api
sameProducts.Add(product);
}
return Task.FromResult<IDictionary<string, IList<ProductListing>>>(listingNames);
return Task.FromResult<IReadOnlyDictionary<string, IList<ProductListing>>>(listingNames);
}
public void StartUpdateTimer(int delay = 300000, int period = 300000)
{
if (disposedValue) throw new ObjectDisposedException("ProductListingManager");
if (refreshTimer != null) throw new InvalidOperationException("Refresh timer already running.");
refreshTimer = new Timer((state) => {
RefreshProductListings();
}, null, delay, period);
RefreshProductListings();
}
public void StopUpdateTimer()
{
if (disposedValue) throw new ObjectDisposedException("ProductListingManager");
if (refreshTimer == null) throw new InvalidOperationException("Refresh timer not running.");
refreshTimer.Dispose();
refreshTimer = null;
}
protected virtual void Dispose(bool disposing)
@@ -78,8 +68,6 @@ namespace Props.Shop.Adafruit.Tests.Api
{
if (disposing)
{
refreshTimer?.Dispose();
refreshTimer = null;
}
disposedValue = true;