props/Props.Shop/Adafruit/AdafruitShop.cs

172 lines
6.1 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Props.Shop.Adafruit.Api;
using Props.Shop.Adafruit.Persistence;
using Props.Shop.Framework;
namespace Props.Shop.Adafruit
{
public class AdafruitShop : IShop, IDisposable
{
private string workspaceDir;
private ILoggerFactory loggerFactory;
private ILogger<AdafruitShop> logger;
private SearchManager searchManager;
private Configuration configuration;
private HttpClient http;
private bool disposedValue;
public string ShopName => "Adafruit";
public string ShopDescription => "A electronic component online hardware company.";
public string ShopModuleAuthor => "Reslate";
public SupportedFeatures SupportedFeatures => new SupportedFeatures(
false,
false,
false,
false,
true
);
public async ValueTask Initialize(string workspaceDir, ILoggerFactory loggerFactory)
{
workspaceDir = workspaceDir ?? "";
this.workspaceDir = workspaceDir;
this.loggerFactory = loggerFactory;
logger = loggerFactory.CreateLogger<AdafruitShop>();
http = new HttpClient();
http.BaseAddress = new Uri("http://www.adafruit.com/api/");
string configPath = Path.Combine(workspaceDir, Configuration.FILE_NAME);
try
{
configuration = JsonSerializer.Deserialize<Configuration>(File.ReadAllText(configPath));
}
catch (JsonException e)
{
logger.LogWarning("Could not read JSON file \"{0}\": {1}", configPath, e.Message);
}
catch (ArgumentException)
{
logger.LogWarning("No working directory path provided.");
}
catch (DirectoryNotFoundException)
{
logger.LogWarning("Directory \"{0}\" could not be found.", Path.GetDirectoryName(configPath));
}
catch (FileNotFoundException)
{
logger.LogWarning("File \"{0}\" could not be found.", configPath);
}
finally
{
if (configuration == null)
{
configuration = new Configuration();
}
}
ProductListingCacheData listingData = null;
string cachePath = Path.Combine(workspaceDir, ProductListingCacheData.FILE_NAME);
try
{
using (Stream fileStream = File.OpenRead(cachePath))
{
listingData = await JsonSerializer.DeserializeAsync<ProductListingCacheData>(fileStream);
}
}
catch (JsonException e)
{
logger.LogWarning("Could not read JSON file \"{0}\": {1}", cachePath, e.Message);
}
catch (ArgumentException)
{
logger.LogWarning("No working directory path provided.");
}
catch (DirectoryNotFoundException)
{
logger.LogWarning("Directory \"{0}\" could not be found.", Path.GetDirectoryName(cachePath));
}
catch (FileNotFoundException)
{
logger.LogWarning("File \"{0}\" could not be found.", cachePath);
}
finally
{
if (configuration == null)
{
configuration = new Configuration();
}
}
LiveProductListingManager productListingManager = new LiveProductListingManager(http, loggerFactory.CreateLogger<LiveProductListingManager>(), listingData, configuration.MinDownloadInterval);
this.searchManager = new SearchManager(productListingManager, configuration.Similarity);
productListingManager.StartUpdateTimer(delay: 0, configuration.CacheLifespan);
}
public async Task<ProductListing> GetProductFromIdentifier(string identifier)
{
return await searchManager.ProductListingManager.GetProductListingFromIdentifier(identifier);
}
public IAsyncEnumerable<ProductListing> Search(string query, Filters filters)
{
return searchManager.Search(query);
}
public async ValueTask SaveData()
{
if (workspaceDir != null)
{
logger.LogDebug("Saving data in \"{0}\"...", workspaceDir);
string configurationPath = Path.Combine(workspaceDir, Configuration.FILE_NAME);
File.Delete(configurationPath);
await File.WriteAllTextAsync(Path.Combine(workspaceDir, Configuration.FILE_NAME), JsonSerializer.Serialize(configuration));
string productListingCachePath = Path.Combine(workspaceDir, ProductListingCacheData.FILE_NAME);
File.Delete(productListingCachePath);
using (Stream fileStream = File.OpenWrite(productListingCachePath))
{
await JsonSerializer.SerializeAsync(fileStream, new ProductListingCacheData(await searchManager.ProductListingManager.ProductListings));
}
logger.LogDebug("Completed saving data.");
}
}
public async ValueTask DisposeAsync()
{
Dispose(true);
await DisposeAsyncCore();
}
protected virtual async ValueTask DisposeAsyncCore()
{
await SaveData();
}
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
http.Dispose();
searchManager.Dispose();
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
}