diff --git a/Wabbajack.App/Controls/ResourceView.axaml b/Wabbajack.App/Controls/ResourceView.axaml
new file mode 100644
index 00000000..7a3826a4
--- /dev/null
+++ b/Wabbajack.App/Controls/ResourceView.axaml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Wabbajack.App/Controls/ResourceView.axaml.cs b/Wabbajack.App/Controls/ResourceView.axaml.cs
new file mode 100644
index 00000000..e5cd57ae
--- /dev/null
+++ b/Wabbajack.App/Controls/ResourceView.axaml.cs
@@ -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, 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);
+
+ });
+ }
+
+}
\ No newline at end of file
diff --git a/Wabbajack.App/Controls/ResourceViewModel.cs b/Wabbajack.App/Controls/ResourceViewModel.cs
new file mode 100644
index 00000000..f46999f6
--- /dev/null
+++ b/Wabbajack.App/Controls/ResourceViewModel.cs
@@ -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();
+ }
+}
\ No newline at end of file
diff --git a/Wabbajack.App/Screens/SettingsView.axaml b/Wabbajack.App/Screens/SettingsView.axaml
index 52651b07..8a3f0167 100644
--- a/Wabbajack.App/Screens/SettingsView.axaml
+++ b/Wabbajack.App/Screens/SettingsView.axaml
@@ -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">
@@ -26,5 +27,25 @@
+
+
+
+ Resource Limits
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Wabbajack.App/Screens/SettingsView.axaml.cs b/Wabbajack.App/Screens/SettingsView.axaml.cs
index 385a2dd7..66257c94 100644
--- a/Wabbajack.App/Screens/SettingsView.axaml.cs
+++ b/Wabbajack.App/Screens/SettingsView.axaml.cs
@@ -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);
});
}
diff --git a/Wabbajack.App/Screens/SettingsViewModel.cs b/Wabbajack.App/Screens/SettingsViewModel.cs
index fc3dbb6d..7c4c8add 100644
--- a/Wabbajack.App/Screens/SettingsViewModel.cs
+++ b/Wabbajack.App/Screens/SettingsViewModel.cs
@@ -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 _fileSystemEvents = new();
-
- public SettingsViewModel(ILogger logger, Configuration configuration, NexusApiTokenProvider nexusProvider)
+ public readonly IEnumerable Resources;
+
+ public SettingsViewModel(ILogger logger, Configuration configuration, NexusApiTokenProvider nexusProvider, IEnumerable resources)
{
_logger = logger;
+ Resources = resources.Select(r => new ResourceViewModel(r)).ToArray();
Activator = new ViewModelActivator();
this.WhenActivated(disposables =>
diff --git a/Wabbajack.RateLimiter/IResource.cs b/Wabbajack.RateLimiter/IResource.cs
index 22475bd3..051e7106 100644
--- a/Wabbajack.RateLimiter/IResource.cs
+++ b/Wabbajack.RateLimiter/IResource.cs
@@ -7,7 +7,8 @@ namespace Wabbajack.RateLimiter
{
StatusReport StatusReport { get; }
string Name { get; }
-
+ int MaxTasks { get; set; }
+ long MaxThroughput { get; set; }
}
public interface IResource : IResource
{
diff --git a/Wabbajack.RateLimiter/Resource.cs b/Wabbajack.RateLimiter/Resource.cs
index e503ebc5..c9b9530d 100644
--- a/Wabbajack.RateLimiter/Resource.cs
+++ b/Wabbajack.RateLimiter/Resource.cs
@@ -16,8 +16,8 @@ namespace Wabbajack.RateLimiter
private readonly ConcurrentDictionary> _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 ?? "";
- _maxTasks = maxTasks ?? Environment.ProcessorCount;
- _maxThroughput = maxThroughput;
+ MaxTasks = maxTasks ?? Environment.ProcessorCount;
+ MaxThroughput = maxThroughput;
- _semaphore = new SemaphoreSlim(_maxTasks);
+ _semaphore = new SemaphoreSlim(MaxTasks);
_channel = Channel.CreateBounded(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);