From 0d5d28483b1b2abf49b02a30af5672c96ee4deea Mon Sep 17 00:00:00 2001 From: Roger Far Date: Thu, 28 Oct 2021 08:29:42 -0600 Subject: [PATCH] Fixed issues with retrying and cancelling torrents. --- CHANGELOG.md | 4 + client/src/app/navbar/navbar.component.html | 2 +- package.json | 2 +- .../Services/DownloadClient.cs | 3 + .../Services/Downloaders/Aria2cDownloader.cs | 4 + .../Services/TorrentRunner.cs | 33 +++++- server/RdtClient.Service/Services/Torrents.cs | 111 +++++++++++------- server/RdtClient.Web/RdtClient.Web.csproj | 2 +- 8 files changed, 111 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce9e4d3..b5dad9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ 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). +## [1.9.4] - 2021-10-28 +### Changed +- Fixed issues retrying torrents after multiple failed downloads in large torrents. + ## [1.9.3] - 2021-10-27 ### Changed - Fixed issue with the unpack queue. diff --git a/client/src/app/navbar/navbar.component.html b/client/src/app/navbar/navbar.component.html index 753aeb7..a4e9317 100644 --- a/client/src/app/navbar/navbar.component.html +++ b/client/src/app/navbar/navbar.component.html @@ -55,7 +55,7 @@ Profile Logout - + diff --git a/package.json b/package.json index b5c7831..d373624 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rdt-client", - "version": "1.9.3", + "version": "1.9.4", "description": "This is a web interface to manage your torrents on Real-Debrid.", "main": "index.js", "dependencies": { diff --git a/server/RdtClient.Service/Services/DownloadClient.cs b/server/RdtClient.Service/Services/DownloadClient.cs index 128cb21..622bed8 100644 --- a/server/RdtClient.Service/Services/DownloadClient.cs +++ b/server/RdtClient.Service/Services/DownloadClient.cs @@ -90,6 +90,9 @@ namespace RdtClient.Service.Services public async Task Cancel() { + Finished = true; + Error = null; + if (Downloader == null) { return; diff --git a/server/RdtClient.Service/Services/Downloaders/Aria2cDownloader.cs b/server/RdtClient.Service/Services/Downloaders/Aria2cDownloader.cs index dae8410..81cc464 100644 --- a/server/RdtClient.Service/Services/Downloaders/Aria2cDownloader.cs +++ b/server/RdtClient.Service/Services/Downloaders/Aria2cDownloader.cs @@ -168,6 +168,10 @@ namespace RdtClient.Service.Services.Downloaders if (download == null) { + DownloadComplete?.Invoke(this, new DownloadCompleteEventArgs + { + Error = $"Download was not found in Aria2" + }); return; } diff --git a/server/RdtClient.Service/Services/TorrentRunner.cs b/server/RdtClient.Service/Services/TorrentRunner.cs index 98cf0f1..58af329 100644 --- a/server/RdtClient.Service/Services/TorrentRunner.cs +++ b/server/RdtClient.Service/Services/TorrentRunner.cs @@ -4,9 +4,11 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Net.Http; +using System.Threading; using System.Threading.Tasks; using System.Web; using Aria2NET; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using RdtClient.Data.Enums; @@ -27,15 +29,19 @@ namespace RdtClient.Service.Services public static readonly ConcurrentDictionary ActiveDownloadClients = new(); public static readonly ConcurrentDictionary ActiveUnpackClients = new(); + public static readonly SemaphoreSlim TorrentResetLock = new(1, 1); + private readonly ILogger _logger; + private readonly IServiceProvider _serviceProvider; private readonly Torrents _torrents; private readonly Downloads _downloads; private readonly RemoteService _remoteService; private readonly HttpClient _httpClient; - public TorrentRunner(ILogger logger, Torrents torrents, Downloads downloads, RemoteService remoteService) + public TorrentRunner(ILogger logger, IServiceProvider serviceProvider, Torrents torrents, Downloads downloads, RemoteService remoteService) { _logger = logger; + _serviceProvider = serviceProvider; _torrents = torrents; _downloads = downloads; _remoteService = remoteService; @@ -185,9 +191,17 @@ namespace RdtClient.Service.Services { Log($"Retrying torrent", download, download.Torrent); - await _torrents.RetryTorrent(download.TorrentId, download.Torrent.RetryCount + 1); + _ = Task.Run(async () => + { + using var blockScope = _serviceProvider.CreateScope(); + var torrentsService = (Torrents) blockScope.ServiceProvider.GetService(typeof(Torrents)); + await torrentsService.RetryTorrent(download.TorrentId, download.Torrent.RetryCount + 1); + }); - continue; + // Force a delay and return the main loop to prevent concurrency issues. + await Task.Delay(10000); + + return; } else { @@ -468,8 +482,17 @@ namespace RdtClient.Service.Services { Log($"Retrying torrent", torrent); - await _torrents.RetryTorrent(torrent.TorrentId, torrent.RetryCount + 1); - continue; + _ = Task.Run(async () => + { + using var blockScope = _serviceProvider.CreateScope(); + var torrentsService = (Torrents) blockScope.ServiceProvider.GetService(typeof(Torrents)); + await torrentsService.RetryTorrent(torrent.TorrentId, torrent.RetryCount + 1); + }); + + // Force a delay and return the main loop to prevent concurrency issues. + await Task.Delay(10000); + + return; } Log($"Received RealDebrid error: {torrent.RdStatusRaw}, not processing further", torrent); diff --git a/server/RdtClient.Service/Services/Torrents.cs b/server/RdtClient.Service/Services/Torrents.cs index 35d0896..7124414 100644 --- a/server/RdtClient.Service/Services/Torrents.cs +++ b/server/RdtClient.Service/Services/Torrents.cs @@ -27,6 +27,8 @@ namespace RdtClient.Service.Services private readonly ITorrentClient _torrentClient; + public static readonly SemaphoreSlim TorrentResetLock = new(1, 1); + public Torrents(ILogger logger, TorrentData torrentData, Downloads downloads, @@ -219,6 +221,8 @@ namespace RdtClient.Service.Services Log($"Deleting", torrent); + await UpdateComplete(torrentId, DateTimeOffset.UtcNow); + foreach (var download in torrent.Downloads) { while (TorrentRunner.ActiveDownloadClients.TryGetValue(download.DownloadId, out var downloadClient)) @@ -359,59 +363,82 @@ namespace RdtClient.Service.Services public async Task RetryTorrent(Guid torrentId, Int32 retryCount) { - var torrent = await _torrentData.GetById(torrentId); + await TorrentResetLock.WaitAsync(); - if (torrent == null) + try { - return; - } + var torrent = await _torrentData.GetById(torrentId); - Log($"Retrying Torrent", torrent); - - foreach (var download in torrent.Downloads) - { - while (TorrentRunner.ActiveDownloadClients.TryGetValue(download.DownloadId, out var downloadClient)) + if (torrent == null) { - await downloadClient.Cancel(); - - await Task.Delay(100); + return; } - while (TorrentRunner.ActiveUnpackClients.TryGetValue(download.DownloadId, out var unpackClient)) + Log($"Retrying Torrent", torrent); + + await UpdateComplete(torrent.TorrentId, DateTimeOffset.Now); + + foreach (var download in torrent.Downloads) { - unpackClient.Cancel(); - - await Task.Delay(100); + await _downloads.UpdateError(download.DownloadId, null); + await _downloads.UpdateCompleted(download.DownloadId, DateTimeOffset.Now); } + + foreach (var download in torrent.Downloads) + { + while (TorrentRunner.ActiveDownloadClients.TryGetValue(download.DownloadId, out var downloadClient)) + { + await downloadClient.Cancel(); + + await Task.Delay(100); + } + + while (TorrentRunner.ActiveUnpackClients.TryGetValue(download.DownloadId, out var unpackClient)) + { + unpackClient.Cancel(); + + await Task.Delay(100); + } + } + + await Delete(torrentId, true, true, true); + + if (String.IsNullOrWhiteSpace(torrent.FileOrMagnet)) + { + throw new Exception($"Cannot re-add this torrent, original magnet or file not found"); + } + + Torrent newTorrent; + + if (torrent.IsFile) + { + var bytes = Convert.FromBase64String(torrent.FileOrMagnet); + + newTorrent = await UploadFile(bytes, + torrent.Category, + torrent.DownloadAction, + torrent.FinishedAction, + torrent.DownloadMinSize, + torrent.DownloadManualFiles, + torrent.Priority); + } + else + { + newTorrent = await UploadMagnet(torrent.FileOrMagnet, + torrent.Category, + torrent.DownloadAction, + torrent.FinishedAction, + torrent.DownloadMinSize, + torrent.DownloadManualFiles, + torrent.Priority); + } + + await _torrentData.UpdateRetryCount(newTorrent.TorrentId, retryCount); } - - await Delete(torrentId, true, true, true); - - if (String.IsNullOrWhiteSpace(torrent.FileOrMagnet)) + finally { - throw new Exception($"Cannot re-add this torrent, original magnet or file not found"); + TorrentResetLock.Release(); } - - Torrent newTorrent; - - if (torrent.IsFile) - { - var bytes = Convert.FromBase64String(torrent.FileOrMagnet); - - newTorrent = await UploadFile(bytes, torrent.Category, torrent.DownloadAction, torrent.FinishedAction, torrent.DownloadMinSize, torrent.DownloadManualFiles, torrent.Priority); - } - else - { - newTorrent = await UploadMagnet(torrent.FileOrMagnet, - torrent.Category, - torrent.DownloadAction, - torrent.FinishedAction, - torrent.DownloadMinSize, - torrent.DownloadManualFiles, - torrent.Priority); - } - - await _torrentData.UpdateRetryCount(newTorrent.TorrentId, retryCount); } public async Task RetryDownload(Guid downloadId) diff --git a/server/RdtClient.Web/RdtClient.Web.csproj b/server/RdtClient.Web/RdtClient.Web.csproj index d9c2e86..e0377fa 100644 --- a/server/RdtClient.Web/RdtClient.Web.csproj +++ b/server/RdtClient.Web/RdtClient.Web.csproj @@ -4,7 +4,7 @@ net5.0 Exe 94c24cba-f03f-4453-a671-3640b517c573 - 1.9.3 + 1.9.4