From 731daddc9915e7a1a78ef16db1ad80631ef1d1c8 Mon Sep 17 00:00:00 2001 From: Roger Far Date: Sat, 18 Apr 2020 08:07:06 -0600 Subject: [PATCH] Improved logging and fixed queued failure handling. --- server/RdtClient.Data/Data/DownloadData.cs | 2 +- server/RdtClient.Data/Data/TorrentData.cs | 2 +- .../ExceptionMiddlewareExtensions.cs | 29 ++++ .../Services/DownloadManager.cs | 2 +- .../RdtClient.Service/Services/QBittorrent.cs | 103 +++++++------ .../RdtClient.Service/Services/TaskRunner.cs | 2 +- server/RdtClient.Service/Services/Torrents.cs | 25 ++-- .../Controllers/AuthController.cs | 44 ++---- .../Controllers/QBittorrentController.cs | 140 +++++------------- .../Controllers/SettingsController.cs | 38 +---- .../Controllers/TorrentsController.cs | 98 ++++-------- server/RdtClient.Web/Startup.cs | 4 +- 12 files changed, 184 insertions(+), 305 deletions(-) create mode 100644 server/RdtClient.Service/Middleware/ExceptionMiddlewareExtensions.cs diff --git a/server/RdtClient.Data/Data/DownloadData.cs b/server/RdtClient.Data/Data/DownloadData.cs index ef7c1ad..ff674d4 100644 --- a/server/RdtClient.Data/Data/DownloadData.cs +++ b/server/RdtClient.Data/Data/DownloadData.cs @@ -53,7 +53,7 @@ namespace RdtClient.Data.Data Status = DownloadStatus.PendingDownload }; - _dataContext.Downloads.Add(download); + await _dataContext.Downloads.AddAsync(download); await _dataContext.SaveChangesAsync(); diff --git a/server/RdtClient.Data/Data/TorrentData.cs b/server/RdtClient.Data/Data/TorrentData.cs index e4ba6ba..a6c5a94 100644 --- a/server/RdtClient.Data/Data/TorrentData.cs +++ b/server/RdtClient.Data/Data/TorrentData.cs @@ -92,7 +92,7 @@ namespace RdtClient.Data.Data AutoDelete = autoDelete }; - _dataContext.Torrents.Add(torrent); + await _dataContext.Torrents.AddAsync(torrent); await _dataContext.SaveChangesAsync(); diff --git a/server/RdtClient.Service/Middleware/ExceptionMiddlewareExtensions.cs b/server/RdtClient.Service/Middleware/ExceptionMiddlewareExtensions.cs new file mode 100644 index 0000000..815f8c4 --- /dev/null +++ b/server/RdtClient.Service/Middleware/ExceptionMiddlewareExtensions.cs @@ -0,0 +1,29 @@ +using System; +using System.Net; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Diagnostics; +using Microsoft.AspNetCore.Http; + +namespace RdtClient.Service.Middleware +{ + public static class ExceptionMiddlewareExtensions + { + public static void ConfigureExceptionHandler(this IApplicationBuilder app) + { + app.UseExceptionHandler(appError => + { + appError.Run(async context => + { + context.Response.StatusCode = (Int32) HttpStatusCode.InternalServerError; + context.Response.ContentType = "application/json"; + + var contextFeature = context.Features.Get(); + if (contextFeature != null) + { + await context.Response.WriteAsync(contextFeature.Error.Message); + } + }); + }); + } + } +} \ No newline at end of file diff --git a/server/RdtClient.Service/Services/DownloadManager.cs b/server/RdtClient.Service/Services/DownloadManager.cs index 4d4b4b3..d3f4f97 100644 --- a/server/RdtClient.Service/Services/DownloadManager.cs +++ b/server/RdtClient.Service/Services/DownloadManager.cs @@ -78,7 +78,7 @@ namespace RdtClient.Service.Services while (fileStream.Length < response.ContentLength) { - var read = stream.Read(buffer, 0, buffer.Length); + var read = await stream.ReadAsync(buffer, 0, buffer.Length); if (read > 0) { diff --git a/server/RdtClient.Service/Services/QBittorrent.cs b/server/RdtClient.Service/Services/QBittorrent.cs index 31fc465..434ef49 100644 --- a/server/RdtClient.Service/Services/QBittorrent.cs +++ b/server/RdtClient.Service/Services/QBittorrent.cs @@ -231,59 +231,58 @@ namespace RdtClient.Service.Services var prio = 0; foreach (var torrent in torrents) { - var result = new TorrentInfo + var result = new TorrentInfo(); + result.AddedOn = torrent.RdAdded.ToUnixTimeSeconds(); + result.AmountLeft = (Int64) (torrent.RdSize * (100.0 - torrent.RdProgress) / 100.0); + result.AutoTmm = false; + result.Availability = 2; + result.Category = torrent.Category ?? ""; + result.Completed = (Int64) (torrent.RdSize * (torrent.RdProgress / 100.0)); + result.CompletionOn = torrent.RdEnded?.ToUnixTimeSeconds(); + result.DlLimit = -1; + result.Dlspeed = torrent.RdSpeed ?? 0; + result.Downloaded = (Int64) (torrent.RdSize * (torrent.RdProgress / 100.0)); + result.DownloadedSession = (Int64) (torrent.RdSize * (torrent.RdProgress / 100.0)); + result.Eta = 0; + result.FlPiecePrio = false; + result.ForceStart = false; + result.Hash = torrent.Hash; + result.LastActivity = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + result.MagnetUri = ""; + result.MaxRatio = -1; + result.MaxSeedingTime = -1; + result.Name = torrent.RdName; + result.NumComplete = 10; + result.NumIncomplete = 0; + result.NumLeechs = 100; + result.NumSeeds = 100; + result.Priority = ++prio; + result.Progress = (Int64) (torrent.RdProgress / 100.0); + result.Ratio = 1; + result.RatioLimit = 1; + result.SavePath = savePath; + result.SeedingTimeLimit = 1; + result.SeenComplete = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + result.SeqDl = false; + result.Size = torrent.RdSize; + result.SuperSeeding = false; + result.Tags = ""; + result.TimeActive = (Int64) (torrent.RdAdded - DateTimeOffset.UtcNow).TotalMinutes; + result.TotalSize = torrent.RdSize; + result.Tracker = "udp://tracker.opentrackr.org:1337"; + result.UpLimit = -1; + result.Uploaded = (Int64) (torrent.RdSize * (torrent.RdProgress / 100.0)); + result.UploadedSession = (Int64) (torrent.RdSize * (torrent.RdProgress / 100.0)); + result.Upspeed = torrent.RdSpeed ?? 0; + result.State = torrent.Status switch { - AddedOn = torrent.RdAdded.ToUnixTimeSeconds(), - AmountLeft = (Int64) (torrent.RdSize * (100.0 - torrent.RdProgress) / 100.0), - AutoTmm = false, - Availability = 2, - Category = torrent.Category ?? "", - Completed = (Int64) (torrent.RdSize * (torrent.RdProgress / 100.0)), - CompletionOn = torrent.RdEnded?.ToUnixTimeSeconds(), - DlLimit = -1, - Dlspeed = torrent.RdSpeed ?? 0, - Downloaded = (Int64) (torrent.RdSize * (torrent.RdProgress / 100.0)), - DownloadedSession = (Int64) (torrent.RdSize * (torrent.RdProgress / 100.0)), - Eta = 0, - FlPiecePrio = false, - ForceStart = false, - Hash = torrent.Hash, - LastActivity = DateTimeOffset.UtcNow.ToUnixTimeSeconds(), - MagnetUri = "", - MaxRatio = -1, - MaxSeedingTime = -1, - Name = torrent.RdName, - NumComplete = 10, - NumIncomplete = 0, - NumLeechs = 100, - NumSeeds = 100, - Priority = ++prio, - Progress = (Int64) (torrent.RdProgress / 100.0), - Ratio = 1, - RatioLimit = 1, - SavePath = savePath, - SeedingTimeLimit = 1, - SeenComplete = DateTimeOffset.UtcNow.ToUnixTimeSeconds(), - SeqDl = false, - Size = torrent.RdSize, - SuperSeeding = false, - Tags = "", - TimeActive = (Int64) (torrent.RdAdded - DateTimeOffset.UtcNow).TotalMinutes, - TotalSize = torrent.RdSize, - Tracker = "udp://tracker.opentrackr.org:1337", - UpLimit = -1, - Uploaded = (Int64) (torrent.RdSize * (torrent.RdProgress / 100.0)), - UploadedSession = (Int64) (torrent.RdSize * (torrent.RdProgress / 100.0)), - Upspeed = torrent.RdSpeed ?? 0, - State = torrent.Status switch - { - TorrentStatus.RealDebrid => "downloading", - TorrentStatus.WaitingForDownload => "downloading", - TorrentStatus.Downloading => "downloading", - TorrentStatus.Finished => "pausedUP", - TorrentStatus.Error => "error", - _ => throw new ArgumentOutOfRangeException() - } + TorrentStatus.RealDebrid => "downloading", + TorrentStatus.WaitingForDownload => "downloading", + TorrentStatus.DownloadQueued => "downloading", + TorrentStatus.Downloading => "downloading", + TorrentStatus.Finished => "pausedUP", + TorrentStatus.Error => "error", + _ => throw new ArgumentOutOfRangeException() }; results.Add(result); diff --git a/server/RdtClient.Service/Services/TaskRunner.cs b/server/RdtClient.Service/Services/TaskRunner.cs index 3542627..4198137 100644 --- a/server/RdtClient.Service/Services/TaskRunner.cs +++ b/server/RdtClient.Service/Services/TaskRunner.cs @@ -72,7 +72,7 @@ namespace RdtClient.Service.Services { var allTorrents = await torrents.Get(); - allTorrents = allTorrents.Where(m => m.Status == TorrentStatus.WaitingForDownload && m.AutoDownload && m.Downloads.Count == 0) + allTorrents = allTorrents.Where(m => (m.Status == TorrentStatus.WaitingForDownload && m.AutoDownload && m.Downloads.Count == 0) || m.Status == TorrentStatus.DownloadQueued) .ToList(); foreach (var torrent in allTorrents) diff --git a/server/RdtClient.Service/Services/Torrents.cs b/server/RdtClient.Service/Services/Torrents.cs index b44118c..976aa72 100644 --- a/server/RdtClient.Service/Services/Torrents.cs +++ b/server/RdtClient.Service/Services/Torrents.cs @@ -33,8 +33,6 @@ namespace RdtClient.Service.Services { private static RdNetClient _rdtClient; - private static DateTime _rdtLastUpdate = DateTime.UtcNow; - private static readonly SemaphoreSlim SemaphoreSlim = new SemaphoreSlim(1, 1); private readonly IDownloads _downloads; private readonly ISettings _settings; @@ -71,14 +69,7 @@ namespace RdtClient.Service.Services public async Task> Get() { var torrents = await _torrentData.Get(); - - if (DateTime.UtcNow > _rdtLastUpdate) - { - _rdtLastUpdate = DateTime.UtcNow.AddSeconds(10); - - torrents = await Update(); - } - + foreach (var torrent in torrents) { foreach (var download in torrent.Downloads) @@ -204,7 +195,7 @@ namespace RdtClient.Service.Services public async Task UploadFile(Byte[] bytes, Boolean autoDownload, Boolean autoDelete) { - var torrent = MonoTorrent.Torrent.Load(bytes); + var torrent = await MonoTorrent.Torrent.LoadAsync(bytes); var rdTorrent = await RdNetClient.AddTorrentFileAsync(bytes); @@ -233,10 +224,17 @@ namespace RdtClient.Service.Services var rdTorrent = await RdNetClient.GetTorrentInfoAsync(torrent.RdId); + var existingDownloads = await _downloads.GetForTorrent(id); + foreach (var link in rdTorrent.Links) { var unrestrictedLink = await RdNetClient.UnrestrictLinkAsync(link); + if (existingDownloads.Any(m => m.Link == unrestrictedLink.Download)) + { + continue; + } + await _downloads.Add(torrent.TorrentId, unrestrictedLink.Download); } } @@ -244,17 +242,16 @@ namespace RdtClient.Service.Services public void Reset() { _rdtClient = null; - _rdtLastUpdate = DateTime.UtcNow; } public async Task GetProfile() { - if (_rdtClient == null) + if (RdNetClient == null) { return new Profile(); } - var user = await _rdtClient.GetUserAsync(); + var user = await RdNetClient.GetUserAsync(); var profile = new Profile { diff --git a/server/RdtClient.Web/Controllers/AuthController.cs b/server/RdtClient.Web/Controllers/AuthController.cs index e691ac4..7d9ceac 100644 --- a/server/RdtClient.Web/Controllers/AuthController.cs +++ b/server/RdtClient.Web/Controllers/AuthController.cs @@ -22,48 +22,34 @@ namespace RdtClient.Web.Controllers [HttpPost] public async Task Login([FromBody] AuthControllerLoginRequest request) { - try + var user = await _authentication.GetUser(); + + if (user == null) { - var user = await _authentication.GetUser(); + var registerResult = await _authentication.Register(request.UserName, request.Password); - if (user == null) + if (!registerResult.Succeeded) { - var registerResult = await _authentication.Register(request.UserName, request.Password); - - if (!registerResult.Succeeded) - { - return BadRequest(registerResult.Errors.First().Description); - } + return BadRequest(registerResult.Errors.First().Description); } - - var result = await _authentication.Login(request.UserName, request.Password); - - if (!result.Succeeded) - { - return BadRequest("Invalid credentials"); - } - - return Ok(); } - catch(Exception ex) + + var result = await _authentication.Login(request.UserName, request.Password); + + if (!result.Succeeded) { - return BadRequest(ex.Message); + return BadRequest("Invalid credentials"); } + + return Ok(); } [Route("Logout")] [HttpPost] public async Task Logout() { - try - { - await _authentication.Logout(); - return Ok(); - } - catch(Exception ex) - { - return BadRequest(ex.Message); - } + await _authentication.Logout(); + return Ok(); } } diff --git a/server/RdtClient.Web/Controllers/QBittorrentController.cs b/server/RdtClient.Web/Controllers/QBittorrentController.cs index df78976..4cc3a77 100644 --- a/server/RdtClient.Web/Controllers/QBittorrentController.cs +++ b/server/RdtClient.Web/Controllers/QBittorrentController.cs @@ -31,21 +31,14 @@ namespace RdtClient.Web.Controllers [HttpGet] public async Task AuthLogin([FromQuery] QBAuthLoginRequest request) { - try - { - var result = await _qBittorrent.AuthLogin(request.UserName, request.Password); + var result = await _qBittorrent.AuthLogin(request.UserName, request.Password); - if (result) - { - return Ok("Ok."); - } - - return Ok("Fails."); - } - catch (Exception ex) + if (result) { - return BadRequest(ex.Message); + return Ok("Ok."); } + + return Ok("Fails."); } [AllowAnonymous] @@ -62,15 +55,8 @@ namespace RdtClient.Web.Controllers [HttpPost] public async Task AuthLogout() { - try - { - await _qBittorrent.AuthLogout(); - return Ok(); - } - catch (Exception ex) - { - return BadRequest(ex.Message); - } + await _qBittorrent.AuthLogout(); + return Ok(); } [Route("app/version")] @@ -121,15 +107,8 @@ namespace RdtClient.Web.Controllers [HttpPost] public async Task> AppPreferences() { - try - { - var result = await _qBittorrent.AppPreferences(); - return Ok(result); - } - catch (Exception ex) - { - return BadRequest(ex.Message); - } + var result = await _qBittorrent.AppPreferences(); + return Ok(result); } [Authorize] @@ -147,15 +126,8 @@ namespace RdtClient.Web.Controllers [HttpPost] public async Task> AppDefaultSavePath() { - try - { - var result = await _qBittorrent.AppDefaultSavePath(); - return Ok(result); - } - catch (Exception ex) - { - return BadRequest(ex.Message); - } + var result = await _qBittorrent.AppDefaultSavePath(); + return Ok(result); } [Authorize] @@ -164,15 +136,8 @@ namespace RdtClient.Web.Controllers [HttpPost] public async Task>> TorrentsInfo() { - try - { - var result = await _qBittorrent.TorrentInfo(); - return Ok(result); - } - catch (Exception ex) - { - return BadRequest(ex.Message); - } + var result = await _qBittorrent.TorrentInfo(); + return Ok(result); } [Authorize] @@ -180,21 +145,14 @@ namespace RdtClient.Web.Controllers [HttpGet] public async Task>> TorrentsProperties([FromQuery] QBTorrentsHashRequest request) { - try - { - var result = await _qBittorrent.TorrentProperties(request.Hash); + var result = await _qBittorrent.TorrentProperties(request.Hash); - if (result == null) - { - return NotFound(); - } - - return Ok(result); - } - catch (Exception ex) + if (result == null) { - return BadRequest(ex.Message); + return NotFound(); } + + return Ok(result); } [Authorize] @@ -237,21 +195,14 @@ namespace RdtClient.Web.Controllers [HttpGet] public async Task TorrentsDelete([FromQuery] QBTorrentsDeleteRequest request) { - try - { - var hashes = request.Hashes.Split("|"); + var hashes = request.Hashes.Split("|"); - foreach (var hash in hashes) - { - await _qBittorrent.TorrentsDelete(hash, request.DeleteFiles); - } - - return Ok(); - } - catch (Exception ex) + foreach (var hash in hashes) { - return BadRequest(ex.Message); + await _qBittorrent.TorrentsDelete(hash, request.DeleteFiles); } + + return Ok(); } [Authorize] @@ -267,21 +218,14 @@ namespace RdtClient.Web.Controllers [HttpGet] public async Task TorrentsAdd([FromQuery] QBTorrentsAddRequest request) { - try - { - var urls = request.Urls.Split("\n"); + var urls = request.Urls.Split("\n"); - foreach (var url in urls) - { - await _qBittorrent.TorrentsAdd(url.Trim(), true, true); - } - - return Ok(); - } - catch (Exception ex) + foreach (var url in urls) { - return BadRequest(ex.Message); + await _qBittorrent.TorrentsAdd(url.Trim(), true, true); } + + return Ok(); } [Authorize] @@ -315,21 +259,14 @@ namespace RdtClient.Web.Controllers [HttpGet] public async Task TorrentsSetCategory([FromQuery] QBTorrentsSetCategoryRequest request) { - try - { - var hashes = request.Hashes.Split("|"); + var hashes = request.Hashes.Split("|"); - foreach (var hash in hashes) - { - await _qBittorrent.TorrentsSetCategory(hash, request.Category); - } - - return Ok(); - } - catch (Exception ex) + foreach (var hash in hashes) { - return BadRequest(ex.Message); + await _qBittorrent.TorrentsSetCategory(hash, request.Category); } + + return Ok(); } [Authorize] @@ -346,15 +283,8 @@ namespace RdtClient.Web.Controllers [HttpPost] public async Task>> TorrentsCategories() { - try - { - var categories = await _qBittorrent.TorrentsCategories(); - return Ok(categories); - } - catch (Exception ex) - { - return BadRequest(ex.Message); - } + var categories = await _qBittorrent.TorrentsCategories(); + return Ok(categories); } [Authorize] diff --git a/server/RdtClient.Web/Controllers/SettingsController.cs b/server/RdtClient.Web/Controllers/SettingsController.cs index f8b80e2..d862937 100644 --- a/server/RdtClient.Web/Controllers/SettingsController.cs +++ b/server/RdtClient.Web/Controllers/SettingsController.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -26,47 +25,26 @@ namespace RdtClient.Web.Controllers [Route("")] public async Task>> Get() { - try - { - var result = await _settings.GetAll(); - return Ok(result); - } - catch (Exception ex) - { - return BadRequest(ex.Message); - } + var result = await _settings.GetAll(); + return Ok(result); } [HttpPut] [Route("")] public async Task Update([FromBody] SettingsControllerUpdateRequest request) { - try - { - await _settings.Update(request.Settings); - _torrents.Reset(); + await _settings.Update(request.Settings); + _torrents.Reset(); - return Ok(); - } - catch (Exception ex) - { - return BadRequest(ex.Message); - } + return Ok(); } [HttpGet] [Route("Profile")] public async Task> Profile() { - try - { - var profile = await _torrents.GetProfile(); - return Ok(profile); - } - catch (Exception ex) - { - return BadRequest(ex.Message); - } + var profile = await _torrents.GetProfile(); + return Ok(profile); } } diff --git a/server/RdtClient.Web/Controllers/TorrentsController.cs b/server/RdtClient.Web/Controllers/TorrentsController.cs index 88ee580..b8b7f54 100644 --- a/server/RdtClient.Web/Controllers/TorrentsController.cs +++ b/server/RdtClient.Web/Controllers/TorrentsController.cs @@ -26,37 +26,23 @@ namespace RdtClient.Web.Controllers [Route("")] public async Task>> Get() { - try - { - var result = await _torrents.Get(); - return Ok(result); - } - catch (Exception ex) - { - return BadRequest(ex.Message); - } + var result = await _torrents.Get(); + return Ok(result); } [HttpGet] [Route("{id}")] public async Task> Get(Guid id) { - try - { - var result = await _torrents.GetById(id); + var result = await _torrents.GetById(id); - if (result == null) - { - throw new Exception("Torrent not found"); - } - - return Ok(result); - } - catch (Exception ex) + if (result == null) { - return BadRequest(ex.Message); + throw new Exception("Torrent not found"); + } + + return Ok(result); } - } [HttpPost] [Route("UploadFile")] @@ -64,77 +50,49 @@ namespace RdtClient.Web.Controllers [ModelBinder(BinderType = typeof(JsonModelBinder))] TorrentControllerUploadFileRequest formData) { - try + if (file == null || file.Length <= 0) { - if (file == null || file.Length <= 0) - { - throw new Exception("Invalid torrent file"); - } - - var fileStream = file.OpenReadStream(); - - await using var memoryStream = new MemoryStream(); - - fileStream.CopyTo(memoryStream); - - var bytes = memoryStream.ToArray(); - - await _torrents.UploadFile(bytes, formData.AutoDownload, formData.AutoDelete); - - return Ok(); - } - catch (Exception ex) - { - return BadRequest(ex.Message); + throw new Exception("Invalid torrent file"); } + + var fileStream = file.OpenReadStream(); + + await using var memoryStream = new MemoryStream(); + + await fileStream.CopyToAsync(memoryStream); + + var bytes = memoryStream.ToArray(); + + await _torrents.UploadFile(bytes, formData.AutoDownload, formData.AutoDelete); + + return Ok(); } [HttpPost] [Route("UploadMagnet")] public async Task UploadMagnet([FromBody] TorrentControllerUploadMagnetRequest request) { - try - { - await _torrents.UploadMagnet(request.MagnetLink, request.AutoDownload, request.AutoDelete); + await _torrents.UploadMagnet(request.MagnetLink, request.AutoDownload, request.AutoDelete); - return Ok(); - } - catch (Exception ex) - { - return BadRequest(ex.Message); - } + return Ok(); } [HttpDelete] [Route("{id}")] public async Task Delete(Guid id) { - try - { - await _torrents.Delete(id); + await _torrents.Delete(id); - return Ok(); - } - catch (Exception ex) - { - return BadRequest(ex.Message); - } + return Ok(); } [HttpGet] [Route("Download/{id}")] public async Task Download(Guid id) { - try - { - await _torrents.Download(id); + await _torrents.Download(id); - return Ok(); - } - catch (Exception ex) - { - return BadRequest(ex.Message); - } + return Ok(); } } diff --git a/server/RdtClient.Web/Startup.cs b/server/RdtClient.Web/Startup.cs index c75094e..3f42152 100644 --- a/server/RdtClient.Web/Startup.cs +++ b/server/RdtClient.Web/Startup.cs @@ -12,6 +12,7 @@ using Microsoft.Extensions.Logging; using RdtClient.Data; using RdtClient.Data.Data; using RdtClient.Data.Models.Internal; +using RdtClient.Service.Middleware; namespace RdtClient.Web { @@ -89,9 +90,10 @@ namespace RdtClient.Web if (env.IsDevelopment()) { app.UseCors("Dev"); - app.UseDeveloperExceptionPage(); } + app.ConfigureExceptionHandler(); + app.Use(async (context, next) => { await next.Invoke();