3using System.IO.Compression;
5using System.Threading.Tasks;
17 internal sealed
class InternetCacheService : LoadableService, IInternetCacheService
19 private static readonly TimeSpan defaultExpiry = Constants.Cache.DefaultImageCache;
20 private readonly FileCacheManager cacheManager;
22 public InternetCacheService()
24 this.cacheManager =
new FileCacheManager(
"InternetCache", defaultExpiry);
27 public override async Task Load(
bool IsResuming, CancellationToken CancellationToken)
29 if (this.
BeginLoad(IsResuming, CancellationToken))
43 public Task<(
byte[]? Data,
string ContentType)> TryGet(Uri Uri)
44 => this.cacheManager.TryGet(Uri.AbsoluteUri);
46 public async Task<(
byte[]? Data,
string ContentType)> GetOrFetch(Uri Uri,
string ParentId,
bool Permanent)
48 return await this.GetOrFetch(Uri, ParentId, Permanent, TimeSpan.FromSeconds(60));
51 public async Task<(
byte[]? Data,
string ContentType)> GetOrFetch(Uri Uri,
string ParentId,
bool Permanent, TimeSpan Timeout)
54 (
byte[]? Cached,
string CachedType,
bool IsExpired) = await this.cacheManager.TryGetWithExpiry(Uri.AbsoluteUri);
55 if (Cached is not
null && !IsExpired)
56 return (Cached, CachedType);
58 double TimeoutMsDouble = Math.Min(Math.Max(Timeout.TotalMilliseconds, 1d),
int.MaxValue);
59 int TimeoutMs = (int)TimeoutMsDouble;
63 App.ValidateCertificateCallback,
68 if (Cached is not
null)
69 return (Cached,
string.IsNullOrEmpty(CachedType) ?
"" : CachedType);
71 return (
null,
string.Empty);
74 byte[] Bytes = Response.
Encoded;
78 Bytes = TryDecompress(Bytes);
80 await this.cacheManager.AddOrUpdate(Uri.AbsoluteUri, ParentId, Permanent, Bytes, Type);
84 public Task<bool> Remove(Uri Uri)
85 => this.cacheManager.Remove(Uri.AbsoluteUri);
87 public Task MakeTemporary(
string ParentId)
88 => this.cacheManager.MakeTemporary(ParentId);
90 public Task MakePermanent(
string ParentId)
91 => this.cacheManager.MakePermanent(ParentId);
93 public Task<int> RemoveByParentId(
string ParentId)
94 => this.cacheManager.RemoveByParentId(ParentId);
96 #region 🔧 Decompression Helpers
98 private static bool IsGzip(
byte[] data)
99 => data.Length > 2 && data[0] == 0x1F && data[1] == 0x8B;
101 private static byte[] TryDecompress(
byte[] data)
107 using var input =
new MemoryStream(data);
108 using var gzip =
new GZipStream(input, CompressionMode.Decompress);
109 using var output =
new MemoryStream();
111 return output.ToArray();
117 using var input =
new MemoryStream(data);
118 using var br =
new BrotliStream(input, CompressionMode.Decompress);
119 using var output =
new MemoryStream();
121 return output.ToArray();
bool BeginLoad(bool IsResuming, CancellationToken CancellationToken)
Sets the IsLoading flag if the service isn't already loading.
void EndLoad(bool isLoaded)
Sets the IsLoading and IsLoaded flags and fires an event representing the current load state of the s...
bool IsResuming
If App is resuming service.
Contains information about a response to a content request.
byte[] Encoded
Encoded object.
string ContentType
Internet Content-Type of encoded object.
bool HasError
If an error occurred.
Static class managing encoding and decoding of internet content.
static Task< ContentResponse > GetAsync(Uri Uri, params KeyValuePair< string, string >[] Headers)
Gets a resource, given its URI.
ContentType
DTLS Record content type.