Work on resource settings page

This commit is contained in:
Timothy Baldridge 2021-10-21 06:57:02 -06:00
parent 672a7a7c6d
commit c8b383cecc
8 changed files with 164 additions and 10 deletions

View File

@ -0,0 +1,16 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Wabbajack.App.Controls.ResourceView">
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="ResourceName" Width="100" HorizontalAlignment="Left" VerticalAlignment="Center"></TextBlock>
<Label Width="100" HorizontalContentAlignment="Right" VerticalAlignment="Center">Tasks:</Label>
<TextBox x:Name="MaxTasks" Width="20" HorizontalAlignment="Left" VerticalAlignment="Center"></TextBox>
<Label Width="100" HorizontalContentAlignment="Right" VerticalAlignment="Center">Throughput:</Label>
<TextBox x:Name="MaxThroughput" Width="20" HorizontalAlignment="Left" VerticalAlignment="Center"></TextBox>
<Label Width="100" HorizontalContentAlignment="Right" VerticalAlignment="Center">Status:</Label>
<TextBlock x:Name="CurrentThrougput" Width="50" HorizontalAlignment="Left" VerticalAlignment="Center"></TextBlock>
</StackPanel>
</UserControl>

View File

@ -0,0 +1,32 @@
using System.Reactive.Disposables;
using Avalonia.ReactiveUI;
using FluentFTP.Helpers;
using ReactiveUI;
namespace Wabbajack.App.Controls;
public partial class ResourceView : ReactiveUserControl<ResourceViewModel>, IActivatableView
{
public ResourceView()
{
InitializeComponent();
this.WhenActivated(disposables =>
{
this.OneWayBind(ViewModel, vm => vm.Name, view => view.ResourceName.Text)
.DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.MaxTasks, view => view.MaxTasks.Text)
.DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.MaxThroughput, view => view.MaxThroughput.Text)
.DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.CurrentThroughput, view => view.CurrentThrougput.Text,
val => val.FileSizeToString())
.DisposeWith(disposables);
});
}
}

View File

@ -0,0 +1,76 @@
using System;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Timers;using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using Wabbajack.App.ViewModels;
using Wabbajack.RateLimiter;
namespace Wabbajack.App.Controls;
public class ResourceViewModel : ViewModelBase, IActivatableViewModel, IDisposable
{
private readonly IResource _resource;
private readonly Timer _timer;
[Reactive]
public int MaxTasks { get; set; }
[Reactive]
public long MaxThroughput { get; set; }
[Reactive]
public long CurrentThroughput { get; set; }
[Reactive]
public string Name { get; set; }
public ResourceViewModel(IResource resource)
{
Activator = new ViewModelActivator();
_resource = resource;
_timer = new Timer(1.0);
Name = resource.Name;
this.WhenActivated(disposables =>
{
_timer.Elapsed += TimerElapsed;
_timer.Start();
Disposable.Create(() =>
{
_timer.Stop();
_timer.Elapsed -= TimerElapsed;
}).DisposeWith(disposables);
this.WhenAnyValue(vm => vm.MaxThroughput)
.Skip(1)
.Subscribe(v =>
{
_resource.MaxThroughput = MaxThroughput;
}).DisposeWith(disposables);
this.WhenAnyValue(vm => vm.MaxTasks)
.Skip(1)
.Subscribe(v =>
{
_resource.MaxTasks = MaxTasks;
}).DisposeWith(disposables);
});
}
private void TimerElapsed(object? sender, ElapsedEventArgs e)
{
MaxTasks = _resource.MaxTasks;
MaxThroughput = _resource.MaxThroughput;
CurrentThroughput = _resource.StatusReport.Transferred;
}
public void Dispose()
{
_timer.Dispose();
}
}

View File

@ -2,6 +2,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="clr-namespace:Wabbajack.App.Controls"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Wabbajack.App.Screens.SettingsView">
<WrapPanel Margin="40">
@ -26,5 +27,25 @@
</Grid>
</Border>
<Border x:Name="ResourcesBorder" Margin="5" BorderThickness="1">
<Grid RowDefinitions="Auto, Auto">
<TextBlock FontSize="20" Grid.ColumnSpan="4">Resource Limits</TextBlock>
<ItemsControl Grid.Row="1" x:Name="ResourceList">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"></StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<controls:ResourceView></controls:ResourceView>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Border>
</WrapPanel>
</UserControl>

View File

@ -16,6 +16,8 @@ namespace Wabbajack.App.Screens
.DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.NexusLogout, view => view.NexusLogOut)
.DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.Resources, view => view.ResourceList.Items)
.DisposeWith(disposables);
});
}

View File

@ -1,14 +1,18 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using Microsoft.Extensions.Logging;
using ReactiveUI;
using Wabbajack.App.Controls;
using Wabbajack.App.Messages;
using Wabbajack.App.ViewModels;
using Wabbajack.Paths;
using Wabbajack.Paths.IO;
using Wabbajack.RateLimiter;
using Wabbajack.Services.OSIntegrated.TokenProviders;
namespace Wabbajack.App.Screens
@ -23,10 +27,12 @@ namespace Wabbajack.App.Screens
public FileSystemWatcher Watcher { get; set; }
private readonly Subject<AbsolutePath> _fileSystemEvents = new();
public SettingsViewModel(ILogger<SettingsViewModel> logger, Configuration configuration, NexusApiTokenProvider nexusProvider)
public readonly IEnumerable<ResourceViewModel> Resources;
public SettingsViewModel(ILogger<SettingsViewModel> logger, Configuration configuration, NexusApiTokenProvider nexusProvider, IEnumerable<IResource> resources)
{
_logger = logger;
Resources = resources.Select(r => new ResourceViewModel(r)).ToArray();
Activator = new ViewModelActivator();
this.WhenActivated(disposables =>

View File

@ -7,7 +7,8 @@ namespace Wabbajack.RateLimiter
{
StatusReport StatusReport { get; }
string Name { get; }
int MaxTasks { get; set; }
long MaxThroughput { get; set; }
}
public interface IResource<T> : IResource
{

View File

@ -16,8 +16,8 @@ namespace Wabbajack.RateLimiter
private readonly ConcurrentDictionary<ulong, Job<T>> _tasks;
private ulong _nextId = 0;
private long _totalUsed = 0;
private readonly int _maxTasks;
private readonly long _maxThroughput;
public int MaxTasks { get; set; }
public long MaxThroughput { get; set; }
private readonly string _humanName;
public string Name => _humanName;
@ -26,10 +26,10 @@ namespace Wabbajack.RateLimiter
public Resource(string? humanName = null, int? maxTasks = 0, long maxThroughput = long.MaxValue)
{
_humanName = humanName ?? "<unknown>";
_maxTasks = maxTasks ?? Environment.ProcessorCount;
_maxThroughput = maxThroughput;
MaxTasks = maxTasks ?? Environment.ProcessorCount;
MaxThroughput = maxThroughput;
_semaphore = new SemaphoreSlim(_maxTasks);
_semaphore = new SemaphoreSlim(MaxTasks);
_channel = Channel.CreateBounded<PendingReport>(10);
_tasks = new ();
@ -44,14 +44,14 @@ namespace Wabbajack.RateLimiter
await foreach (var item in _channel.Reader.ReadAllAsync(token))
{
Interlocked.Add(ref _totalUsed, item.Size);
if (_maxThroughput == long.MaxValue)
if (MaxThroughput == long.MaxValue)
{
item.Result.TrySetResult();
sw.Restart();
continue;
}
var span = TimeSpan.FromSeconds((double)item.Size / _maxThroughput);
var span = TimeSpan.FromSeconds((double)item.Size / MaxThroughput);
await Task.Delay(span, token);