New: Make indexer HTTP requests async

This commit is contained in:
ta264
2021-03-17 21:20:57 +00:00
committed by Qstick
parent 231d43e181
commit 29da0b7031
29 changed files with 216 additions and 213 deletions

View File

@@ -12,6 +12,7 @@ namespace NzbDrone.Common.Http
{ {
Url = new HttpUri(url); Url = new HttpUri(url);
Headers = new HttpHeader(); Headers = new HttpHeader();
ConnectionKeepAlive = true;
AllowAutoRedirect = true; AllowAutoRedirect = true;
StoreRequestCookie = true; StoreRequestCookie = true;
IgnorePersistentCookies = false; IgnorePersistentCookies = false;

View File

@@ -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;
}
}
}

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Threading.Tasks;
using FluentAssertions; using FluentAssertions;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
@@ -27,15 +28,15 @@ namespace NzbDrone.Core.Test.IndexerTests.FileListTests
} }
[Test] [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"); var recentFeed = ReadAllText(@"Files/Indexers/FileList/recentfeed.json");
Mocker.GetMock<IHttpClient>() Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET))) .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed)); .Returns<HttpRequest>(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.Should().HaveCount(4);
releases.First().Should().BeOfType<TorrentInfo>(); releases.First().Should().BeOfType<TorrentInfo>();

View File

@@ -2,6 +2,7 @@ using System;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Text; using System.Text;
using System.Threading.Tasks;
using FluentAssertions; using FluentAssertions;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
@@ -39,15 +40,15 @@ namespace NzbDrone.Core.Test.IndexerTests.HDBitsTests
[TestCase("Files/Indexers/HdBits/RecentFeedLongIDs.json")] [TestCase("Files/Indexers/HdBits/RecentFeedLongIDs.json")]
[TestCase("Files/Indexers/HdBits/RecentFeedStringIDs.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); var responseJson = ReadAllText(fileName);
Mocker.GetMock<IHttpClient>() Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.POST))) .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.POST)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new CookieCollection(), responseJson)); .Returns<HttpRequest>(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.Should().HaveCount(2);
torrents.First().Should().BeOfType<HDBitsInfo>(); torrents.First().Should().BeOfType<HDBitsInfo>();
@@ -68,15 +69,15 @@ namespace NzbDrone.Core.Test.IndexerTests.HDBitsTests
} }
[Test] [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(); var responseJson = new { status = 5, message = "Invalid authentication credentials" }.ToJson();
Mocker.GetMock<IHttpClient>() Mocker.GetMock<IHttpClient>()
.Setup(v => v.Execute(It.IsAny<HttpRequest>())) .Setup(v => v.ExecuteAsync(It.IsAny<HttpRequest>()))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new CookieCollection(), Encoding.UTF8.GetBytes(responseJson))); .Returns<HttpRequest>(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(); torrents.Should().BeEmpty();

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Threading.Tasks;
using FluentAssertions; using FluentAssertions;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
@@ -37,15 +38,15 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests
} }
[Test] [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"); var recentFeed = ReadAllText(@"Files/Indexers/Newznab/newznab_nzb_su.xml");
Mocker.GetMock<IHttpClient>() Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET))) .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed)); .Returns<HttpRequest>(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); releases.Should().HaveCount(100);

View File

@@ -1,5 +1,6 @@
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Threading.Tasks;
using FluentAssertions; using FluentAssertions;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
@@ -27,7 +28,7 @@ namespace NzbDrone.Core.Test.IndexerTests.PTPTests
} }
[TestCase("Files/Indexers/PTP/imdbsearch.json")] [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" }; var authResponse = new PassThePopcornAuthResponse { Result = "Ok" };
@@ -36,14 +37,14 @@ namespace NzbDrone.Core.Test.IndexerTests.PTPTests
var responseJson = ReadAllText(fileName); var responseJson = ReadAllText(fileName);
Mocker.GetMock<IHttpClient>() Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.POST))) .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.POST)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new CookieCollection(), authStream.ToString())); .Returns<HttpRequest>(r => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), authStream.ToString())));
Mocker.GetMock<IHttpClient>() Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET))) .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader { ContentType = HttpAccept.Json.Value }, new CookieCollection(), responseJson)); .Returns<HttpRequest>(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.Should().HaveCount(293);
torrents.First().Should().BeOfType<PassThePopcornInfo>(); torrents.First().Should().BeOfType<PassThePopcornInfo>();

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Threading.Tasks;
using FluentAssertions; using FluentAssertions;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
@@ -32,15 +33,15 @@ namespace NzbDrone.Core.Test.IndexerTests.RarbgTests
} }
[Test] [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"); var recentFeed = ReadAllText(@"Files/Indexers/Rarbg/RecentFeed_v2.json");
Mocker.GetMock<IHttpClient>() Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET))) .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed)); .Returns<HttpRequest>(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.Should().HaveCount(4);
releases.First().Should().BeOfType<TorrentInfo>(); releases.First().Should().BeOfType<TorrentInfo>();
@@ -61,25 +62,25 @@ namespace NzbDrone.Core.Test.IndexerTests.RarbgTests
} }
[Test] [Test]
public void should_parse_error_20_as_empty_results() public async Task should_parse_error_20_as_empty_results()
{ {
Mocker.GetMock<IHttpClient>() Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET))) .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new CookieCollection(), "{ error_code: 20, error: \"some message\" }")); .Returns<HttpRequest>(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); releases.Should().HaveCount(0);
} }
[Test] [Test]
public void should_warn_on_unknown_error() public async Task should_warn_on_unknown_error()
{ {
Mocker.GetMock<IHttpClient>() Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET))) .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new CookieCollection(), "{ error_code: 25, error: \"some message\" }")); .Returns<HttpRequest>(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); releases.Should().HaveCount(0);

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Threading.Tasks;
using FluentAssertions; using FluentAssertions;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
@@ -38,15 +39,15 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests
} }
[Test] [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"); var recentFeed = ReadAllText(@"Files/Indexers/Torznab/torznab_hdaccess_net.xml");
Mocker.GetMock<IHttpClient>() Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET))) .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed)); .Returns<HttpRequest>(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); releases.Should().HaveCount(5);
@@ -67,15 +68,15 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests
} }
[Test] [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"); var recentFeed = ReadAllText(@"Files/Indexers/Torznab/torznab_tpb.xml");
Mocker.GetMock<IHttpClient>() Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET))) .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed)); .Returns<HttpRequest>(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); releases.Should().HaveCount(5);
@@ -97,15 +98,15 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests
} }
[Test] [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"); var recentFeed = ReadAllText(@"Files/Indexers/Torznab/torznab_animetosho.xml");
Mocker.GetMock<IHttpClient>() Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET))) .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed)); .Returns<HttpRequest>(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); releases.Should().HaveCount(2);

View File

@@ -4,7 +4,6 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using NLog; using NLog;
using NzbDrone.Common.Instrumentation.Extensions; using NzbDrone.Common.Instrumentation.Extensions;
using NzbDrone.Common.TPL;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.Events; using NzbDrone.Core.Indexers.Events;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
@@ -15,7 +14,7 @@ namespace NzbDrone.Core.IndexerSearch
{ {
public interface ISearchForNzb public interface ISearchForNzb
{ {
NewznabResults Search(NewznabRequest request, List<int> indexerIds, bool interactiveSearch); Task<NewznabResults> Search(NewznabRequest request, List<int> indexerIds, bool interactiveSearch);
} }
public class NzbSearchService : ISearchForNzb public class NzbSearchService : ISearchForNzb
@@ -36,7 +35,7 @@ namespace NzbDrone.Core.IndexerSearch
_logger = logger; _logger = logger;
} }
public NewznabResults Search(NewznabRequest request, List<int> indexerIds, bool interactiveSearch) public Task<NewznabResults> Search(NewznabRequest request, List<int> indexerIds, bool interactiveSearch)
{ {
switch (request.t) switch (request.t)
{ {
@@ -53,7 +52,7 @@ namespace NzbDrone.Core.IndexerSearch
} }
} }
private NewznabResults MovieSearch(NewznabRequest request, List<int> indexerIds, bool interactiveSearch) private async Task<NewznabResults> MovieSearch(NewznabRequest request, List<int> indexerIds, bool interactiveSearch)
{ {
var searchSpec = Get<MovieSearchCriteria>(request, indexerIds, interactiveSearch); var searchSpec = Get<MovieSearchCriteria>(request, indexerIds, interactiveSearch);
@@ -61,10 +60,10 @@ namespace NzbDrone.Core.IndexerSearch
searchSpec.TmdbId = request.tmdbid; searchSpec.TmdbId = request.tmdbid;
searchSpec.TraktId = request.traktid; 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<int> indexerIds, bool interactiveSearch) private async Task<NewznabResults> MusicSearch(NewznabRequest request, List<int> indexerIds, bool interactiveSearch)
{ {
var searchSpec = Get<MusicSearchCriteria>(request, indexerIds, interactiveSearch); var searchSpec = Get<MusicSearchCriteria>(request, indexerIds, interactiveSearch);
@@ -72,10 +71,10 @@ namespace NzbDrone.Core.IndexerSearch
searchSpec.Album = request.album; searchSpec.Album = request.album;
searchSpec.Label = request.label; 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<int> indexerIds, bool interactiveSearch) private async Task<NewznabResults> TvSearch(NewznabRequest request, List<int> indexerIds, bool interactiveSearch)
{ {
var searchSpec = Get<TvSearchCriteria>(request, indexerIds, interactiveSearch); var searchSpec = Get<TvSearchCriteria>(request, indexerIds, interactiveSearch);
@@ -87,24 +86,24 @@ namespace NzbDrone.Core.IndexerSearch
searchSpec.RId = request.rid; searchSpec.RId = request.rid;
searchSpec.TvMazeId = request.tvmazeid; 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<int> indexerIds, bool interactiveSearch) private async Task<NewznabResults> BookSearch(NewznabRequest request, List<int> indexerIds, bool interactiveSearch)
{ {
var searchSpec = Get<BookSearchCriteria>(request, indexerIds, interactiveSearch); var searchSpec = Get<BookSearchCriteria>(request, indexerIds, interactiveSearch);
searchSpec.Author = request.author; searchSpec.Author = request.author;
searchSpec.Title = request.title; 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<int> indexerIds, bool interactiveSearch) private async Task<NewznabResults> BasicSearch(NewznabRequest request, List<int> indexerIds, bool interactiveSearch)
{ {
var searchSpec = Get<BasicSearchCriteria>(request, indexerIds, interactiveSearch); var searchSpec = Get<BasicSearchCriteria>(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<ReleaseInfo> MapReleases(List<ReleaseInfo> releases, string serverUrl) private List<ReleaseInfo> MapReleases(List<ReleaseInfo> releases, string serverUrl)
@@ -145,7 +144,7 @@ namespace NzbDrone.Core.IndexerSearch
return spec; return spec;
} }
private List<ReleaseInfo> Dispatch(Func<IIndexer, IndexerPageableQueryResult> searchAction, SearchCriteriaBase criteriaBase) private async Task<List<ReleaseInfo>> Dispatch(Func<IIndexer, Task<IndexerPageableQueryResult>> searchAction, SearchCriteriaBase criteriaBase)
{ {
var indexers = _indexerFactory.GetAvailableProviders(); var indexers = _indexerFactory.GetAvailableProviders();
@@ -157,46 +156,39 @@ namespace NzbDrone.Core.IndexerSearch
.ToList(); .ToList();
} }
var reports = new List<ReleaseInfo>();
_logger.ProgressInfo("Searching {0} indexers for {1}", indexers.Count, criteriaBase.SearchTerm); _logger.ProgressInfo("Searching {0} indexers for {1}", indexers.Count, criteriaBase.SearchTerm);
var taskList = new List<Task>(); var tasks = indexers.Select(x => DispatchIndexer(searchAction, x, criteriaBase));
var taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.None);
foreach (var indexer in indexers) var batch = await Task.WhenAll(tasks);
{
var indexerLocal = indexer;
taskList.Add(taskFactory.StartNew(() => var reports = batch.SelectMany(x => x).ToList();
{
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());
_logger.Debug("Total of {0} reports were found for {1} from {2} indexers", reports.Count, criteriaBase, indexers.Count); _logger.Debug("Total of {0} reports were found for {1} from {2} indexers", reports.Count, criteriaBase, indexers.Count);
return reports; return reports;
} }
private async Task<IList<ReleaseInfo>> DispatchIndexer(Func<IIndexer, Task<IndexerPageableQueryResult>> 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<ReleaseInfo>();
}
} }
} }

View File

@@ -4,6 +4,7 @@ using System.Collections.Specialized;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks;
using AngleSharp.Html.Parser; using AngleSharp.Html.Parser;
using FluentValidation; using FluentValidation;
using NLog; using NLog;
@@ -44,7 +45,7 @@ namespace NzbDrone.Core.Indexers.Definitions
return new AnimeTorrentsParser(Settings, Capabilities.Categories, BaseUrl); return new AnimeTorrentsParser(Settings, Capabilities.Categories, BaseUrl);
} }
protected override void DoLogin() protected override async Task DoLogin()
{ {
UpdateCookies(null, null); UpdateCookies(null, null);
@@ -54,7 +55,7 @@ namespace NzbDrone.Core.Indexers.Definitions
AllowAutoRedirect = true AllowAutoRedirect = true
}; };
var loginPage = _httpClient.Execute(new HttpRequest(LoginUrl)); var loginPage = await _httpClient.ExecuteAsync(new HttpRequest(LoginUrl));
requestBuilder.Method = HttpMethod.POST; requestBuilder.Method = HttpMethod.POST;
requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15);
requestBuilder.SetCookies(loginPage.GetCookies()); requestBuilder.SetCookies(loginPage.GetCookies());
@@ -67,7 +68,7 @@ namespace NzbDrone.Core.Indexers.Definitions
.SetHeader("Content-Type", "multipart/form-data") .SetHeader("Content-Type", "multipart/form-data")
.Build(); .Build();
var response = _httpClient.Execute(authLoginRequest); var response = await _httpClient.ExecuteAsync(authLoginRequest);
if (response.Content != null && response.Content.Contains("logout.php")) if (response.Content != null && response.Content.Contains("logout.php"))
{ {

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Net; using System.Net;
using System.Threading.Tasks;
using FluentValidation.Results; using FluentValidation.Results;
using NLog; using NLog;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
@@ -52,9 +53,9 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
return caps; return caps;
} }
protected override void DoLogin() protected override async Task DoLogin()
{ {
Settings.Token = GetToken(); Settings.Token = await GetToken();
if (Definition.Id > 0) if (Definition.Id > 0)
{ {
@@ -74,11 +75,11 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
return false; return false;
} }
protected override ValidationFailure TestConnection() protected override async Task<ValidationFailure> TestConnection()
{ {
try try
{ {
GetToken(); await GetToken();
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -90,7 +91,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
return null; return null;
} }
private string GetToken() private async Task<string> GetToken()
{ {
var requestBuilder = new HttpRequestBuilder(LoginUrl) var requestBuilder = new HttpRequestBuilder(LoginUrl)
{ {
@@ -108,7 +109,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
.Accept(HttpAccept.Json) .Accept(HttpAccept.Json)
.Build(); .Build();
var response = _httpClient.Post<AvistazAuthResponse>(authLoginRequest); var response = await _httpClient.PostAsync<AvistazAuthResponse>(authLoginRequest);
var token = response.Resource.Token; var token = response.Resource.Token;
return token; return token;

View File

@@ -5,6 +5,7 @@ using System.Globalization;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks;
using AngleSharp.Dom; using AngleSharp.Dom;
using AngleSharp.Html.Parser; using AngleSharp.Html.Parser;
using FluentValidation; using FluentValidation;
@@ -45,7 +46,7 @@ namespace NzbDrone.Core.Indexers.Definitions
return new BakaBTParser(Settings, Capabilities.Categories, BaseUrl); return new BakaBTParser(Settings, Capabilities.Categories, BaseUrl);
} }
protected override void DoLogin() protected override async Task DoLogin()
{ {
UpdateCookies(null, null); UpdateCookies(null, null);
@@ -55,7 +56,7 @@ namespace NzbDrone.Core.Indexers.Definitions
AllowAutoRedirect = true AllowAutoRedirect = true
}; };
var loginPage = _httpClient.Execute(new HttpRequest(LoginUrl)); var loginPage = await _httpClient.ExecuteAsync(new HttpRequest(LoginUrl));
requestBuilder.Method = HttpMethod.POST; requestBuilder.Method = HttpMethod.POST;
requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15);
@@ -77,7 +78,7 @@ namespace NzbDrone.Core.Indexers.Definitions
.SetHeader("Content-Type", "multipart/form-data") .SetHeader("Content-Type", "multipart/form-data")
.Build(); .Build();
var response = _httpClient.Execute(authLoginRequest); var response = await _httpClient.ExecuteAsync(authLoginRequest);
if (response.Content != null && response.Content.Contains("<a href=\"logout.php\">Logout</a>")) if (response.Content != null && response.Content.Contains("<a href=\"logout.php\">Logout</a>"))
{ {

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks;
using FluentValidation.Results; using FluentValidation.Results;
using NLog; using NLog;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
@@ -95,18 +96,18 @@ namespace NzbDrone.Core.Indexers.Cardigann
return generator.CheckIfLoginIsNeeded(httpResponse); return generator.CheckIfLoginIsNeeded(httpResponse);
} }
protected override void DoLogin() protected override async Task DoLogin()
{ {
var generator = (CardigannRequestGenerator)GetRequestGenerator(); var generator = (CardigannRequestGenerator)GetRequestGenerator();
SetCookieFunctions(generator); SetCookieFunctions(generator);
generator.DoLogin(); await generator.DoLogin();
} }
protected override void Test(List<ValidationFailure> failures) protected override async Task Test(List<ValidationFailure> failures)
{ {
base.Test(failures); await base.Test(failures);
if (failures.HasErrors()) if (failures.HasErrors())
{ {
return; return;

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Threading.Tasks;
using AngleSharp.Html.Dom; using AngleSharp.Html.Dom;
using AngleSharp.Html.Parser; using AngleSharp.Html.Parser;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
@@ -157,7 +158,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
return variables; return variables;
} }
public void DoLogin() public async Task DoLogin()
{ {
var login = _definition.Login; var login = _definition.Login;
@@ -190,7 +191,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
requestBuilder.Headers.Add("Referer", SiteLink); requestBuilder.Headers.Add("Referer", SiteLink);
var response = HttpClient.Execute(requestBuilder.Build()); var response = await HttpClient.ExecuteAsync(requestBuilder.Build());
Cookies = response.GetCookies(); 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 // landingResultDocument might not be initiated if the login is caused by a relogin during a query
if (landingResultDocument == null) if (landingResultDocument == null)
{ {
GetConfigurationForSetup(true); await GetConfigurationForSetup(true);
} }
var form = landingResultDocument.QuerySelector(formSelector); var form = landingResultDocument.QuerySelector(formSelector);
@@ -327,7 +328,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
requestBuilder.Headers.Add("Referer", loginUrl); 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 simpleCaptchaJSON = JObject.Parse(simpleCaptchaResult.Content);
var captchaSelection = simpleCaptchaJSON["images"][0]["hash"].ToString(); var captchaSelection = simpleCaptchaJSON["images"][0]["hash"].ToString();
@@ -431,7 +432,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
var request = requestBuilder.Build(); var request = requestBuilder.Build();
request.SetContent(body); request.SetContent(body);
loginResult = HttpClient.Execute(request); loginResult = await HttpClient.ExecuteAsync(request);
} }
else else
{ {
@@ -451,7 +452,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
requestBuilder.AddFormParameter(pair.Key, pair.Value); requestBuilder.AddFormParameter(pair.Key, pair.Value);
} }
loginResult = HttpClient.Execute(requestBuilder.Build()); loginResult = await HttpClient.ExecuteAsync(requestBuilder.Build());
} }
Cookies = loginResult.GetCookies(); Cookies = loginResult.GetCookies();
@@ -486,7 +487,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
requestBuilder.Headers.Add("Referer", SiteLink); requestBuilder.Headers.Add("Referer", SiteLink);
var response = HttpClient.Execute(requestBuilder.Build()); var response = await HttpClient.ExecuteAsync(requestBuilder.Build());
Cookies = response.GetCookies(); Cookies = response.GetCookies();
@@ -510,7 +511,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
requestBuilder.Headers.Add("Referer", SiteLink); requestBuilder.Headers.Add("Referer", SiteLink);
var response = HttpClient.Execute(requestBuilder.Build()); var response = await HttpClient.ExecuteAsync(requestBuilder.Build());
Cookies = response.GetCookies(); Cookies = response.GetCookies();
@@ -556,7 +557,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
return true; return true;
} }
public void GetConfigurationForSetup(bool automaticlogin) public async Task GetConfigurationForSetup(bool automaticlogin)
{ {
var login = _definition.Login; var login = _definition.Login;
@@ -587,7 +588,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
requestBuilder.SetCookies(Cookies); requestBuilder.SetCookies(Cookies);
} }
landingResult = HttpClient.Execute(requestBuilder.Build()); landingResult = await HttpClient.ExecuteAsync(requestBuilder.Build());
Cookies = landingResult.GetCookies(); Cookies = landingResult.GetCookies();
@@ -659,7 +660,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
return; return;
} }
protected bool TestLogin() protected async Task<bool> TestLogin()
{ {
var login = _definition.Login; var login = _definition.Login;
@@ -684,7 +685,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
requestBuilder.SetCookies(Cookies); requestBuilder.SetCookies(Cookies);
} }
var testResult = HttpClient.Execute(requestBuilder.Build()); var testResult = await HttpClient.ExecuteAsync(requestBuilder.Build());
if (testResult.HasHttpRedirect) if (testResult.HasHttpRedirect)
{ {

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Threading.Tasks;
using NLog; using NLog;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
@@ -47,7 +48,7 @@ namespace NzbDrone.Core.Indexers.Gazelle
return caps; return caps;
} }
protected override void DoLogin() protected override async Task DoLogin()
{ {
var requestBuilder = new HttpRequestBuilder(LoginUrl) var requestBuilder = new HttpRequestBuilder(LoginUrl)
{ {
@@ -68,7 +69,7 @@ namespace NzbDrone.Core.Indexers.Gazelle
.Accept(HttpAccept.Json) .Accept(HttpAccept.Json)
.Build(); .Build();
var response = _httpClient.Execute(authLoginRequest); var response = await _httpClient.ExecuteAsync(authLoginRequest);
cookies = response.GetCookies(); cookies = response.GetCookies();

View File

@@ -4,6 +4,7 @@ using System.Collections.Specialized;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks;
using AngleSharp.Html.Parser; using AngleSharp.Html.Parser;
using FluentValidation; using FluentValidation;
using NLog; using NLog;
@@ -43,7 +44,7 @@ namespace NzbDrone.Core.Indexers.Definitions
return new HDTorrentsParser(Settings, Capabilities.Categories, BaseUrl); return new HDTorrentsParser(Settings, Capabilities.Categories, BaseUrl);
} }
protected override void DoLogin() protected override async Task DoLogin()
{ {
var requestBuilder = new HttpRequestBuilder(LoginUrl) var requestBuilder = new HttpRequestBuilder(LoginUrl)
{ {
@@ -62,7 +63,7 @@ namespace NzbDrone.Core.Indexers.Definitions
.SetHeader("Content-Type", "multipart/form-data") .SetHeader("Content-Type", "multipart/form-data")
.Build(); .Build();
var response = _httpClient.Execute(authLoginRequest); var response = await _httpClient.ExecuteAsync(authLoginRequest);
cookies = response.GetCookies(); cookies = response.GetCookies();
UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30)); UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30));

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using FluentValidation.Results; using FluentValidation.Results;
using NLog; using NLog;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
@@ -38,9 +39,9 @@ namespace NzbDrone.Core.Indexers.Headphones
{ {
} }
protected override void Test(List<ValidationFailure> failures) protected override async Task Test(List<ValidationFailure> failures)
{ {
base.Test(failures); await base.Test(failures);
if (failures.Any()) if (failures.Any())
{ {
@@ -48,7 +49,7 @@ namespace NzbDrone.Core.Indexers.Headphones
} }
} }
public override byte[] Download(HttpUri link) public override async Task<byte[]> Download(HttpUri link)
{ {
var requestBuilder = new HttpRequestBuilder(link.FullUri); var requestBuilder = new HttpRequestBuilder(link.FullUri);
@@ -60,7 +61,8 @@ namespace NzbDrone.Core.Indexers.Headphones
try try
{ {
downloadBytes = _httpClient.Execute(request).ResponseData; var response = await _httpClient.ExecuteAsync(request);
downloadBytes = response.ResponseData;
} }
catch (Exception) catch (Exception)
{ {

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using FluentValidation.Results; using FluentValidation.Results;
using NLog; using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
@@ -131,9 +132,9 @@ namespace NzbDrone.Core.Indexers.Newznab
return settings; return settings;
} }
protected override void Test(List<ValidationFailure> failures) protected override async Task Test(List<ValidationFailure> failures)
{ {
base.Test(failures); await base.Test(failures);
if (failures.HasErrors()) if (failures.HasErrors())
{ {
return; return;

View File

@@ -4,6 +4,7 @@ using System.Collections.Specialized;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks;
using AngleSharp.Html.Parser; using AngleSharp.Html.Parser;
using FluentValidation; using FluentValidation;
using NLog; using NLog;
@@ -45,7 +46,7 @@ namespace NzbDrone.Core.Indexers.Definitions
return new RevolutionTTParser(Settings, Capabilities.Categories, BaseUrl); return new RevolutionTTParser(Settings, Capabilities.Categories, BaseUrl);
} }
protected override void DoLogin() protected override async Task DoLogin()
{ {
UpdateCookies(null, null); UpdateCookies(null, null);
@@ -55,7 +56,7 @@ namespace NzbDrone.Core.Indexers.Definitions
AllowAutoRedirect = true 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.Method = HttpMethod.POST;
requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15);
@@ -67,7 +68,7 @@ namespace NzbDrone.Core.Indexers.Definitions
.SetHeader("Content-Type", "multipart/form-data") .SetHeader("Content-Type", "multipart/form-data")
.Build(); .Build();
var response = _httpClient.Execute(authLoginRequest); var response = await _httpClient.ExecuteAsync(authLoginRequest);
if (response.Content != null && response.Content.Contains("/logout.php")) if (response.Content != null && response.Content.Contains("/logout.php"))
{ {

View File

@@ -4,6 +4,7 @@ using System.Globalization;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks;
using FluentValidation; using FluentValidation;
using Newtonsoft.Json; using Newtonsoft.Json;
using NLog; using NLog;
@@ -44,7 +45,7 @@ namespace NzbDrone.Core.Indexers.Definitions
return new TorrentLeechParser(Settings, Capabilities.Categories, BaseUrl); return new TorrentLeechParser(Settings, Capabilities.Categories, BaseUrl);
} }
protected override void DoLogin() protected override async Task DoLogin()
{ {
var requestBuilder = new HttpRequestBuilder(LoginUrl) var requestBuilder = new HttpRequestBuilder(LoginUrl)
{ {
@@ -63,7 +64,7 @@ namespace NzbDrone.Core.Indexers.Definitions
.SetHeader("Content-Type", "multipart/form-data") .SetHeader("Content-Type", "multipart/form-data")
.Build(); .Build();
var response = _httpClient.Execute(authLoginRequest); var response = await _httpClient.ExecuteAsync(authLoginRequest);
cookies = response.GetCookies(); cookies = response.GetCookies();
UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30)); UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30));

View File

@@ -4,6 +4,7 @@ using System.Collections.Specialized;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks;
using AngleSharp.Html.Parser; using AngleSharp.Html.Parser;
using FluentValidation; using FluentValidation;
using NLog; using NLog;
@@ -44,14 +45,14 @@ namespace NzbDrone.Core.Indexers.Definitions
return new TorrentSeedsParser(Settings, Capabilities.Categories, BaseUrl); return new TorrentSeedsParser(Settings, Capabilities.Categories, BaseUrl);
} }
protected override void DoLogin() protected override async Task DoLogin()
{ {
var requestBuilder = new HttpRequestBuilder(LoginUrl) var requestBuilder = new HttpRequestBuilder(LoginUrl)
{ {
LogResponseContent = true LogResponseContent = true
}; };
var loginPage = _httpClient.Execute(new HttpRequest(TokenUrl)); var loginPage = await _httpClient.ExecuteAsync(new HttpRequest(TokenUrl));
var parser = new HtmlParser(); var parser = new HtmlParser();
var dom = parser.ParseDocument(loginPage.Content); var dom = parser.ParseDocument(loginPage.Content);
var token = dom.QuerySelector("form.form-horizontal > span"); var token = dom.QuerySelector("form.form-horizontal > span");
@@ -72,7 +73,7 @@ namespace NzbDrone.Core.Indexers.Definitions
.SetHeader("Content-Type", "multipart/form-data") .SetHeader("Content-Type", "multipart/form-data")
.Build(); .Build();
var response = _httpClient.Execute(authLoginRequest); var response = await _httpClient.ExecuteAsync(authLoginRequest);
cookies = response.GetCookies(); cookies = response.GetCookies();
UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30)); UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30));

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using FluentValidation.Results; using FluentValidation.Results;
using NLog; using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
@@ -81,9 +82,9 @@ namespace NzbDrone.Core.Indexers.Torznab
return settings; return settings;
} }
protected override void Test(List<ValidationFailure> failures) protected override async Task Test(List<ValidationFailure> failures)
{ {
base.Test(failures); await base.Test(failures);
if (failures.HasErrors()) if (failures.HasErrors())
{ {
return; return;

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Threading.Tasks;
using NLog; using NLog;
using NzbDrone.Common.EnsureThat; using NzbDrone.Common.EnsureThat;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
@@ -12,7 +13,7 @@ namespace NzbDrone.Core.Indexers
{ {
public interface IDownloadService public interface IDownloadService
{ {
byte[] DownloadReport(string link, int indexerId, string source, string title); Task<byte[]> DownloadReport(string link, int indexerId, string source, string title);
void RecordRedirect(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; _logger = logger;
} }
public byte[] DownloadReport(string link, int indexerId, string source, string title) public async Task<byte[]> DownloadReport(string link, int indexerId, string source, string title)
{ {
var url = new HttpUri(link); var url = new HttpUri(link);
// Limit grabs to 2 per second. // Limit grabs to 2 per second.
if (link.IsNotNullOrWhiteSpace() && !link.StartsWith("magnet:")) 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)); var indexer = _indexerFactory.GetInstance(_indexerFactory.Get(indexerId));
@@ -53,7 +54,7 @@ namespace NzbDrone.Core.Indexers
try try
{ {
downloadedBytes = indexer.Download(url); downloadedBytes = await indexer.Download(url);
_indexerStatusService.RecordSuccess(indexerId); _indexerStatusService.RecordSuccess(indexerId);
success = true; success = true;
} }

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Threading.Tasks;
using FluentValidation.Results; using FluentValidation.Results;
using NLog; using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
@@ -42,57 +43,57 @@ namespace NzbDrone.Core.Indexers
_httpClient = httpClient; _httpClient = httpClient;
} }
public override IndexerPageableQueryResult Fetch(MovieSearchCriteria searchCriteria) public override Task<IndexerPageableQueryResult> Fetch(MovieSearchCriteria searchCriteria)
{ {
//TODO: Re-Enable when All Indexer Caps are fixed and tests don't fail //TODO: Re-Enable when All Indexer Caps are fixed and tests don't fail
//if (!SupportsSearch) //if (!SupportsSearch)
//{ //{
// return new IndexerPageableQueryResult(); // return Task.FromResult(new Task<IndexerPageableQueryResult>());
//} //}
return FetchReleases(g => SetCookieFunctions(g).GetSearchRequests(searchCriteria)); return FetchReleases(g => SetCookieFunctions(g).GetSearchRequests(searchCriteria));
} }
public override IndexerPageableQueryResult Fetch(MusicSearchCriteria searchCriteria) public override Task<IndexerPageableQueryResult> Fetch(MusicSearchCriteria searchCriteria)
{ {
if (!SupportsSearch) if (!SupportsSearch)
{ {
return new IndexerPageableQueryResult(); return Task.FromResult(new IndexerPageableQueryResult());
} }
return FetchReleases(g => SetCookieFunctions(g).GetSearchRequests(searchCriteria)); return FetchReleases(g => SetCookieFunctions(g).GetSearchRequests(searchCriteria));
} }
public override IndexerPageableQueryResult Fetch(TvSearchCriteria searchCriteria) public override Task<IndexerPageableQueryResult> Fetch(TvSearchCriteria searchCriteria)
{ {
if (!SupportsSearch) if (!SupportsSearch)
{ {
return new IndexerPageableQueryResult(); return Task.FromResult(new IndexerPageableQueryResult());
} }
return FetchReleases(g => SetCookieFunctions(g).GetSearchRequests(searchCriteria)); return FetchReleases(g => SetCookieFunctions(g).GetSearchRequests(searchCriteria));
} }
public override IndexerPageableQueryResult Fetch(BookSearchCriteria searchCriteria) public override Task<IndexerPageableQueryResult> Fetch(BookSearchCriteria searchCriteria)
{ {
if (!SupportsSearch) if (!SupportsSearch)
{ {
return new IndexerPageableQueryResult(); return Task.FromResult(new IndexerPageableQueryResult());
} }
return FetchReleases(g => SetCookieFunctions(g).GetSearchRequests(searchCriteria)); return FetchReleases(g => SetCookieFunctions(g).GetSearchRequests(searchCriteria));
} }
public override IndexerPageableQueryResult Fetch(BasicSearchCriteria searchCriteria) public override Task<IndexerPageableQueryResult> Fetch(BasicSearchCriteria searchCriteria)
{ {
if (!SupportsSearch) if (!SupportsSearch)
{ {
return new IndexerPageableQueryResult(); return Task.FromResult(new IndexerPageableQueryResult());
} }
return FetchReleases(g => SetCookieFunctions(g).GetSearchRequests(searchCriteria)); return FetchReleases(g => SetCookieFunctions(g).GetSearchRequests(searchCriteria));
} }
public override byte[] Download(HttpUri link) public override async Task<byte[]> Download(HttpUri link)
{ {
Cookies = GetCookies(); Cookies = GetCookies();
@@ -107,7 +108,8 @@ namespace NzbDrone.Core.Indexers
try try
{ {
downloadBytes = _httpClient.Execute(requestBuilder.Build()).ResponseData; var response = await _httpClient.ExecuteAsync(requestBuilder.Build());
downloadBytes = response.ResponseData;
} }
catch (Exception) catch (Exception)
{ {
@@ -159,7 +161,7 @@ namespace NzbDrone.Core.Indexers
_indexerStatusService.UpdateCookies(Definition.Id, cookies, expiration); _indexerStatusService.UpdateCookies(Definition.Id, cookies, expiration);
} }
protected virtual IndexerPageableQueryResult FetchReleases(Func<IIndexerRequestGenerator, IndexerPageableRequestChain> pageableRequestChainSelector, bool isRecent = false) protected virtual async Task<IndexerPageableQueryResult> FetchReleases(Func<IIndexerRequestGenerator, IndexerPageableRequestChain> pageableRequestChainSelector, bool isRecent = false)
{ {
var releases = new List<ReleaseInfo>(); var releases = new List<ReleaseInfo>();
var result = new IndexerPageableQueryResult(); var result = new IndexerPageableQueryResult();
@@ -195,7 +197,7 @@ namespace NzbDrone.Core.Indexers
{ {
url = request.Url.FullUri; url = request.Url.FullUri;
var page = FetchPage(request, parser); var page = await FetchPage(request, parser);
result.Queries.Add(page); result.Queries.Add(page);
@@ -360,9 +362,9 @@ namespace NzbDrone.Core.Indexers
return PageSize != 0 && page.Count >= PageSize; return PageSize != 0 && page.Count >= PageSize;
} }
protected virtual IndexerQueryResult FetchPage(IndexerRequest request, IParseIndexerResponse parser) protected virtual async Task<IndexerQueryResult> FetchPage(IndexerRequest request, IParseIndexerResponse parser)
{ {
var response = FetchIndexerResponse(request); var response = await FetchIndexerResponse(request);
try try
{ {
@@ -398,11 +400,12 @@ namespace NzbDrone.Core.Indexers
return false; return false;
} }
protected virtual void DoLogin() protected virtual Task DoLogin()
{ {
return Task.CompletedTask;
} }
protected virtual IndexerResponse FetchIndexerResponse(IndexerRequest request) protected virtual async Task<IndexerResponse> FetchIndexerResponse(IndexerRequest request)
{ {
_logger.Debug("Downloading Feed " + request.HttpRequest.ToString(false)); _logger.Debug("Downloading Feed " + request.HttpRequest.ToString(false));
@@ -431,7 +434,7 @@ namespace NzbDrone.Core.Indexers
var stopWatch = Stopwatch.StartNew(); var stopWatch = Stopwatch.StartNew();
request.HttpRequest.SuppressHttpError = true; request.HttpRequest.SuppressHttpError = true;
var response = _httpClient.Execute(request.HttpRequest); var response = await _httpClient.ExecuteAsync(request.HttpRequest);
stopWatch.Stop(); stopWatch.Stop();
@@ -440,7 +443,7 @@ namespace NzbDrone.Core.Indexers
{ {
_logger.Trace("Attempting to re-auth based on indexer search response"); _logger.Trace("Attempting to re-auth based on indexer search response");
DoLogin(); await DoLogin();
request.HttpRequest.Cookies.Clear(); request.HttpRequest.Cookies.Clear();
if (Cookies != null) 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 // 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); return new IndexerResponse(request, response, stopWatch.ElapsedMilliseconds);
} }
protected override void Test(List<ValidationFailure> failures) protected override async Task Test(List<ValidationFailure> failures)
{ {
failures.AddIfNotNull(TestConnection()); failures.AddIfNotNull(await TestConnection());
} }
protected virtual ValidationFailure TestConnection() protected virtual async Task<ValidationFailure> TestConnection()
{ {
try 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."); 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()) if (releases.Releases.Empty())
{ {

View File

@@ -1,3 +1,4 @@
using System.Threading.Tasks;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.ThingiProvider;
@@ -15,13 +16,13 @@ namespace NzbDrone.Core.Indexers
DownloadProtocol Protocol { get; } DownloadProtocol Protocol { get; }
IndexerPrivacy Privacy { get; } IndexerPrivacy Privacy { get; }
IndexerPageableQueryResult Fetch(MovieSearchCriteria searchCriteria); Task<IndexerPageableQueryResult> Fetch(MovieSearchCriteria searchCriteria);
IndexerPageableQueryResult Fetch(MusicSearchCriteria searchCriteria); Task<IndexerPageableQueryResult> Fetch(MusicSearchCriteria searchCriteria);
IndexerPageableQueryResult Fetch(TvSearchCriteria searchCriteria); Task<IndexerPageableQueryResult> Fetch(TvSearchCriteria searchCriteria);
IndexerPageableQueryResult Fetch(BookSearchCriteria searchCriteria); Task<IndexerPageableQueryResult> Fetch(BookSearchCriteria searchCriteria);
IndexerPageableQueryResult Fetch(BasicSearchCriteria searchCriteria); Task<IndexerPageableQueryResult> Fetch(BasicSearchCriteria searchCriteria);
byte[] Download(HttpUri link); Task<byte[]> Download(HttpUri link);
IndexerCapabilities GetCapabilities(); IndexerCapabilities GetCapabilities();
} }

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using FluentValidation.Results; using FluentValidation.Results;
using NLog; using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
@@ -68,12 +69,12 @@ namespace NzbDrone.Core.Indexers
protected TSettings Settings => (TSettings)Definition.Settings; protected TSettings Settings => (TSettings)Definition.Settings;
public abstract IndexerPageableQueryResult Fetch(MovieSearchCriteria searchCriteria); public abstract Task<IndexerPageableQueryResult> Fetch(MovieSearchCriteria searchCriteria);
public abstract IndexerPageableQueryResult Fetch(MusicSearchCriteria searchCriteria); public abstract Task<IndexerPageableQueryResult> Fetch(MusicSearchCriteria searchCriteria);
public abstract IndexerPageableQueryResult Fetch(TvSearchCriteria searchCriteria); public abstract Task<IndexerPageableQueryResult> Fetch(TvSearchCriteria searchCriteria);
public abstract IndexerPageableQueryResult Fetch(BookSearchCriteria searchCriteria); public abstract Task<IndexerPageableQueryResult> Fetch(BookSearchCriteria searchCriteria);
public abstract IndexerPageableQueryResult Fetch(BasicSearchCriteria searchCriteria); public abstract Task<IndexerPageableQueryResult> Fetch(BasicSearchCriteria searchCriteria);
public abstract byte[] Download(HttpUri searchCriteria); public abstract Task<byte[]> Download(HttpUri searchCriteria);
public abstract IndexerCapabilities GetCapabilities(); public abstract IndexerCapabilities GetCapabilities();
@@ -98,7 +99,7 @@ namespace NzbDrone.Core.Indexers
try try
{ {
Test(failures); Test(failures).GetAwaiter().GetResult();
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -109,7 +110,7 @@ namespace NzbDrone.Core.Indexers
return new ValidationResult(failures); return new ValidationResult(failures);
} }
protected abstract void Test(List<ValidationFailure> failures); protected abstract Task Test(List<ValidationFailure> failures);
public override string ToString() public override string ToString()
{ {

View File

@@ -142,7 +142,7 @@ namespace NzbDrone.Host
}); });
builder.ConfigureKestrel(serverOptions => builder.ConfigureKestrel(serverOptions =>
{ {
serverOptions.AllowSynchronousIO = true; serverOptions.AllowSynchronousIO = false;
serverOptions.Limits.MaxRequestBodySize = null; serverOptions.Limits.MaxRequestBodySize = null;
}); });
builder.UseStartup<Startup>(); builder.UseStartup<Startup>();

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
using System.Text; using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
@@ -41,7 +42,7 @@ namespace Prowlarr.Api.V1.Indexers
} }
[HttpGet("{id:int}/newznab")] [HttpGet("{id:int}/newznab")]
public IActionResult GetNewznabResponse(int id, [FromQuery] NewznabRequest request) public async Task<IActionResult> GetNewznabResponse(int id, [FromQuery] NewznabRequest request)
{ {
var requestType = request.t; var requestType = request.t;
request.source = UserAgentParser.ParseSource(Request.Headers["User-Agent"]); request.source = UserAgentParser.ParseSource(Request.Headers["User-Agent"]);
@@ -64,13 +65,14 @@ namespace Prowlarr.Api.V1.Indexers
switch (requestType) switch (requestType)
{ {
case "caps": case "caps":
return Content(indexerInstance.GetCapabilities().ToXml(), "application/rss+xml"); var caps = indexerInstance.GetCapabilities();
return Content(caps.ToXml(), "application/rss+xml");
case "search": case "search":
case "tvsearch": case "tvsearch":
case "music": case "music":
case "book": case "book":
case "movie": case "movie":
var results = _nzbSearchService.Search(request, new List<int> { indexer.Id }, false); var results = await _nzbSearchService.Search(request, new List<int> { indexer.Id }, false);
return Content(results.ToXml(indexerInstance.Protocol), "application/rss+xml"); return Content(results.ToXml(indexerInstance.Protocol), "application/rss+xml");
default: default:
throw new BadRequestException("Function Not Available"); throw new BadRequestException("Function Not Available");
@@ -78,7 +80,7 @@ namespace Prowlarr.Api.V1.Indexers
} }
[HttpGet("{id:int}/download")] [HttpGet("{id:int}/download")]
public object GetDownload(int id, string link, string file) public async Task<object> GetDownload(int id, string link, string file)
{ {
var indexerDef = _indexerFactory.Get(id); var indexerDef = _indexerFactory.Get(id);
var indexer = _indexerFactory.GetInstance(indexerDef); var indexer = _indexerFactory.GetInstance(indexerDef);
@@ -107,7 +109,7 @@ namespace Prowlarr.Api.V1.Indexers
} }
var downloadBytes = Array.Empty<byte>(); var downloadBytes = Array.Empty<byte>();
downloadBytes = _downloadService.DownloadReport(unprotectedlLink, id, source, file); downloadBytes = await _downloadService.DownloadReport(unprotectedlLink, id, source, file);
// handle magnet URLs // handle magnet URLs
if (downloadBytes.Length >= 7 if (downloadBytes.Length >= 7

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using NLog; using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
@@ -26,7 +27,7 @@ namespace Prowlarr.Api.V1.Search
} }
[HttpGet] [HttpGet]
public List<SearchResource> GetAll(string query, [FromQuery] List<int> indexerIds, [FromQuery] List<int> categories) public Task<List<SearchResource>> GetAll(string query, [FromQuery] List<int> indexerIds, [FromQuery] List<int> categories)
{ {
if (query.IsNotNullOrWhiteSpace()) if (query.IsNotNullOrWhiteSpace())
{ {
@@ -40,15 +41,16 @@ namespace Prowlarr.Api.V1.Search
} }
} }
return new List<SearchResource>(); return Task.FromResult(new List<SearchResource>());
} }
private List<SearchResource> GetSearchReleases(string query, List<int> indexerIds, List<int> categories) private async Task<List<SearchResource>> GetSearchReleases(string query, List<int> indexerIds, List<int> categories)
{ {
try try
{ {
var request = new NewznabRequest { q = query, source = "Prowlarr", t = "search", cat = string.Join(",", categories), server = Request.GetServerUrl() }; 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); return MapDecisions(decisions);
} }