Support for primary and fallback download client

pull/6/head
Taloth Saldono 5 years ago committed by Qstick
parent 1ec5973520
commit a85c6c0a91

@ -54,7 +54,8 @@ class DownloadClient extends Component {
const {
id,
name,
enable
enable,
priority
} = this.props;
return (
@ -80,6 +81,16 @@ class DownloadClient extends Component {
Disabled
</Label>
}
{
priority > 1 &&
<Label
kind={kinds.DISABLED}
outline={true}
>
Priority: {priority}
</Label>
}
</div>
<EditDownloadClientModalConnector
@ -107,6 +118,7 @@ DownloadClient.propTypes = {
id: PropTypes.number.isRequired,
name: PropTypes.string.isRequired,
enable: PropTypes.bool.isRequired,
priority: PropTypes.number.isRequired,
onConfirmDeleteDownloadClient: PropTypes.func.isRequired
};

@ -44,6 +44,7 @@ class EditDownloadClientModalContent extends Component {
implementationName,
name,
enable,
priority,
fields,
message
} = item;
@ -115,6 +116,23 @@ class EditDownloadClientModalContent extends Component {
})
}
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>Client Priority</FormLabel>
<FormInputGroup
type={inputTypes.NUMBER}
name="priority"
helpText="Prioritize multiple Download Clients. Round-Robin is used for clients with the same priority."
min={1}
max={50}
{...priority}
onChange={onInputChange}
/>
</FormGroup>
</Form>
}
</ModalBody>

@ -7,6 +7,7 @@ namespace Lidarr.Api.V1.DownloadClient
{
public bool Enable { get; set; }
public DownloadProtocol Protocol { get; set; }
public int Priority { get; set; }
}
public class DownloadClientResourceMapper : ProviderResourceMapper<DownloadClientResource, DownloadClientDefinition>
@ -19,6 +20,7 @@ namespace Lidarr.Api.V1.DownloadClient
resource.Enable = definition.Enable;
resource.Protocol = definition.Protocol;
resource.Priority = definition.Priority;
return resource;
}
@ -31,6 +33,7 @@ namespace Lidarr.Api.V1.DownloadClient
definition.Enable = resource.Enable;
definition.Protocol = resource.Protocol;
definition.Priority = resource.Priority;
return definition;
}

@ -0,0 +1,178 @@
using System.Linq;
using FluentAssertions;
using Newtonsoft.Json.Linq;
using NUnit.Framework;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Datastore.Migration;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.Datastore.Migration
{
[TestFixture]
public class add_download_client_priorityFixture : MigrationTest<add_download_client_priority>
{
[Test]
public void should_set_prio_to_one()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("DownloadClients").Row(new
{
Enable = 1,
Name = "Deluge",
Implementation = "Deluge",
Settings = new DelugeSettings36
{
Host = "127.0.0.1",
MusicCategory = "abc",
UrlBase = "/my/"
}.ToJson(),
ConfigContract = "DelugeSettings"
});
});
var items = db.Query<DownloadClientDefinition036>("SELECT * FROM DownloadClients");
items.Should().HaveCount(1);
items.First().Priority.Should().Be(1);
}
[Test]
public void should_renumber_prio_for_enabled_clients()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("DownloadClients").Row(new
{
Enable = 1,
Name = "Deluge",
Implementation = "Deluge",
Settings = new DelugeSettings36
{
Host = "127.0.0.1",
MusicCategory = "abc",
UrlBase = "/my/"
}.ToJson(),
ConfigContract = "DelugeSettings"
}).Row(new
{
Enable = 1,
Name = "Deluge2",
Implementation = "Deluge",
Settings = new DelugeSettings36
{
Host = "127.0.0.1",
MusicCategory = "abc",
UrlBase = "/my/"
}.ToJson(),
ConfigContract = "DelugeSettings"
}).Row(new
{
Enable = 1,
Name = "sab",
Implementation = "Sabnzbd",
Settings = new SabnzbdSettings36
{
Host = "127.0.0.1",
MusicCategory = "abc"
}.ToJson(),
ConfigContract = "SabnzbdSettings"
});
});
var items = db.Query<DownloadClientDefinition036>("SELECT * FROM DownloadClients");
items.Should().HaveCount(3);
items[0].Priority.Should().Be(1);
items[1].Priority.Should().Be(2);
items[2].Priority.Should().Be(1);
}
[Test]
public void should_not_renumber_prio_for_disabled_clients()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("DownloadClients").Row(new
{
Enable = 0,
Name = "Deluge",
Implementation = "Deluge",
Settings = new DelugeSettings36
{
Host = "127.0.0.1",
MusicCategory = "abc",
UrlBase = "/my/"
}.ToJson(),
ConfigContract = "DelugeSettings"
}).Row(new
{
Enable = 0,
Name = "Deluge2",
Implementation = "Deluge",
Settings = new DelugeSettings36
{
Host = "127.0.0.1",
MusicCategory = "abc",
UrlBase = "/my/"
}.ToJson(),
ConfigContract = "DelugeSettings"
}).Row(new
{
Enable = 0,
Name = "sab",
Implementation = "Sabnzbd",
Settings = new SabnzbdSettings36
{
Host = "127.0.0.1",
MusicCategory = "abc"
}.ToJson(),
ConfigContract = "SabnzbdSettings"
});
});
var items = db.Query<DownloadClientDefinition036>("SELECT * FROM DownloadClients");
items.Should().HaveCount(3);
items[0].Priority.Should().Be(1);
items[1].Priority.Should().Be(1);
items[1].Priority.Should().Be(1);
}
}
public class DownloadClientDefinition036
{
public int Id { get; set; }
public bool Enable { get; set; }
public int Priority { get; set; }
public string Name { get; set; }
public string Implementation { get; set; }
public JObject Settings { get; set; }
public string ConfigContract { get; set; }
}
public class DelugeSettings36
{
public string Host { get; set; }
public int Port { get; set; }
public string UrlBase { get; set; }
public string Password { get; set; }
public string MusicCategory { get; set; }
public int RecentTvPriority { get; set; }
public int OlderTvPriority { get; set; }
public bool UseSsl { get; set; }
}
public class SabnzbdSettings36
{
public string Host { get; set; }
public int Port { get; set; }
public string ApiKey { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string MusicCategory { get; set; }
public int RecentTvPriority { get; set; }
public int OlderTvPriority { get; set; }
public bool UseSsl { get; set; }
}
}

@ -35,13 +35,14 @@ namespace NzbDrone.Core.Test.Download
.Returns(_blockedProviders);
}
private Mock<IDownloadClient> WithUsenetClient()
private Mock<IDownloadClient> WithUsenetClient(int priority = 0)
{
var mock = new Mock<IDownloadClient>(MockBehavior.Default);
mock.SetupGet(s => s.Definition)
.Returns(Builder<DownloadClientDefinition>
.CreateNew()
.With(v => v.Id = _nextId++)
.With(v => v.Priority = priority)
.Build());
_downloadClients.Add(mock.Object);
@ -51,13 +52,14 @@ namespace NzbDrone.Core.Test.Download
return mock;
}
private Mock<IDownloadClient> WithTorrentClient()
private Mock<IDownloadClient> WithTorrentClient(int priority = 0)
{
var mock = new Mock<IDownloadClient>(MockBehavior.Default);
mock.SetupGet(s => s.Definition)
.Returns(Builder<DownloadClientDefinition>
.CreateNew()
.With(v => v.Id = _nextId++)
.With(v => v.Priority = priority)
.Build());
_downloadClients.Add(mock.Object);
@ -181,5 +183,47 @@ namespace NzbDrone.Core.Test.Download
client3.Definition.Id.Should().Be(4);
client4.Definition.Id.Should().Be(2);
}
[Test]
public void should_skip_secondary_prio_torrent_client()
{
WithUsenetClient();
WithTorrentClient(2);
WithTorrentClient();
WithTorrentClient();
var client1 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client2 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client3 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client4 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client5 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
client1.Definition.Id.Should().Be(3);
client2.Definition.Id.Should().Be(4);
client3.Definition.Id.Should().Be(3);
client4.Definition.Id.Should().Be(4);
}
[Test]
public void should_not_skip_secondary_prio_torrent_client_if_primary_blocked()
{
WithUsenetClient();
WithTorrentClient(2);
WithTorrentClient(2);
WithTorrentClient();
GivenBlockedClient(4);
var client1 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client2 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client3 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client4 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client5 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
client1.Definition.Id.Should().Be(2);
client2.Definition.Id.Should().Be(3);
client3.Definition.Id.Should().Be(2);
client4.Definition.Id.Should().Be(3);
}
}
}

@ -0,0 +1,56 @@
using System.Collections.Generic;
using System.Data;
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(036)]
public class add_download_client_priority : NzbDroneMigrationBase
{
// Need snapshot in time without having to instantiate.
private static HashSet<string> _usenetImplementations = new HashSet<string>
{
"Sabnzbd", "NzbGet", "NzbVortex", "UsenetBlackhole", "UsenetDownloadStation"
};
protected override void MainDbUpgrade()
{
Alter.Table("DownloadClients").AddColumn("Priority").AsInt32().WithDefaultValue(1);
Execute.WithConnection(InitPriorityForBackwardCompatibility);
}
private void InitPriorityForBackwardCompatibility(IDbConnection conn, IDbTransaction tran)
{
using (var cmd = conn.CreateCommand())
{
cmd.Transaction = tran;
cmd.CommandText = "SELECT Id, Implementation FROM DownloadClients WHERE Enable = 1";
using (var reader = cmd.ExecuteReader())
{
int nextUsenet = 1;
int nextTorrent = 1;
while (reader.Read())
{
var id = reader.GetInt32(0);
var implName = reader.GetString(1);
var isUsenet = _usenetImplementations.Contains(implName);
using (var updateCmd = conn.CreateCommand())
{
updateCmd.Transaction = tran;
updateCmd.CommandText = "UPDATE DownloadClients SET Priority = ? WHERE Id = ?";
updateCmd.AddParameter(isUsenet ? nextUsenet++ : nextTorrent++);
updateCmd.AddParameter(id);
updateCmd.ExecuteNonQuery();
}
}
}
}
}
}
}

@ -6,5 +6,6 @@ namespace NzbDrone.Core.Download
public class DownloadClientDefinition : ProviderDefinition
{
public DownloadProtocol Protocol { get; set; }
public int Priority { get; set; } = 1;
}
}

@ -50,6 +50,11 @@ namespace NzbDrone.Core.Download
}
}
// Use the first priority clients first
availableProviders = availableProviders.GroupBy(v => (v.Definition as DownloadClientDefinition).Priority)
.OrderBy(v => v.Key)
.First().OrderBy(v => v.Definition.Id).ToList();
var lastId = _lastUsedDownloadClient.Find(downloadProtocol.ToString());
var provider = availableProviders.FirstOrDefault(v => v.Definition.Id > lastId) ?? availableProviders.First();

Loading…
Cancel
Save