diff --git a/src/NzbDrone.Common/Http/HttpRequest.cs b/src/NzbDrone.Common/Http/HttpRequest.cs index 3674d61d5..89ec89a38 100644 --- a/src/NzbDrone.Common/Http/HttpRequest.cs +++ b/src/NzbDrone.Common/Http/HttpRequest.cs @@ -12,6 +12,7 @@ namespace NzbDrone.Common.Http { Url = new HttpUri(url); Headers = new HttpHeader(); + ConnectionKeepAlive = true; AllowAutoRedirect = true; StoreRequestCookie = true; IgnorePersistentCookies = false; diff --git a/src/NzbDrone.Common/Http/NzbDroneWebClient.cs b/src/NzbDrone.Common/Http/NzbDroneWebClient.cs deleted file mode 100644 index ccd369bb7..000000000 --- a/src/NzbDrone.Common/Http/NzbDroneWebClient.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Net; - -namespace NzbDrone.Common.Http -{ - public class NzbDroneWebClient : WebClient - { - protected override WebRequest GetWebRequest(Uri address) - { - var request = base.GetWebRequest(address); - if (request is HttpWebRequest) - { - ((HttpWebRequest)request).KeepAlive = false; - ((HttpWebRequest)request).ServicePoint.Expect100Continue = false; - } - - return request; - } - } -} diff --git a/src/NzbDrone.Core.Test/IndexerTests/FileListTests/FileListFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/FileListTests/FileListFixture.cs index 0b8c8a407..ce24c5a7b 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/FileListTests/FileListFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/FileListTests/FileListFixture.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Net; +using System.Threading.Tasks; using FluentAssertions; using Moq; using NUnit.Framework; @@ -27,15 +28,15 @@ namespace NzbDrone.Core.Test.IndexerTests.FileListTests } [Test] - public void should_parse_recent_feed_from_FileList() + public async Task should_parse_recent_feed_from_FileList() { var recentFeed = ReadAllText(@"Files/Indexers/FileList/recentfeed.json"); Mocker.GetMock() - .Setup(o => o.Execute(It.Is(v => v.Method == HttpMethod.GET))) - .Returns(r => new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed)); + .Setup(o => o.ExecuteAsync(It.Is(v => v.Method == HttpMethod.GET))) + .Returns(r => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); - var releases = Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } }).Releases; + var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } })).Releases; releases.Should().HaveCount(4); releases.First().Should().BeOfType(); diff --git a/src/NzbDrone.Core.Test/IndexerTests/HDBitsTests/HDBitsFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/HDBitsTests/HDBitsFixture.cs index 6224c35c8..5fc9c6296 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/HDBitsTests/HDBitsFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/HDBitsTests/HDBitsFixture.cs @@ -2,6 +2,7 @@ using System; using System.Linq; using System.Net; using System.Text; +using System.Threading.Tasks; using FluentAssertions; using Moq; using NUnit.Framework; @@ -39,15 +40,15 @@ namespace NzbDrone.Core.Test.IndexerTests.HDBitsTests [TestCase("Files/Indexers/HdBits/RecentFeedLongIDs.json")] [TestCase("Files/Indexers/HdBits/RecentFeedStringIDs.json")] - public void should_parse_recent_feed_from_HDBits(string fileName) + public async Task should_parse_recent_feed_from_HDBits(string fileName) { var responseJson = ReadAllText(fileName); Mocker.GetMock() - .Setup(o => o.Execute(It.Is(v => v.Method == HttpMethod.POST))) - .Returns(r => new HttpResponse(r, new HttpHeader(), new CookieCollection(), responseJson)); + .Setup(o => o.ExecuteAsync(It.Is(v => v.Method == HttpMethod.POST))) + .Returns(r => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), responseJson))); - var torrents = Subject.Fetch(_movieSearchCriteria).Releases; + var torrents = (await Subject.Fetch(_movieSearchCriteria)).Releases; torrents.Should().HaveCount(2); torrents.First().Should().BeOfType(); @@ -68,15 +69,15 @@ namespace NzbDrone.Core.Test.IndexerTests.HDBitsTests } [Test] - public void should_warn_on_wrong_passkey() + public async Task should_warn_on_wrong_passkey() { var responseJson = new { status = 5, message = "Invalid authentication credentials" }.ToJson(); Mocker.GetMock() - .Setup(v => v.Execute(It.IsAny())) - .Returns(r => new HttpResponse(r, new HttpHeader(), new CookieCollection(), Encoding.UTF8.GetBytes(responseJson))); + .Setup(v => v.ExecuteAsync(It.IsAny())) + .Returns(r => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), Encoding.UTF8.GetBytes(responseJson)))); - var torrents = Subject.Fetch(_movieSearchCriteria).Releases; + var torrents = (await Subject.Fetch(_movieSearchCriteria)).Releases; torrents.Should().BeEmpty(); diff --git a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabFixture.cs index 94db26fc4..a3d5a8d14 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabFixture.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Net; +using System.Threading.Tasks; using FluentAssertions; using Moq; using NUnit.Framework; @@ -37,15 +38,15 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests } [Test] - public void should_parse_recent_feed_from_newznab_nzb_su() + public async Task should_parse_recent_feed_from_newznab_nzb_su() { var recentFeed = ReadAllText(@"Files/Indexers/Newznab/newznab_nzb_su.xml"); Mocker.GetMock() - .Setup(o => o.Execute(It.Is(v => v.Method == HttpMethod.GET))) - .Returns(r => new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed)); + .Setup(o => o.ExecuteAsync(It.Is(v => v.Method == HttpMethod.GET))) + .Returns(r => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); - var releases = Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 }, Limit = 100, Offset = 0 }).Releases; + var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 }, Limit = 100, Offset = 0 })).Releases; releases.Should().HaveCount(100); diff --git a/src/NzbDrone.Core.Test/IndexerTests/PTPTests/PTPFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/PTPTests/PTPFixture.cs index 9b8d58e77..ef44ed04d 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/PTPTests/PTPFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/PTPTests/PTPFixture.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Net; +using System.Threading.Tasks; using FluentAssertions; using Moq; using NUnit.Framework; @@ -27,7 +28,7 @@ namespace NzbDrone.Core.Test.IndexerTests.PTPTests } [TestCase("Files/Indexers/PTP/imdbsearch.json")] - public void should_parse_feed_from_PTP(string fileName) + public async Task should_parse_feed_from_PTP(string fileName) { var authResponse = new PassThePopcornAuthResponse { Result = "Ok" }; @@ -36,14 +37,14 @@ namespace NzbDrone.Core.Test.IndexerTests.PTPTests var responseJson = ReadAllText(fileName); Mocker.GetMock() - .Setup(o => o.Execute(It.Is(v => v.Method == HttpMethod.POST))) - .Returns(r => new HttpResponse(r, new HttpHeader(), new CookieCollection(), authStream.ToString())); + .Setup(o => o.ExecuteAsync(It.Is(v => v.Method == HttpMethod.POST))) + .Returns(r => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), authStream.ToString()))); Mocker.GetMock() - .Setup(o => o.Execute(It.Is(v => v.Method == HttpMethod.GET))) - .Returns(r => new HttpResponse(r, new HttpHeader { ContentType = HttpAccept.Json.Value }, new CookieCollection(), responseJson)); + .Setup(o => o.ExecuteAsync(It.Is(v => v.Method == HttpMethod.GET))) + .Returns(r => Task.FromResult(new HttpResponse(r, new HttpHeader { ContentType = HttpAccept.Json.Value }, new CookieCollection(), responseJson))); - var torrents = Subject.Fetch(new MovieSearchCriteria()).Releases; + var torrents = (await Subject.Fetch(new MovieSearchCriteria())).Releases; torrents.Should().HaveCount(293); torrents.First().Should().BeOfType(); diff --git a/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs index b9bea4352..7fcfe1cdf 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Net; +using System.Threading.Tasks; using FluentAssertions; using Moq; using NUnit.Framework; @@ -32,15 +33,15 @@ namespace NzbDrone.Core.Test.IndexerTests.RarbgTests } [Test] - public void should_parse_recent_feed_from_Rarbg() + public async Task should_parse_recent_feed_from_Rarbg() { var recentFeed = ReadAllText(@"Files/Indexers/Rarbg/RecentFeed_v2.json"); Mocker.GetMock() - .Setup(o => o.Execute(It.Is(v => v.Method == HttpMethod.GET))) - .Returns(r => new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed)); + .Setup(o => o.ExecuteAsync(It.Is(v => v.Method == HttpMethod.GET))) + .Returns(r => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); - var releases = Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } }).Releases; + var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } })).Releases; releases.Should().HaveCount(4); releases.First().Should().BeOfType(); @@ -61,25 +62,25 @@ namespace NzbDrone.Core.Test.IndexerTests.RarbgTests } [Test] - public void should_parse_error_20_as_empty_results() + public async Task should_parse_error_20_as_empty_results() { Mocker.GetMock() - .Setup(o => o.Execute(It.Is(v => v.Method == HttpMethod.GET))) - .Returns(r => new HttpResponse(r, new HttpHeader(), new CookieCollection(), "{ error_code: 20, error: \"some message\" }")); + .Setup(o => o.ExecuteAsync(It.Is(v => v.Method == HttpMethod.GET))) + .Returns(r => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), "{ error_code: 20, error: \"some message\" }"))); - var releases = Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } }).Releases; + var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } })).Releases; releases.Should().HaveCount(0); } [Test] - public void should_warn_on_unknown_error() + public async Task should_warn_on_unknown_error() { Mocker.GetMock() - .Setup(o => o.Execute(It.Is(v => v.Method == HttpMethod.GET))) - .Returns(r => new HttpResponse(r, new HttpHeader(), new CookieCollection(), "{ error_code: 25, error: \"some message\" }")); + .Setup(o => o.ExecuteAsync(It.Is(v => v.Method == HttpMethod.GET))) + .Returns(r => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), "{ error_code: 25, error: \"some message\" }"))); - var releases = Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } }).Releases; + var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } })).Releases; releases.Should().HaveCount(0); diff --git a/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs index 9e1fe4b31..8922e36be 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Net; +using System.Threading.Tasks; using FluentAssertions; using Moq; using NUnit.Framework; @@ -38,15 +39,15 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests } [Test] - public void should_parse_recent_feed_from_torznab_hdaccess_net() + public async Task should_parse_recent_feed_from_torznab_hdaccess_net() { var recentFeed = ReadAllText(@"Files/Indexers/Torznab/torznab_hdaccess_net.xml"); Mocker.GetMock() - .Setup(o => o.Execute(It.Is(v => v.Method == HttpMethod.GET))) - .Returns(r => new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed)); + .Setup(o => o.ExecuteAsync(It.Is(v => v.Method == HttpMethod.GET))) + .Returns(r => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); - var releases = Subject.Fetch(new MovieSearchCriteria()).Releases; + var releases = (await Subject.Fetch(new MovieSearchCriteria())).Releases; releases.Should().HaveCount(5); @@ -67,15 +68,15 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests } [Test] - public void should_parse_recent_feed_from_torznab_tpb() + public async Task should_parse_recent_feed_from_torznab_tpb() { var recentFeed = ReadAllText(@"Files/Indexers/Torznab/torznab_tpb.xml"); Mocker.GetMock() - .Setup(o => o.Execute(It.Is(v => v.Method == HttpMethod.GET))) - .Returns(r => new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed)); + .Setup(o => o.ExecuteAsync(It.Is(v => v.Method == HttpMethod.GET))) + .Returns(r => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); - var releases = Subject.Fetch(new MovieSearchCriteria()).Releases; + var releases = (await Subject.Fetch(new MovieSearchCriteria())).Releases; releases.Should().HaveCount(5); @@ -97,15 +98,15 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests } [Test] - public void should_parse_recent_feed_from_torznab_animetosho() + public async Task should_parse_recent_feed_from_torznab_animetosho() { var recentFeed = ReadAllText(@"Files/Indexers/Torznab/torznab_animetosho.xml"); Mocker.GetMock() - .Setup(o => o.Execute(It.Is(v => v.Method == HttpMethod.GET))) - .Returns(r => new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed)); + .Setup(o => o.ExecuteAsync(It.Is(v => v.Method == HttpMethod.GET))) + .Returns(r => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); - var releases = Subject.Fetch(new MovieSearchCriteria()).Releases; + var releases = (await Subject.Fetch(new MovieSearchCriteria())).Releases; releases.Should().HaveCount(2); diff --git a/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs b/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs index c6a9c6f5c..620ea110d 100644 --- a/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs +++ b/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Threading.Tasks; using NLog; using NzbDrone.Common.Instrumentation.Extensions; -using NzbDrone.Common.TPL; using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers.Events; using NzbDrone.Core.IndexerSearch.Definitions; @@ -15,7 +14,7 @@ namespace NzbDrone.Core.IndexerSearch { public interface ISearchForNzb { - NewznabResults Search(NewznabRequest request, List indexerIds, bool interactiveSearch); + Task Search(NewznabRequest request, List indexerIds, bool interactiveSearch); } public class NzbSearchService : ISearchForNzb @@ -36,7 +35,7 @@ namespace NzbDrone.Core.IndexerSearch _logger = logger; } - public NewznabResults Search(NewznabRequest request, List indexerIds, bool interactiveSearch) + public Task Search(NewznabRequest request, List indexerIds, bool interactiveSearch) { switch (request.t) { @@ -53,7 +52,7 @@ namespace NzbDrone.Core.IndexerSearch } } - private NewznabResults MovieSearch(NewznabRequest request, List indexerIds, bool interactiveSearch) + private async Task MovieSearch(NewznabRequest request, List indexerIds, bool interactiveSearch) { var searchSpec = Get(request, indexerIds, interactiveSearch); @@ -61,10 +60,10 @@ namespace NzbDrone.Core.IndexerSearch searchSpec.TmdbId = request.tmdbid; searchSpec.TraktId = request.traktid; - return new NewznabResults { Releases = MapReleases(Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec), request.server) }; + return new NewznabResults { Releases = MapReleases(await Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec), request.server) }; } - private NewznabResults MusicSearch(NewznabRequest request, List indexerIds, bool interactiveSearch) + private async Task MusicSearch(NewznabRequest request, List indexerIds, bool interactiveSearch) { var searchSpec = Get(request, indexerIds, interactiveSearch); @@ -72,10 +71,10 @@ namespace NzbDrone.Core.IndexerSearch searchSpec.Album = request.album; searchSpec.Label = request.label; - return new NewznabResults { Releases = MapReleases(Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec), request.server) }; + return new NewznabResults { Releases = MapReleases(await Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec), request.server) }; } - private NewznabResults TvSearch(NewznabRequest request, List indexerIds, bool interactiveSearch) + private async Task TvSearch(NewznabRequest request, List indexerIds, bool interactiveSearch) { var searchSpec = Get(request, indexerIds, interactiveSearch); @@ -87,24 +86,24 @@ namespace NzbDrone.Core.IndexerSearch searchSpec.RId = request.rid; searchSpec.TvMazeId = request.tvmazeid; - return new NewznabResults { Releases = MapReleases(Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec), request.server) }; + return new NewznabResults { Releases = MapReleases(await Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec), request.server) }; } - private NewznabResults BookSearch(NewznabRequest request, List indexerIds, bool interactiveSearch) + private async Task BookSearch(NewznabRequest request, List indexerIds, bool interactiveSearch) { var searchSpec = Get(request, indexerIds, interactiveSearch); searchSpec.Author = request.author; searchSpec.Title = request.title; - return new NewznabResults { Releases = MapReleases(Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec), request.server) }; + return new NewznabResults { Releases = MapReleases(await Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec), request.server) }; } - private NewznabResults BasicSearch(NewznabRequest request, List indexerIds, bool interactiveSearch) + private async Task BasicSearch(NewznabRequest request, List indexerIds, bool interactiveSearch) { var searchSpec = Get(request, indexerIds, interactiveSearch); - return new NewznabResults { Releases = MapReleases(Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec), request.server) }; + return new NewznabResults { Releases = MapReleases(await Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec), request.server) }; } private List MapReleases(List releases, string serverUrl) @@ -145,7 +144,7 @@ namespace NzbDrone.Core.IndexerSearch return spec; } - private List Dispatch(Func searchAction, SearchCriteriaBase criteriaBase) + private async Task> Dispatch(Func> searchAction, SearchCriteriaBase criteriaBase) { var indexers = _indexerFactory.GetAvailableProviders(); @@ -157,46 +156,39 @@ namespace NzbDrone.Core.IndexerSearch .ToList(); } - var reports = new List(); - _logger.ProgressInfo("Searching {0} indexers for {1}", indexers.Count, criteriaBase.SearchTerm); - var taskList = new List(); - var taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.None); + var tasks = indexers.Select(x => DispatchIndexer(searchAction, x, criteriaBase)); - foreach (var indexer in indexers) - { - var indexerLocal = indexer; + var batch = await Task.WhenAll(tasks); - taskList.Add(taskFactory.StartNew(() => - { - try - { - var indexerReports = searchAction(indexerLocal); - - lock (reports) - { - reports.AddRange(indexerReports.Releases); - } - - foreach (var query in indexerReports.Queries) - { - _eventAggregator.PublishEvent(new IndexerQueryEvent(indexer.Definition.Id, criteriaBase, query.ElapsedTime, true, indexerReports.Releases.Count())); - } - } - catch (Exception e) - { - _eventAggregator.PublishEvent(new IndexerQueryEvent(indexer.Definition.Id, criteriaBase, 0, false)); - _logger.Error(e, "Error while searching for {0}", criteriaBase); - } - }).LogExceptions()); - } - - Task.WaitAll(taskList.ToArray()); + var reports = batch.SelectMany(x => x).ToList(); _logger.Debug("Total of {0} reports were found for {1} from {2} indexers", reports.Count, criteriaBase, indexers.Count); return reports; } + + private async Task> DispatchIndexer(Func> searchAction, IIndexer indexer, SearchCriteriaBase criteriaBase) + { + try + { + var indexerReports = await searchAction(indexer); + + foreach (var query in indexerReports.Queries) + { + _eventAggregator.PublishEvent(new IndexerQueryEvent(indexer.Definition.Id, criteriaBase, query.ElapsedTime, true, indexerReports.Releases.Count())); + } + + return indexerReports.Releases; + } + catch (Exception e) + { + _eventAggregator.PublishEvent(new IndexerQueryEvent(indexer.Definition.Id, criteriaBase, 0, false)); + _logger.Error(e, "Error while searching for {0}", criteriaBase); + } + + return new List(); + } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/AnimeTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/AnimeTorrents.cs index f3b4d1092..f5abfcc88 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/AnimeTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/AnimeTorrents.cs @@ -4,6 +4,7 @@ using System.Collections.Specialized; using System.Globalization; using System.Linq; using System.Text.RegularExpressions; +using System.Threading.Tasks; using AngleSharp.Html.Parser; using FluentValidation; using NLog; @@ -44,7 +45,7 @@ namespace NzbDrone.Core.Indexers.Definitions return new AnimeTorrentsParser(Settings, Capabilities.Categories, BaseUrl); } - protected override void DoLogin() + protected override async Task DoLogin() { UpdateCookies(null, null); @@ -54,7 +55,7 @@ namespace NzbDrone.Core.Indexers.Definitions AllowAutoRedirect = true }; - var loginPage = _httpClient.Execute(new HttpRequest(LoginUrl)); + var loginPage = await _httpClient.ExecuteAsync(new HttpRequest(LoginUrl)); requestBuilder.Method = HttpMethod.POST; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); requestBuilder.SetCookies(loginPage.GetCookies()); @@ -67,7 +68,7 @@ namespace NzbDrone.Core.Indexers.Definitions .SetHeader("Content-Type", "multipart/form-data") .Build(); - var response = _httpClient.Execute(authLoginRequest); + var response = await _httpClient.ExecuteAsync(authLoginRequest); if (response.Content != null && response.Content.Contains("logout.php")) { diff --git a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/Avistaz.cs b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/Avistaz.cs index afecb2393..1b6aa36bb 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/Avistaz.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/Avistaz.cs @@ -1,5 +1,6 @@ using System; using System.Net; +using System.Threading.Tasks; using FluentValidation.Results; using NLog; using NzbDrone.Common.Http; @@ -52,9 +53,9 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz return caps; } - protected override void DoLogin() + protected override async Task DoLogin() { - Settings.Token = GetToken(); + Settings.Token = await GetToken(); if (Definition.Id > 0) { @@ -74,11 +75,11 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz return false; } - protected override ValidationFailure TestConnection() + protected override async Task TestConnection() { try { - GetToken(); + await GetToken(); } catch (Exception ex) { @@ -90,7 +91,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz return null; } - private string GetToken() + private async Task GetToken() { var requestBuilder = new HttpRequestBuilder(LoginUrl) { @@ -108,7 +109,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz .Accept(HttpAccept.Json) .Build(); - var response = _httpClient.Post(authLoginRequest); + var response = await _httpClient.PostAsync(authLoginRequest); var token = response.Resource.Token; return token; diff --git a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs index b171ffa2d..23dea7db0 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs @@ -5,6 +5,7 @@ using System.Globalization; using System.Linq; using System.Net; using System.Text.RegularExpressions; +using System.Threading.Tasks; using AngleSharp.Dom; using AngleSharp.Html.Parser; using FluentValidation; @@ -45,7 +46,7 @@ namespace NzbDrone.Core.Indexers.Definitions return new BakaBTParser(Settings, Capabilities.Categories, BaseUrl); } - protected override void DoLogin() + protected override async Task DoLogin() { UpdateCookies(null, null); @@ -55,7 +56,7 @@ namespace NzbDrone.Core.Indexers.Definitions AllowAutoRedirect = true }; - var loginPage = _httpClient.Execute(new HttpRequest(LoginUrl)); + var loginPage = await _httpClient.ExecuteAsync(new HttpRequest(LoginUrl)); requestBuilder.Method = HttpMethod.POST; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); @@ -77,7 +78,7 @@ namespace NzbDrone.Core.Indexers.Definitions .SetHeader("Content-Type", "multipart/form-data") .Build(); - var response = _httpClient.Execute(authLoginRequest); + var response = await _httpClient.ExecuteAsync(authLoginRequest); if (response.Content != null && response.Content.Contains("Logout")) { diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs index e060b7141..7e421b8b3 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading.Tasks; using FluentValidation.Results; using NLog; using NzbDrone.Common.Http; @@ -95,18 +96,18 @@ namespace NzbDrone.Core.Indexers.Cardigann return generator.CheckIfLoginIsNeeded(httpResponse); } - protected override void DoLogin() + protected override async Task DoLogin() { var generator = (CardigannRequestGenerator)GetRequestGenerator(); SetCookieFunctions(generator); - generator.DoLogin(); + await generator.DoLogin(); } - protected override void Test(List failures) + protected override async Task Test(List failures) { - base.Test(failures); + await base.Test(failures); if (failures.HasErrors()) { return; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 072bc95f7..b74433d88 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using System.Net; +using System.Threading.Tasks; using AngleSharp.Html.Dom; using AngleSharp.Html.Parser; using Newtonsoft.Json.Linq; @@ -157,7 +158,7 @@ namespace NzbDrone.Core.Indexers.Cardigann return variables; } - public void DoLogin() + public async Task DoLogin() { var login = _definition.Login; @@ -190,7 +191,7 @@ namespace NzbDrone.Core.Indexers.Cardigann requestBuilder.Headers.Add("Referer", SiteLink); - var response = HttpClient.Execute(requestBuilder.Build()); + var response = await HttpClient.ExecuteAsync(requestBuilder.Build()); Cookies = response.GetCookies(); @@ -214,7 +215,7 @@ namespace NzbDrone.Core.Indexers.Cardigann // landingResultDocument might not be initiated if the login is caused by a relogin during a query if (landingResultDocument == null) { - GetConfigurationForSetup(true); + await GetConfigurationForSetup(true); } var form = landingResultDocument.QuerySelector(formSelector); @@ -327,7 +328,7 @@ namespace NzbDrone.Core.Indexers.Cardigann requestBuilder.Headers.Add("Referer", loginUrl); - var simpleCaptchaResult = HttpClient.Execute(requestBuilder.Build()); + var simpleCaptchaResult = await HttpClient.ExecuteAsync(requestBuilder.Build()); var simpleCaptchaJSON = JObject.Parse(simpleCaptchaResult.Content); var captchaSelection = simpleCaptchaJSON["images"][0]["hash"].ToString(); @@ -431,7 +432,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var request = requestBuilder.Build(); request.SetContent(body); - loginResult = HttpClient.Execute(request); + loginResult = await HttpClient.ExecuteAsync(request); } else { @@ -451,7 +452,7 @@ namespace NzbDrone.Core.Indexers.Cardigann requestBuilder.AddFormParameter(pair.Key, pair.Value); } - loginResult = HttpClient.Execute(requestBuilder.Build()); + loginResult = await HttpClient.ExecuteAsync(requestBuilder.Build()); } Cookies = loginResult.GetCookies(); @@ -486,7 +487,7 @@ namespace NzbDrone.Core.Indexers.Cardigann requestBuilder.Headers.Add("Referer", SiteLink); - var response = HttpClient.Execute(requestBuilder.Build()); + var response = await HttpClient.ExecuteAsync(requestBuilder.Build()); Cookies = response.GetCookies(); @@ -510,7 +511,7 @@ namespace NzbDrone.Core.Indexers.Cardigann requestBuilder.Headers.Add("Referer", SiteLink); - var response = HttpClient.Execute(requestBuilder.Build()); + var response = await HttpClient.ExecuteAsync(requestBuilder.Build()); Cookies = response.GetCookies(); @@ -556,7 +557,7 @@ namespace NzbDrone.Core.Indexers.Cardigann return true; } - public void GetConfigurationForSetup(bool automaticlogin) + public async Task GetConfigurationForSetup(bool automaticlogin) { var login = _definition.Login; @@ -587,7 +588,7 @@ namespace NzbDrone.Core.Indexers.Cardigann requestBuilder.SetCookies(Cookies); } - landingResult = HttpClient.Execute(requestBuilder.Build()); + landingResult = await HttpClient.ExecuteAsync(requestBuilder.Build()); Cookies = landingResult.GetCookies(); @@ -659,7 +660,7 @@ namespace NzbDrone.Core.Indexers.Cardigann return; } - protected bool TestLogin() + protected async Task TestLogin() { var login = _definition.Login; @@ -684,7 +685,7 @@ namespace NzbDrone.Core.Indexers.Cardigann requestBuilder.SetCookies(Cookies); } - var testResult = HttpClient.Execute(requestBuilder.Build()); + var testResult = await HttpClient.ExecuteAsync(requestBuilder.Build()); if (testResult.HasHttpRedirect) { diff --git a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/Gazelle.cs b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/Gazelle.cs index 9dda57ff7..9adf2a836 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/Gazelle.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/Gazelle.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using NLog; using NzbDrone.Common.Http; using NzbDrone.Core.Configuration; @@ -47,7 +48,7 @@ namespace NzbDrone.Core.Indexers.Gazelle return caps; } - protected override void DoLogin() + protected override async Task DoLogin() { var requestBuilder = new HttpRequestBuilder(LoginUrl) { @@ -68,7 +69,7 @@ namespace NzbDrone.Core.Indexers.Gazelle .Accept(HttpAccept.Json) .Build(); - var response = _httpClient.Execute(authLoginRequest); + var response = await _httpClient.ExecuteAsync(authLoginRequest); cookies = response.GetCookies(); diff --git a/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs index a18f0da12..a443f11d0 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs @@ -4,6 +4,7 @@ using System.Collections.Specialized; using System.Globalization; using System.Linq; using System.Text.RegularExpressions; +using System.Threading.Tasks; using AngleSharp.Html.Parser; using FluentValidation; using NLog; @@ -43,7 +44,7 @@ namespace NzbDrone.Core.Indexers.Definitions return new HDTorrentsParser(Settings, Capabilities.Categories, BaseUrl); } - protected override void DoLogin() + protected override async Task DoLogin() { var requestBuilder = new HttpRequestBuilder(LoginUrl) { @@ -62,7 +63,7 @@ namespace NzbDrone.Core.Indexers.Definitions .SetHeader("Content-Type", "multipart/form-data") .Build(); - var response = _httpClient.Execute(authLoginRequest); + var response = await _httpClient.ExecuteAsync(authLoginRequest); cookies = response.GetCookies(); UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30)); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Headphones/Headphones.cs b/src/NzbDrone.Core/Indexers/Definitions/Headphones/Headphones.cs index b4b241af3..e12d52aca 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Headphones/Headphones.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Headphones/Headphones.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using FluentValidation.Results; using NLog; using NzbDrone.Common.Http; @@ -38,9 +39,9 @@ namespace NzbDrone.Core.Indexers.Headphones { } - protected override void Test(List failures) + protected override async Task Test(List failures) { - base.Test(failures); + await base.Test(failures); if (failures.Any()) { @@ -48,7 +49,7 @@ namespace NzbDrone.Core.Indexers.Headphones } } - public override byte[] Download(HttpUri link) + public override async Task Download(HttpUri link) { var requestBuilder = new HttpRequestBuilder(link.FullUri); @@ -60,7 +61,8 @@ namespace NzbDrone.Core.Indexers.Headphones try { - downloadBytes = _httpClient.Execute(request).ResponseData; + var response = await _httpClient.ExecuteAsync(request); + downloadBytes = response.ResponseData; } catch (Exception) { diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs index cecbd10f6..845bd52a4 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using FluentValidation.Results; using NLog; using NzbDrone.Common.Extensions; @@ -131,9 +132,9 @@ namespace NzbDrone.Core.Indexers.Newznab return settings; } - protected override void Test(List failures) + protected override async Task Test(List failures) { - base.Test(failures); + await base.Test(failures); if (failures.HasErrors()) { return; diff --git a/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs b/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs index cc740baf2..e2b419a2f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs @@ -4,6 +4,7 @@ using System.Collections.Specialized; using System.Globalization; using System.Linq; using System.Text.RegularExpressions; +using System.Threading.Tasks; using AngleSharp.Html.Parser; using FluentValidation; using NLog; @@ -45,7 +46,7 @@ namespace NzbDrone.Core.Indexers.Definitions return new RevolutionTTParser(Settings, Capabilities.Categories, BaseUrl); } - protected override void DoLogin() + protected override async Task DoLogin() { UpdateCookies(null, null); @@ -55,7 +56,7 @@ namespace NzbDrone.Core.Indexers.Definitions AllowAutoRedirect = true }; - var loginPage = _httpClient.Execute(new HttpRequest(BaseUrl + "login.php")); + var loginPage = await _httpClient.ExecuteAsync(new HttpRequest(BaseUrl + "login.php")); requestBuilder.Method = HttpMethod.POST; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); @@ -67,7 +68,7 @@ namespace NzbDrone.Core.Indexers.Definitions .SetHeader("Content-Type", "multipart/form-data") .Build(); - var response = _httpClient.Execute(authLoginRequest); + var response = await _httpClient.ExecuteAsync(authLoginRequest); if (response.Content != null && response.Content.Contains("/logout.php")) { diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs index dff9baee5..72b35568f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Linq; using System.Net; using System.Text.RegularExpressions; +using System.Threading.Tasks; using FluentValidation; using Newtonsoft.Json; using NLog; @@ -44,7 +45,7 @@ namespace NzbDrone.Core.Indexers.Definitions return new TorrentLeechParser(Settings, Capabilities.Categories, BaseUrl); } - protected override void DoLogin() + protected override async Task DoLogin() { var requestBuilder = new HttpRequestBuilder(LoginUrl) { @@ -63,7 +64,7 @@ namespace NzbDrone.Core.Indexers.Definitions .SetHeader("Content-Type", "multipart/form-data") .Build(); - var response = _httpClient.Execute(authLoginRequest); + var response = await _httpClient.ExecuteAsync(authLoginRequest); cookies = response.GetCookies(); UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30)); diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs index 9fa614a5a..8461e854e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs @@ -4,6 +4,7 @@ using System.Collections.Specialized; using System.Linq; using System.Net; using System.Text.RegularExpressions; +using System.Threading.Tasks; using AngleSharp.Html.Parser; using FluentValidation; using NLog; @@ -44,14 +45,14 @@ namespace NzbDrone.Core.Indexers.Definitions return new TorrentSeedsParser(Settings, Capabilities.Categories, BaseUrl); } - protected override void DoLogin() + protected override async Task DoLogin() { var requestBuilder = new HttpRequestBuilder(LoginUrl) { LogResponseContent = true }; - var loginPage = _httpClient.Execute(new HttpRequest(TokenUrl)); + var loginPage = await _httpClient.ExecuteAsync(new HttpRequest(TokenUrl)); var parser = new HtmlParser(); var dom = parser.ParseDocument(loginPage.Content); var token = dom.QuerySelector("form.form-horizontal > span"); @@ -72,7 +73,7 @@ namespace NzbDrone.Core.Indexers.Definitions .SetHeader("Content-Type", "multipart/form-data") .Build(); - var response = _httpClient.Execute(authLoginRequest); + var response = await _httpClient.ExecuteAsync(authLoginRequest); cookies = response.GetCookies(); UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30)); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs b/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs index 343f03a0f..439b03772 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using FluentValidation.Results; using NLog; using NzbDrone.Common.Extensions; @@ -81,9 +82,9 @@ namespace NzbDrone.Core.Indexers.Torznab return settings; } - protected override void Test(List failures) + protected override async Task Test(List failures) { - base.Test(failures); + await base.Test(failures); if (failures.HasErrors()) { return; diff --git a/src/NzbDrone.Core/Indexers/DownloadService.cs b/src/NzbDrone.Core/Indexers/DownloadService.cs index 52b4ff4d5..978bf6f01 100644 --- a/src/NzbDrone.Core/Indexers/DownloadService.cs +++ b/src/NzbDrone.Core/Indexers/DownloadService.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using NLog; using NzbDrone.Common.EnsureThat; using NzbDrone.Common.Extensions; @@ -12,7 +13,7 @@ namespace NzbDrone.Core.Indexers { public interface IDownloadService { - byte[] DownloadReport(string link, int indexerId, string source, string title); + Task DownloadReport(string link, int indexerId, string source, string title); void RecordRedirect(string link, int indexerId, string source, string title); } @@ -37,14 +38,14 @@ namespace NzbDrone.Core.Indexers _logger = logger; } - public byte[] DownloadReport(string link, int indexerId, string source, string title) + public async Task DownloadReport(string link, int indexerId, string source, string title) { var url = new HttpUri(link); // Limit grabs to 2 per second. if (link.IsNotNullOrWhiteSpace() && !link.StartsWith("magnet:")) { - _rateLimitService.WaitAndPulse(url.Host, TimeSpan.FromSeconds(2)); + await _rateLimitService.WaitAndPulseAsync(url.Host, TimeSpan.FromSeconds(2)); } var indexer = _indexerFactory.GetInstance(_indexerFactory.Get(indexerId)); @@ -53,7 +54,7 @@ namespace NzbDrone.Core.Indexers try { - downloadedBytes = indexer.Download(url); + downloadedBytes = await indexer.Download(url); _indexerStatusService.RecordSuccess(indexerId); success = true; } diff --git a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs index 00c7b7a0b..0eb99fdda 100644 --- a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net; +using System.Threading.Tasks; using FluentValidation.Results; using NLog; using NzbDrone.Common.Extensions; @@ -42,57 +43,57 @@ namespace NzbDrone.Core.Indexers _httpClient = httpClient; } - public override IndexerPageableQueryResult Fetch(MovieSearchCriteria searchCriteria) + public override Task Fetch(MovieSearchCriteria searchCriteria) { //TODO: Re-Enable when All Indexer Caps are fixed and tests don't fail //if (!SupportsSearch) //{ - // return new IndexerPageableQueryResult(); + // return Task.FromResult(new Task()); //} return FetchReleases(g => SetCookieFunctions(g).GetSearchRequests(searchCriteria)); } - public override IndexerPageableQueryResult Fetch(MusicSearchCriteria searchCriteria) + public override Task Fetch(MusicSearchCriteria searchCriteria) { if (!SupportsSearch) { - return new IndexerPageableQueryResult(); + return Task.FromResult(new IndexerPageableQueryResult()); } return FetchReleases(g => SetCookieFunctions(g).GetSearchRequests(searchCriteria)); } - public override IndexerPageableQueryResult Fetch(TvSearchCriteria searchCriteria) + public override Task Fetch(TvSearchCriteria searchCriteria) { if (!SupportsSearch) { - return new IndexerPageableQueryResult(); + return Task.FromResult(new IndexerPageableQueryResult()); } return FetchReleases(g => SetCookieFunctions(g).GetSearchRequests(searchCriteria)); } - public override IndexerPageableQueryResult Fetch(BookSearchCriteria searchCriteria) + public override Task Fetch(BookSearchCriteria searchCriteria) { if (!SupportsSearch) { - return new IndexerPageableQueryResult(); + return Task.FromResult(new IndexerPageableQueryResult()); } return FetchReleases(g => SetCookieFunctions(g).GetSearchRequests(searchCriteria)); } - public override IndexerPageableQueryResult Fetch(BasicSearchCriteria searchCriteria) + public override Task Fetch(BasicSearchCriteria searchCriteria) { if (!SupportsSearch) { - return new IndexerPageableQueryResult(); + return Task.FromResult(new IndexerPageableQueryResult()); } return FetchReleases(g => SetCookieFunctions(g).GetSearchRequests(searchCriteria)); } - public override byte[] Download(HttpUri link) + public override async Task Download(HttpUri link) { Cookies = GetCookies(); @@ -107,7 +108,8 @@ namespace NzbDrone.Core.Indexers try { - downloadBytes = _httpClient.Execute(requestBuilder.Build()).ResponseData; + var response = await _httpClient.ExecuteAsync(requestBuilder.Build()); + downloadBytes = response.ResponseData; } catch (Exception) { @@ -159,7 +161,7 @@ namespace NzbDrone.Core.Indexers _indexerStatusService.UpdateCookies(Definition.Id, cookies, expiration); } - protected virtual IndexerPageableQueryResult FetchReleases(Func pageableRequestChainSelector, bool isRecent = false) + protected virtual async Task FetchReleases(Func pageableRequestChainSelector, bool isRecent = false) { var releases = new List(); var result = new IndexerPageableQueryResult(); @@ -195,7 +197,7 @@ namespace NzbDrone.Core.Indexers { url = request.Url.FullUri; - var page = FetchPage(request, parser); + var page = await FetchPage(request, parser); result.Queries.Add(page); @@ -360,9 +362,9 @@ namespace NzbDrone.Core.Indexers return PageSize != 0 && page.Count >= PageSize; } - protected virtual IndexerQueryResult FetchPage(IndexerRequest request, IParseIndexerResponse parser) + protected virtual async Task FetchPage(IndexerRequest request, IParseIndexerResponse parser) { - var response = FetchIndexerResponse(request); + var response = await FetchIndexerResponse(request); try { @@ -398,11 +400,12 @@ namespace NzbDrone.Core.Indexers return false; } - protected virtual void DoLogin() + protected virtual Task DoLogin() { + return Task.CompletedTask; } - protected virtual IndexerResponse FetchIndexerResponse(IndexerRequest request) + protected virtual async Task FetchIndexerResponse(IndexerRequest request) { _logger.Debug("Downloading Feed " + request.HttpRequest.ToString(false)); @@ -431,7 +434,7 @@ namespace NzbDrone.Core.Indexers var stopWatch = Stopwatch.StartNew(); request.HttpRequest.SuppressHttpError = true; - var response = _httpClient.Execute(request.HttpRequest); + var response = await _httpClient.ExecuteAsync(request.HttpRequest); stopWatch.Stop(); @@ -440,7 +443,7 @@ namespace NzbDrone.Core.Indexers { _logger.Trace("Attempting to re-auth based on indexer search response"); - DoLogin(); + await DoLogin(); request.HttpRequest.Cookies.Clear(); if (Cookies != null) @@ -451,7 +454,7 @@ namespace NzbDrone.Core.Indexers } } - response = _httpClient.Execute(request.HttpRequest); + response = await _httpClient.ExecuteAsync(request.HttpRequest); } // Throw any other http error we get after attempting auth @@ -474,12 +477,12 @@ namespace NzbDrone.Core.Indexers return new IndexerResponse(request, response, stopWatch.ElapsedMilliseconds); } - protected override void Test(List failures) + protected override async Task Test(List failures) { - failures.AddIfNotNull(TestConnection()); + failures.AddIfNotNull(await TestConnection()); } - protected virtual ValidationFailure TestConnection() + protected virtual async Task TestConnection() { try { @@ -500,7 +503,7 @@ namespace NzbDrone.Core.Indexers return new ValidationFailure(string.Empty, "No rss feed query available. This may be an issue with the indexer or your indexer category settings."); } - var releases = FetchPage(firstRequest, parser); + var releases = await FetchPage(firstRequest, parser); if (releases.Releases.Empty()) { diff --git a/src/NzbDrone.Core/Indexers/IIndexer.cs b/src/NzbDrone.Core/Indexers/IIndexer.cs index cd46b636a..65ab4f7d2 100644 --- a/src/NzbDrone.Core/Indexers/IIndexer.cs +++ b/src/NzbDrone.Core/Indexers/IIndexer.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using NzbDrone.Common.Http; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.ThingiProvider; @@ -15,13 +16,13 @@ namespace NzbDrone.Core.Indexers DownloadProtocol Protocol { get; } IndexerPrivacy Privacy { get; } - IndexerPageableQueryResult Fetch(MovieSearchCriteria searchCriteria); - IndexerPageableQueryResult Fetch(MusicSearchCriteria searchCriteria); - IndexerPageableQueryResult Fetch(TvSearchCriteria searchCriteria); - IndexerPageableQueryResult Fetch(BookSearchCriteria searchCriteria); - IndexerPageableQueryResult Fetch(BasicSearchCriteria searchCriteria); + Task Fetch(MovieSearchCriteria searchCriteria); + Task Fetch(MusicSearchCriteria searchCriteria); + Task Fetch(TvSearchCriteria searchCriteria); + Task Fetch(BookSearchCriteria searchCriteria); + Task Fetch(BasicSearchCriteria searchCriteria); - byte[] Download(HttpUri link); + Task Download(HttpUri link); IndexerCapabilities GetCapabilities(); } diff --git a/src/NzbDrone.Core/Indexers/IndexerBase.cs b/src/NzbDrone.Core/Indexers/IndexerBase.cs index f4c7a383c..b53fe8cd7 100644 --- a/src/NzbDrone.Core/Indexers/IndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/IndexerBase.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using FluentValidation.Results; using NLog; using NzbDrone.Common.Extensions; @@ -68,12 +69,12 @@ namespace NzbDrone.Core.Indexers protected TSettings Settings => (TSettings)Definition.Settings; - public abstract IndexerPageableQueryResult Fetch(MovieSearchCriteria searchCriteria); - public abstract IndexerPageableQueryResult Fetch(MusicSearchCriteria searchCriteria); - public abstract IndexerPageableQueryResult Fetch(TvSearchCriteria searchCriteria); - public abstract IndexerPageableQueryResult Fetch(BookSearchCriteria searchCriteria); - public abstract IndexerPageableQueryResult Fetch(BasicSearchCriteria searchCriteria); - public abstract byte[] Download(HttpUri searchCriteria); + public abstract Task Fetch(MovieSearchCriteria searchCriteria); + public abstract Task Fetch(MusicSearchCriteria searchCriteria); + public abstract Task Fetch(TvSearchCriteria searchCriteria); + public abstract Task Fetch(BookSearchCriteria searchCriteria); + public abstract Task Fetch(BasicSearchCriteria searchCriteria); + public abstract Task Download(HttpUri searchCriteria); public abstract IndexerCapabilities GetCapabilities(); @@ -98,7 +99,7 @@ namespace NzbDrone.Core.Indexers try { - Test(failures); + Test(failures).GetAwaiter().GetResult(); } catch (Exception ex) { @@ -109,7 +110,7 @@ namespace NzbDrone.Core.Indexers return new ValidationResult(failures); } - protected abstract void Test(List failures); + protected abstract Task Test(List failures); public override string ToString() { diff --git a/src/NzbDrone.Host/Bootstrap.cs b/src/NzbDrone.Host/Bootstrap.cs index c4f5a944c..fd3c4bf76 100644 --- a/src/NzbDrone.Host/Bootstrap.cs +++ b/src/NzbDrone.Host/Bootstrap.cs @@ -142,7 +142,7 @@ namespace NzbDrone.Host }); builder.ConfigureKestrel(serverOptions => { - serverOptions.AllowSynchronousIO = true; + serverOptions.AllowSynchronousIO = false; serverOptions.Limits.MaxRequestBodySize = null; }); builder.UseStartup(); diff --git a/src/Prowlarr.Api.V1/Indexers/IndexerController.cs b/src/Prowlarr.Api.V1/Indexers/IndexerController.cs index b33928582..636a829cf 100644 --- a/src/Prowlarr.Api.V1/Indexers/IndexerController.cs +++ b/src/Prowlarr.Api.V1/Indexers/IndexerController.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Net; using System.Text; +using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using NzbDrone.Common.Extensions; using NzbDrone.Core.Indexers; @@ -41,7 +42,7 @@ namespace Prowlarr.Api.V1.Indexers } [HttpGet("{id:int}/newznab")] - public IActionResult GetNewznabResponse(int id, [FromQuery] NewznabRequest request) + public async Task GetNewznabResponse(int id, [FromQuery] NewznabRequest request) { var requestType = request.t; request.source = UserAgentParser.ParseSource(Request.Headers["User-Agent"]); @@ -64,13 +65,14 @@ namespace Prowlarr.Api.V1.Indexers switch (requestType) { case "caps": - return Content(indexerInstance.GetCapabilities().ToXml(), "application/rss+xml"); + var caps = indexerInstance.GetCapabilities(); + return Content(caps.ToXml(), "application/rss+xml"); case "search": case "tvsearch": case "music": case "book": case "movie": - var results = _nzbSearchService.Search(request, new List { indexer.Id }, false); + var results = await _nzbSearchService.Search(request, new List { indexer.Id }, false); return Content(results.ToXml(indexerInstance.Protocol), "application/rss+xml"); default: throw new BadRequestException("Function Not Available"); @@ -78,7 +80,7 @@ namespace Prowlarr.Api.V1.Indexers } [HttpGet("{id:int}/download")] - public object GetDownload(int id, string link, string file) + public async Task GetDownload(int id, string link, string file) { var indexerDef = _indexerFactory.Get(id); var indexer = _indexerFactory.GetInstance(indexerDef); @@ -107,7 +109,7 @@ namespace Prowlarr.Api.V1.Indexers } var downloadBytes = Array.Empty(); - downloadBytes = _downloadService.DownloadReport(unprotectedlLink, id, source, file); + downloadBytes = await _downloadService.DownloadReport(unprotectedlLink, id, source, file); // handle magnet URLs if (downloadBytes.Length >= 7 diff --git a/src/Prowlarr.Api.V1/Search/SearchController.cs b/src/Prowlarr.Api.V1/Search/SearchController.cs index c95ba6655..6a561ee2f 100644 --- a/src/Prowlarr.Api.V1/Search/SearchController.cs +++ b/src/Prowlarr.Api.V1/Search/SearchController.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Net; +using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using NLog; using NzbDrone.Common.Extensions; @@ -26,7 +27,7 @@ namespace Prowlarr.Api.V1.Search } [HttpGet] - public List GetAll(string query, [FromQuery] List indexerIds, [FromQuery] List categories) + public Task> GetAll(string query, [FromQuery] List indexerIds, [FromQuery] List categories) { if (query.IsNotNullOrWhiteSpace()) { @@ -40,15 +41,16 @@ namespace Prowlarr.Api.V1.Search } } - return new List(); + return Task.FromResult(new List()); } - private List GetSearchReleases(string query, List indexerIds, List categories) + private async Task> GetSearchReleases(string query, List indexerIds, List categories) { try { var request = new NewznabRequest { q = query, source = "Prowlarr", t = "search", cat = string.Join(",", categories), server = Request.GetServerUrl() }; - var decisions = _nzbSearhService.Search(request, indexerIds, true).Releases; + var result = await _nzbSearhService.Search(request, indexerIds, true); + var decisions = result.Releases; return MapDecisions(decisions); }