Skip to content

Commit

Permalink
Add retry handler with polly to intercept 429 rate limit errors with …
Browse files Browse the repository at this point in the history
…Real-Debrid.
  • Loading branch information
rogerfar committed Jul 14, 2024
1 parent 343d2d0 commit 8dd0eec
Show file tree
Hide file tree
Showing 15 changed files with 59 additions and 93 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.0.80] - 2024-07-13
### Changed
- Add rate limiter to retry requests that are rate limited from Real-Debrid.
- Optimize calls to Real-Debrid API when torrents are finished and periodic updates.
- Update to .NET 8.0.7

## [2.0.79] - 2024-06-03
### Changed
- Fixed issue with qBittorrent progress sometimes throwing errors.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "rdt-client",
"version": "2.0.79",
"version": "2.0.80",
"description": "This is a web interface to manage your torrents on Real-Debrid.",
"main": "index.js",
"dependencies": {
Expand Down
12 changes: 6 additions & 6 deletions server/RdtClient.Data/RdtClient.Data.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.3" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="8.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="8.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.3">
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.7" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="8.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="8.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Serilog" Version="3.1.1" />
<PackageReference Include="Serilog" Version="4.0.0" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
return;
}

CurrentVersion = $"v{version[..version.LastIndexOf(".", StringComparison.Ordinal)]}";
CurrentVersion = $"v{version[..version.LastIndexOf('.')]}";

logger.LogInformation("UpdateChecker started, currently on version {CurrentVersion}.", CurrentVersion);

Expand Down
17 changes: 11 additions & 6 deletions server/RdtClient.Service/DiConfig.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
using Microsoft.AspNetCore.Authorization;
using System.Net;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Polly;
using Polly.Extensions.Http;
using RdtClient.Service.BackgroundServices;
using RdtClient.Service.Handlers;
using RdtClient.Service.Middleware;
using RdtClient.Service.Services;
using RdtClient.Service.Services.TorrentClients;
Expand Down Expand Up @@ -38,9 +39,13 @@ public static void RegisterRdtServices(this IServiceCollection services)
public static void RegisterHttpClients(this IServiceCollection services)
{
services.AddHttpClient();


var retryPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(r => r.StatusCode == HttpStatusCode.TooManyRequests)
.WaitAndRetryAsync(retryCount: 5, sleepDurationProvider: attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt)));

services.AddHttpClient(RD_CLIENT)
.AddHttpMessageHandler(sp => new RateLimitingHandler(sp.GetRequiredService<ILogger<RateLimitingHandler>>(), 60, TimeSpan.FromSeconds(60)))
.SetHandlerLifetime(Timeout.InfiniteTimeSpan);
.AddPolicyHandler(retryPolicy);
}
}
54 changes: 0 additions & 54 deletions server/RdtClient.Service/Handlers/RateLimitingHandler.cs

This file was deleted.

4 changes: 2 additions & 2 deletions server/RdtClient.Service/Helpers/DownloadHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public static class DownloadHelper

var matchingTorrentFiles = torrent.Files.Where(m => m.Path.EndsWith(fileName)).Where(m => !String.IsNullOrWhiteSpace(m.Path)).ToList();

if (matchingTorrentFiles.Any())
if (matchingTorrentFiles.Count > 0)
{
var matchingTorrentFile = matchingTorrentFiles[0];

Expand Down Expand Up @@ -71,7 +71,7 @@ public static class DownloadHelper

var matchingTorrentFiles = torrent.Files.Where(m => m.Path.EndsWith(fileName)).Where(m => !String.IsNullOrWhiteSpace(m.Path)).ToList();

if (matchingTorrentFiles.Any())
if (matchingTorrentFiles.Count > 0)
{
var matchingTorrentFile = matchingTorrentFiles[0];

Expand Down
5 changes: 1 addition & 4 deletions server/RdtClient.Service/Helpers/JsonModelBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ public class JsonModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
ArgumentNullException.ThrowIfNull(bindingContext);

var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (valueProviderResult != ValueProviderResult.None)
Expand Down
17 changes: 13 additions & 4 deletions server/RdtClient.Service/Middleware/BaseHrefMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,17 @@

namespace RdtClient.Service.Middleware;

public class BaseHrefMiddleware(RequestDelegate next, String basePath)
public partial class BaseHrefMiddleware(RequestDelegate next, String basePath)
{
[GeneratedRegex(@"<base href=""/""")]
private partial Regex BodyRegex();

[GeneratedRegex("(<script.*?src=\")(.*?)(\".*?</script>)")]
private partial Regex ScriptRegex();

[GeneratedRegex("(<link.*?href=\")(.*?)(\".*?>)")]
private partial Regex LinkRegex();

private readonly String _basePath = $"/{basePath.TrimStart('/').TrimEnd('/')}/";

public async Task InvokeAsync(HttpContext context)
Expand All @@ -27,10 +36,10 @@ public async Task InvokeAsync(HttpContext context)
{
if (context.Response.ContentType?.Contains("text/html") == true)
{
responseBody = Regex.Replace(responseBody, @"<base href=""/""", @$"<base href=""{_basePath}""");
responseBody = BodyRegex().Replace(responseBody, @$"<base href=""{_basePath}""");

responseBody = Regex.Replace(responseBody, "(<script.*?src=\")(.*?)(\".*?</script>)", $"$1{_basePath}$2$3");
responseBody = Regex.Replace(responseBody, "(<link.*?href=\")(.*?)(\".*?>)", $"$1{_basePath}$2$3");
responseBody = ScriptRegex().Replace(responseBody, $"$1{_basePath}$2$3");
responseBody = LinkRegex().Replace(responseBody, $"$1{_basePath}$2$3");

context.Response.Headers.Remove("Content-Length");
await context.Response.WriteAsync(responseBody);
Expand Down
11 changes: 7 additions & 4 deletions server/RdtClient.Service/RdtClient.Service.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,17 @@
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="AllDebrid.NET" Version="1.0.12" />
<PackageReference Include="Aria2.NET" Version="1.0.5" />
<PackageReference Include="Downloader" Version="3.0.6" />
<PackageReference Include="Downloader" Version="3.1.2" />
<PackageReference Include="Downloader.NET" Version="1.0.12" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="8.0.7" />
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="8.7.0" />
<PackageReference Include="MonoTorrent" Version="2.0.7" />
<PackageReference Include="Polly" Version="8.4.1" />
<PackageReference Include="Premiumize.NET" Version="1.0.4" />
<PackageReference Include="RD.NET" Version="2.1.4" />
<PackageReference Include="Serilog" Version="3.1.1" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="SharpCompress" Version="0.36.0" />
<PackageReference Include="Serilog" Version="4.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageReference Include="SharpCompress" Version="0.37.2" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public async Task<String> Download()
var filePath = new FileInfo(path);

var rcloneMountPath = Settings.Get.DownloadClient.RcloneMountPath.TrimEnd(['\\', '/']);
var searchSubDirectories = rcloneMountPath.EndsWith("*");
var searchSubDirectories = rcloneMountPath.EndsWith('*');
rcloneMountPath = rcloneMountPath.TrimEnd('*').TrimEnd(['\\', '/']);

if (!Directory.Exists(rcloneMountPath))
Expand Down
2 changes: 1 addition & 1 deletion server/RdtClient.Service/Services/RdtHub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class RdtHub : Hub
{
private static readonly ConcurrentDictionary<String, String> Users = new();

public static Boolean HasConnections => Users.Any();
public static Boolean HasConnections => !Users.IsEmpty;

public override async Task OnConnectedAsync()
{
Expand Down
2 changes: 1 addition & 1 deletion server/RdtClient.Service/Services/UnpackClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ private static async Task<IList<String>> GetArchiveFiles(String filePath)

var entries = archive.Entries
.Where(entry => !entry.IsDirectory)
.Select(m => m.Key)
.Select(m => m.Key!)
.ToList();

archive.Dispose();
Expand Down
2 changes: 1 addition & 1 deletion server/RdtClient.Web/Controllers/QBittorrentController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ public async Task<ActionResult> TorrentsDelete([FromQuery] QBTorrentsDeleteReque
return BadRequest();
}

logger.LogDebug($"Delete {request.Hashes}");
logger.LogDebug("Delete {Hashes}", request.Hashes);

var hashes = request.Hashes.Split("|");

Expand Down
14 changes: 7 additions & 7 deletions server/RdtClient.Web/RdtClient.Web.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,18 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="8.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="8.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.3">
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="8.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="8.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.3" />
<PackageReference Include="Serilog" Version="3.1.1" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.7" />
<PackageReference Include="Serilog" Version="4.0.0" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.1" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
</ItemGroup>

<ItemGroup>
Expand Down

0 comments on commit 8dd0eec

Please sign in to comment.