Tracker list caching with configurable expiration
Add new option to general settings that allows the user to set the time in minutes to cache the tracker list. 0 disables caching. Default value is 60.
This commit is contained in:
parent
80a8a1020c
commit
408c475af5
3 changed files with 77 additions and 16 deletions
|
|
@ -77,7 +77,11 @@ Supports the following parameters:
|
|||
|
||||
[DisplayName("Tracker enrichment list")]
|
||||
[Description("Optional. Specify the URL of a tracker list file to be appended to magnet links and torrent files.")]
|
||||
public String? MagnetTrackerEnrichment { get; set; } = null;
|
||||
public String? TrackerEnrichmentList { get; set; } = null;
|
||||
|
||||
[DisplayName("Tracker enrichment cache expiration")]
|
||||
[Description("The time in minutes to cache the tracker list. Set to 0 to disable caching.")]
|
||||
public Int32 TrackerEnrichmentCacheExpiration { get; set; } = 60;
|
||||
|
||||
[DisplayName("Disable update notifications")]
|
||||
[Description("Ignore update notifications. You will still be notified if the version you are running has a security vulnerability.")]
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ public static class DiConfig
|
|||
|
||||
public static void RegisterRdtServices(this IServiceCollection services)
|
||||
{
|
||||
services.AddMemoryCache();
|
||||
|
||||
services.AddSingleton<IAllDebridNetClientFactory, AllDebridNetClientFactory>();
|
||||
services.AddScoped<AllDebridTorrentClient>();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,34 +1,89 @@
|
|||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace RdtClient.Service.Services;
|
||||
|
||||
public class TrackerListGrabber : ITrackerListGrabber
|
||||
public class TrackerListGrabber(IHttpClientFactory httpClientFactory, IMemoryCache memoryCache, ILogger<TrackerListGrabber> logger) : ITrackerListGrabber
|
||||
{
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private const String CacheKey = "TrackerList";
|
||||
|
||||
public TrackerListGrabber(IHttpClientFactory httpClientFactory)
|
||||
{
|
||||
_httpClientFactory = httpClientFactory;
|
||||
}
|
||||
private Int32? _lastExpirationMinutes;
|
||||
|
||||
private static readonly SemaphoreSlim Semaphore = new(1, 1);
|
||||
|
||||
public async Task<String[]> GetTrackers()
|
||||
{
|
||||
var trackerUrlList = Settings.Get.General.MagnetTrackerEnrichment;
|
||||
if (String.IsNullOrWhiteSpace(trackerUrlList))
|
||||
var currentExpiration = Settings.Get.General.TrackerEnrichmentCacheExpiration;
|
||||
var useCache = currentExpiration > 0;
|
||||
|
||||
if (!useCache)
|
||||
{
|
||||
return [];
|
||||
memoryCache.Remove(CacheKey);
|
||||
_lastExpirationMinutes = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_lastExpirationMinutes is not null && currentExpiration != _lastExpirationMinutes)
|
||||
{
|
||||
logger.LogDebug("Tracker list cache timeout changed, invalidating cache.");
|
||||
memoryCache.Remove(CacheKey);
|
||||
}
|
||||
|
||||
_lastExpirationMinutes = currentExpiration;
|
||||
|
||||
if (memoryCache.TryGetValue(CacheKey, out String[]? cachedTrackers) && cachedTrackers is { Length: > 0 })
|
||||
{
|
||||
logger.LogDebug("Using cached tracker list.");
|
||||
|
||||
return cachedTrackers;
|
||||
}
|
||||
}
|
||||
|
||||
await Semaphore.WaitAsync();
|
||||
|
||||
try
|
||||
{
|
||||
var httpClient = _httpClientFactory.CreateClient();
|
||||
var result = await httpClient.GetStringAsync(trackerUrlList);
|
||||
return result
|
||||
.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToArray();
|
||||
logger.LogDebug("Tracker cache miss or cache disabled. Fetching tracker list.");
|
||||
var trackerUrlList = Settings.Get.General.TrackerEnrichmentList;
|
||||
|
||||
if (String.IsNullOrWhiteSpace(trackerUrlList))
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
var httpClient = httpClientFactory.CreateClient();
|
||||
var response = await httpClient.GetAsync(trackerUrlList);
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var result = await response.Content.ReadAsStringAsync();
|
||||
|
||||
var trackers = result
|
||||
.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToArray();
|
||||
|
||||
if (useCache)
|
||||
{
|
||||
memoryCache.Set(CacheKey,
|
||||
trackers,
|
||||
new MemoryCacheEntryOptions
|
||||
{
|
||||
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(currentExpiration)
|
||||
});
|
||||
}
|
||||
|
||||
return trackers;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Unable to fetch tracker list.");
|
||||
|
||||
throw new InvalidOperationException("Unable to fetch tracker list for enrichment.", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Semaphore.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue