Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
InternetCacheService.cs
1using System;
2using System.IO;
3using System.IO.Compression;
4using System.Threading;
5using System.Threading.Tasks;
9using Waher.Content;
10
12{
16 [Singleton]
17 internal sealed class InternetCacheService : LoadableService, IInternetCacheService
18 {
19 private static readonly TimeSpan defaultExpiry = Constants.Cache.DefaultImageCache; // 7d
20 private readonly FileCacheManager cacheManager;
21
22 public InternetCacheService()
23 {
24 this.cacheManager = new FileCacheManager("InternetCache", defaultExpiry);
25 }
26
27 public override async Task Load(bool IsResuming, CancellationToken CancellationToken)
28 {
29 if (this.BeginLoad(IsResuming, CancellationToken))
30 {
31 try
32 {
33 this.EndLoad(true);
34 }
35 catch
36 {
37 this.EndLoad(false);
38 throw;
39 }
40 }
41 }
42
43 public Task<(byte[]? Data, string ContentType)> TryGet(Uri Uri)
44 => this.cacheManager.TryGet(Uri.AbsoluteUri);
45
46 public async Task<(byte[]? Data, string ContentType)> GetOrFetch(Uri Uri, string ParentId, bool Permanent)
47 {
48 return await this.GetOrFetch(Uri, ParentId, Permanent, TimeSpan.FromSeconds(60));
49 }
50
51 public async Task<(byte[]? Data, string ContentType)> GetOrFetch(Uri Uri, string ParentId, bool Permanent, TimeSpan Timeout)
52 {
53 // Check cache (allow expired entries as fallback)
54 (byte[]? Cached, string CachedType, bool IsExpired) = await this.cacheManager.TryGetWithExpiry(Uri.AbsoluteUri);
55 if (Cached is not null && !IsExpired)
56 return (Cached, CachedType);
57
58 double TimeoutMsDouble = Math.Min(Math.Max(Timeout.TotalMilliseconds, 1d), int.MaxValue);
59 int TimeoutMs = (int)TimeoutMsDouble;
61 Uri,
62 null,
63 App.ValidateCertificateCallback,
64 TimeoutMs);
65
66 if (Response.HasError || Response.Encoded is null || string.IsNullOrEmpty(Response.ContentType))
67 {
68 if (Cached is not null)
69 return (Cached, string.IsNullOrEmpty(CachedType) ? "" : CachedType);
70
71 return (null, string.Empty);
72 }
73
74 byte[] Bytes = Response.Encoded;
75 string Type = Response.ContentType;
76
77 // 🔽 NEW: Transparent decompression
78 Bytes = TryDecompress(Bytes);
79
80 await this.cacheManager.AddOrUpdate(Uri.AbsoluteUri, ParentId, Permanent, Bytes, Type);
81 return (Bytes, Type);
82 }
83
84 public Task<bool> Remove(Uri Uri)
85 => this.cacheManager.Remove(Uri.AbsoluteUri);
86
87 public Task MakeTemporary(string ParentId)
88 => this.cacheManager.MakeTemporary(ParentId);
89
90 public Task MakePermanent(string ParentId)
91 => this.cacheManager.MakePermanent(ParentId);
92
93 public Task<int> RemoveByParentId(string ParentId)
94 => this.cacheManager.RemoveByParentId(ParentId);
95
96 #region 🔧 Decompression Helpers
97
98 private static bool IsGzip(byte[] data)
99 => data.Length > 2 && data[0] == 0x1F && data[1] == 0x8B;
100
101 private static byte[] TryDecompress(byte[] data)
102 {
103 try
104 {
105 if (IsGzip(data))
106 {
107 using var input = new MemoryStream(data);
108 using var gzip = new GZipStream(input, CompressionMode.Decompress);
109 using var output = new MemoryStream();
110 gzip.CopyTo(output);
111 return output.ToArray();
112 }
113
114 // Try Brotli
115 try
116 {
117 using var input = new MemoryStream(data);
118 using var br = new BrotliStream(input, CompressionMode.Decompress);
119 using var output = new MemoryStream();
120 br.CopyTo(output);
121 return output.ToArray();
122 }
123 catch
124 {
125 // Not Brotli — return original
126 return data;
127 }
128 }
129 catch
130 {
131 // Failed decompression — return original
132 return data;
133 }
134 }
135
136 #endregion
137 }
138}
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.
Definition: Enumerations.cs:11