Skip to content

Commit

Permalink
Added Client Priority with matching ui.
Browse files Browse the repository at this point in the history
  • Loading branch information
Taloth committed May 30, 2019
1 parent a3cbb41 commit f3435f9
Show file tree
Hide file tree
Showing 11 changed files with 141 additions and 3 deletions.
6 changes: 6 additions & 0 deletions frontend/src/Components/Form/TextInput.js
Expand Up @@ -128,6 +128,8 @@ class TextInput extends Component {
hasWarning,
hasButton,
step,
min,
max,
onBlur
} = this.props;

Expand All @@ -148,6 +150,8 @@ class TextInput extends Component {
name={name}
value={value}
step={step}
min={min}
max={max}
onChange={this.onChange}
onFocus={this.onFocus}
onBlur={onBlur}
Expand All @@ -171,6 +175,8 @@ TextInput.propTypes = {
hasWarning: PropTypes.bool,
hasButton: PropTypes.bool,
step: PropTypes.number,
min: PropTypes.number,
max: PropTypes.number,
onChange: PropTypes.func.isRequired,
onFocus: PropTypes.func,
onBlur: PropTypes.func,
Expand Down
Expand Up @@ -54,7 +54,8 @@ class DownloadClient extends Component {
const {
id,
name,
enable
enable,
priority
} = this.props;

return (
Expand All @@ -80,6 +81,16 @@ class DownloadClient extends Component {
Disabled
</Label>
}

{
priority > 1 &&
<Label
kind={kinds.DISABLED}
outline={true}
>
Prio: {priority}
</Label>
}
</div>

<EditDownloadClientModalConnector
Expand Down Expand Up @@ -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
};

Expand Down
Expand Up @@ -44,6 +44,7 @@ class EditDownloadClientModalContent extends Component {
implementationName,
name,
enable,
priority,
fields,
message
} = item;
Expand Down Expand Up @@ -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>
Expand Down
2 changes: 2 additions & 0 deletions src/NzbDrone.Api/DownloadClient/DownloadClientModule.cs
Expand Up @@ -15,6 +15,7 @@ protected override void MapToResource(DownloadClientResource resource, DownloadC

resource.Enable = definition.Enable;
resource.Protocol = definition.Protocol;
resource.Priority = definition.Priority;
}

protected override void MapToModel(DownloadClientDefinition definition, DownloadClientResource resource)
Expand All @@ -23,6 +24,7 @@ protected override void MapToModel(DownloadClientDefinition definition, Download

definition.Enable = resource.Enable;
definition.Protocol = resource.Protocol;
definition.Priority = resource.Priority;
}

protected override void Validate(DownloadClientDefinition definition, bool includeWarnings)
Expand Down
1 change: 1 addition & 0 deletions src/NzbDrone.Api/DownloadClient/DownloadClientResource.cs
Expand Up @@ -6,5 +6,6 @@ public class DownloadClientResource : ProviderResource
{
public bool Enable { get; set; }
public DownloadProtocol Protocol { get; set; }
public int Priority { get; set; }
}
}
48 changes: 46 additions & 2 deletions src/NzbDrone.Core.Test/Download/DownloadClientProviderFixture.cs
Expand Up @@ -35,13 +35,14 @@ public void SetUp()
.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);
Expand All @@ -51,13 +52,14 @@ private Mock<IDownloadClient> WithUsenetClient()
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);
Expand Down Expand Up @@ -181,5 +183,47 @@ public void should_not_skip_blocked_torrent_client_if_all_blocked()
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,45 @@
using System.Data;
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;

namespace NzbDrone.Core.Datastore.Migration
{
[Migration(132)]
public class add_download_client_priority : NzbDroneMigrationBase
{
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 FROM DownloadClients WHERE Enable = 1";

using (var reader = cmd.ExecuteReader())
{
int i = 1;
while (reader.Read())
{
var id = reader.GetInt32(0);

using (var updateCmd = conn.CreateCommand())
{
updateCmd.Transaction = tran;
updateCmd.CommandText = "UPDATE DownloadClients SET Priority = ? WHERE Id = ?";
updateCmd.AddParameter(i++);
updateCmd.AddParameter(id);

updateCmd.ExecuteNonQuery();
}
}
}
}
}
}
}
1 change: 1 addition & 0 deletions src/NzbDrone.Core/Download/DownloadClientDefinition.cs
Expand Up @@ -6,5 +6,6 @@ namespace NzbDrone.Core.Download
public class DownloadClientDefinition : ProviderDefinition
{
public DownloadProtocol Protocol { get; set; }
public int Priority { get; set; } = 1;
}
}
5 changes: 5 additions & 0 deletions src/NzbDrone.Core/Download/DownloadClientProvider.cs
Expand Up @@ -50,6 +50,11 @@ public IDownloadClient GetDownloadClient(DownloadProtocol downloadProtocol)
}
}

// 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();
Expand Down
1 change: 1 addition & 0 deletions src/NzbDrone.Core/NzbDrone.Core.csproj
Expand Up @@ -136,6 +136,7 @@
<Compile Include="Configuration\InvalidConfigFileException.cs" />
<Compile Include="Configuration\RescanAfterRefreshType.cs" />
<Compile Include="Configuration\ResetApiKeyCommand.cs" />
<Compile Include="Datastore\Migration\132_add_download_client_priority.cs" />
<Compile Include="Datastore\Migration\131_download_propers_config.cs" />
<Compile Include="Datastore\Migration\130_episode_last_searched_time.cs" />
<Compile Include="Datastore\Migration\129_add_relative_original_path_to_episode_file.cs" />
Expand Down
3 changes: 3 additions & 0 deletions src/Sonarr.Api.V3/DownloadClient/DownloadClientResource.cs
Expand Up @@ -7,6 +7,7 @@ public class DownloadClientResource : ProviderResource
{
public bool Enable { get; set; }
public DownloadProtocol Protocol { get; set; }
public int Priority { get; set; }
}

public class DownloadClientResourceMapper : ProviderResourceMapper<DownloadClientResource, DownloadClientDefinition>
Expand All @@ -19,6 +20,7 @@ public override DownloadClientResource ToResource(DownloadClientDefinition defin

resource.Enable = definition.Enable;
resource.Protocol = definition.Protocol;
resource.Priority = definition.Priority;

return resource;
}
Expand All @@ -31,6 +33,7 @@ public override DownloadClientDefinition ToModel(DownloadClientResource resource

definition.Enable = resource.Enable;
definition.Protocol = resource.Protocol;
definition.Priority = resource.Priority;

return definition;
}
Expand Down

0 comments on commit f3435f9

Please sign in to comment.