namespace LeagueAPI; public class HttpCache : Dictionary> { } public record struct InvalidatableCacheObject( T Value, DateTime? InvalidateTime = null ) { public readonly bool IsValid() { return !InvalidateTime.HasValue || InvalidateTime < DateTime.UtcNow; } } public class CachingHttpClient : IDisposable { private bool _isDisposed; private readonly HttpCache _cache = ResourceService.GetHttpCache() ?? []; private readonly HttpClient _client = new(); public CachingHttpClient(bool insecure = false) { if (insecure) { HttpClientHandler handler = new() { ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator }; _client = new(handler); } else { _client = new(); } } public async Task GetStringAsync(string requestUri, TimeSpan? invalidateAfter = null) { if (_cache.TryGetValue(requestUri, out InvalidatableCacheObject response) && response.IsValid()) { return response.Value; } string result = await _client.GetStringAsync(requestUri); if (invalidateAfter is not null && invalidateAfter > TimeSpan.Zero) { _cache[requestUri] = new(result, DateTime.UtcNow + invalidateAfter); } else { _cache[requestUri] = new(result); } return result; } #region IDisposable protected virtual void Dispose(bool disposing) { if (!_isDisposed) { if (disposing) { _client?.Dispose(); } _cache?.Clear(); _isDisposed = true; } } public void Dispose() { // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method Dispose(disposing: true); GC.SuppressFinalize(this); } #endregion }