mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Merge pull request #1719 from wabbajack-tools/fix-login-logout-buttons
Fix login logout buttons
This commit is contained in:
commit
9ea30334f5
@ -9,6 +9,7 @@
|
|||||||
<Application.Styles>
|
<Application.Styles>
|
||||||
<StyleInclude Source="avares://Material.Icons.Avalonia/App.xaml" />
|
<StyleInclude Source="avares://Material.Icons.Avalonia/App.xaml" />
|
||||||
<FluentTheme Mode="Dark" />
|
<FluentTheme Mode="Dark" />
|
||||||
|
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml"/>
|
||||||
<StyleInclude Source="avares://Wabbajack.App/Assets/Wabbajack.axaml" />
|
<StyleInclude Source="avares://Wabbajack.App/Assets/Wabbajack.axaml" />
|
||||||
<Style Selector="Button:not(:pointerover) /template/ ContentPresenter">
|
<Style Selector="Button:not(:pointerover) /template/ ContentPresenter">
|
||||||
<Setter Property="Background" Value="Transparent" />
|
<Setter Property="Background" Value="Transparent" />
|
||||||
|
@ -41,6 +41,12 @@
|
|||||||
<Setter Property="CornerRadius" Value="4"></Setter>
|
<Setter Property="CornerRadius" Value="4"></Setter>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="Border.StandardBorder">
|
||||||
|
<Setter Property="BorderThickness" Value="2"></Setter>
|
||||||
|
<Setter Property="BorderBrush" Value="DarkGray"></Setter>
|
||||||
|
<Setter Property="CornerRadius" Value="4"></Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
<Style Selector="Border.Settings Grid">
|
<Style Selector="Border.Settings Grid">
|
||||||
<Setter Property="Margin" Value="4"></Setter>
|
<Setter Property="Margin" Value="4"></Setter>
|
||||||
</Style>
|
</Style>
|
||||||
|
@ -21,6 +21,7 @@ using Wabbajack.DTOs.JsonConverters;
|
|||||||
using Wabbajack.Paths;
|
using Wabbajack.Paths;
|
||||||
using Wabbajack.Paths.IO;
|
using Wabbajack.Paths.IO;
|
||||||
using Wabbajack.RateLimiter;
|
using Wabbajack.RateLimiter;
|
||||||
|
using Wabbajack.Services.OSIntegrated;
|
||||||
using Wabbajack.VFS;
|
using Wabbajack.VFS;
|
||||||
|
|
||||||
namespace Wabbajack.App.Controls;
|
namespace Wabbajack.App.Controls;
|
||||||
|
@ -4,13 +4,10 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Wabbajack.App.Controls.ResourceView">
|
x:Class="Wabbajack.App.Controls.ResourceView">
|
||||||
<StackPanel Orientation="Horizontal">
|
<Grid RowDefinitions="Auto" ColumnDefinitions="140, 100, 140, 100">
|
||||||
<TextBlock x:Name="ResourceName" Width="100" HorizontalAlignment="Left" VerticalAlignment="Center" />
|
<TextBlock Grid.Column="0" VerticalAlignment="Center" Margin="4, 0" x:Name="ResourceName"></TextBlock>
|
||||||
<Label Width="100" HorizontalContentAlignment="Right" VerticalAlignment="Center">Tasks:</Label>
|
<TextBox Grid.Column="1" Text="32" Margin="4, 0" x:Name="MaxTasks"></TextBox>
|
||||||
<TextBox x:Name="MaxTasks" Width="20" HorizontalAlignment="Left" VerticalAlignment="Center" />
|
<TextBox Grid.Column="2" Margin="4, 0" x:Name="MaxThroughput"></TextBox>
|
||||||
<Label Width="100" HorizontalContentAlignment="Right" VerticalAlignment="Center">Throughput:</Label>
|
<TextBlock Grid.Column="3" Text="42GB" VerticalAlignment="Center" Margin="4, 0" x:Name="CurrentThroughput"></TextBlock>
|
||||||
<TextBox x:Name="MaxThroughput" Width="20" HorizontalAlignment="Left" VerticalAlignment="Center" />
|
</Grid>
|
||||||
<Label Width="100" HorizontalContentAlignment="Right" VerticalAlignment="Center">Status:</Label>
|
|
||||||
<TextBlock x:Name="CurrentThrougput" Width="50" HorizontalAlignment="Left" VerticalAlignment="Center" />
|
|
||||||
</StackPanel>
|
|
||||||
</UserControl>
|
</UserControl>
|
@ -17,10 +17,21 @@ public partial class ResourceView : ReactiveUserControl<ResourceViewModel>, IAct
|
|||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.MaxTasks, view => view.MaxTasks.Text)
|
this.Bind(ViewModel, vm => vm.MaxTasks, view => view.MaxTasks.Text)
|
||||||
.DisposeWith(disposables);
|
.DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.MaxThroughput, view => view.MaxThroughput.Text)
|
|
||||||
|
this.Bind(ViewModel, vm => vm.MaxThroughput, view => view.MaxThroughput.Text,
|
||||||
|
l => l is 0 or long.MaxValue ? "∞" : (l / 1024 / 1024).ToString(),
|
||||||
|
v =>
|
||||||
|
{
|
||||||
|
v = v.Trim();
|
||||||
|
if (v is "0" or "∞" || v == long.MaxValue.ToString())
|
||||||
|
{
|
||||||
|
return long.MaxValue;
|
||||||
|
}
|
||||||
|
return long.TryParse(v, out var l) ? l * 1024 * 1024 : long.MaxValue;
|
||||||
|
})
|
||||||
.DisposeWith(disposables);
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
this.OneWayBind(ViewModel, vm => vm.CurrentThroughput, view => view.CurrentThrougput.Text,
|
this.OneWayBind(ViewModel, vm => vm.CurrentThroughput, view => view.CurrentThroughput.Text,
|
||||||
val => val.FileSizeToString())
|
val => val.FileSizeToString())
|
||||||
.DisposeWith(disposables);
|
.DisposeWith(disposables);
|
||||||
});
|
});
|
||||||
|
@ -2,9 +2,11 @@ using System;
|
|||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
|
using Avalonia.Threading;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using ReactiveUI.Fody.Helpers;
|
using ReactiveUI.Fody.Helpers;
|
||||||
using Wabbajack.App.ViewModels;
|
using Wabbajack.App.ViewModels;
|
||||||
|
using Wabbajack.Common;
|
||||||
using Wabbajack.RateLimiter;
|
using Wabbajack.RateLimiter;
|
||||||
|
|
||||||
namespace Wabbajack.App.Controls;
|
namespace Wabbajack.App.Controls;
|
||||||
@ -18,7 +20,7 @@ public class ResourceViewModel : ViewModelBase, IActivatableViewModel, IDisposab
|
|||||||
{
|
{
|
||||||
Activator = new ViewModelActivator();
|
Activator = new ViewModelActivator();
|
||||||
_resource = resource;
|
_resource = resource;
|
||||||
_timer = new Timer(1.0);
|
_timer = new Timer(250);
|
||||||
|
|
||||||
Name = resource.Name;
|
Name = resource.Name;
|
||||||
|
|
||||||
@ -33,13 +35,8 @@ public class ResourceViewModel : ViewModelBase, IActivatableViewModel, IDisposab
|
|||||||
_timer.Elapsed -= TimerElapsed;
|
_timer.Elapsed -= TimerElapsed;
|
||||||
}).DisposeWith(disposables);
|
}).DisposeWith(disposables);
|
||||||
|
|
||||||
this.WhenAnyValue(vm => vm.MaxThroughput)
|
MaxTasks = _resource.MaxTasks;
|
||||||
.Skip(1)
|
MaxThroughput = _resource.MaxThroughput;
|
||||||
.Subscribe(v => { _resource.MaxThroughput = MaxThroughput; }).DisposeWith(disposables);
|
|
||||||
|
|
||||||
this.WhenAnyValue(vm => vm.MaxTasks)
|
|
||||||
.Skip(1)
|
|
||||||
.Subscribe(v => { _resource.MaxTasks = MaxTasks; }).DisposeWith(disposables);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,6 +48,8 @@ public class ResourceViewModel : ViewModelBase, IActivatableViewModel, IDisposab
|
|||||||
|
|
||||||
[Reactive] public string Name { get; set; }
|
[Reactive] public string Name { get; set; }
|
||||||
|
|
||||||
|
[Reactive] public string ThroughputHumanFriendly { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
@ -59,8 +58,9 @@ public class ResourceViewModel : ViewModelBase, IActivatableViewModel, IDisposab
|
|||||||
|
|
||||||
private void TimerElapsed(object? sender, ElapsedEventArgs e)
|
private void TimerElapsed(object? sender, ElapsedEventArgs e)
|
||||||
{
|
{
|
||||||
MaxTasks = _resource.MaxTasks;
|
Dispatcher.UIThread.Post(() => {
|
||||||
MaxThroughput = _resource.MaxThroughput;
|
CurrentThroughput = _resource.StatusReport.Transferred;
|
||||||
CurrentThroughput = _resource.StatusReport.Transferred;
|
ThroughputHumanFriendly = _resource.StatusReport.Transferred.ToFileSizeString();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -12,6 +12,7 @@ using Wabbajack.Hashing.xxHash64;
|
|||||||
using Wabbajack.Paths;
|
using Wabbajack.Paths;
|
||||||
using Wabbajack.Paths.IO;
|
using Wabbajack.Paths.IO;
|
||||||
using Wabbajack.RateLimiter;
|
using Wabbajack.RateLimiter;
|
||||||
|
using Wabbajack.Services.OSIntegrated;
|
||||||
using Wabbajack.VFS;
|
using Wabbajack.VFS;
|
||||||
|
|
||||||
namespace Wabbajack.App.Models;
|
namespace Wabbajack.App.Models;
|
||||||
|
@ -31,7 +31,7 @@ namespace Wabbajack.App.Screens;
|
|||||||
|
|
||||||
public class BrowseViewModel : ViewModelBase, IActivatableViewModel
|
public class BrowseViewModel : ViewModelBase, IActivatableViewModel
|
||||||
{
|
{
|
||||||
private readonly Configuration _configuration;
|
private readonly Wabbajack.Services.OSIntegrated.Configuration _configuration;
|
||||||
private readonly DownloadDispatcher _dispatcher;
|
private readonly DownloadDispatcher _dispatcher;
|
||||||
private readonly IResource<DownloadDispatcher> _dispatcherLimiter;
|
private readonly IResource<DownloadDispatcher> _dispatcherLimiter;
|
||||||
private readonly DTOSerializer _dtos;
|
private readonly DTOSerializer _dtos;
|
||||||
@ -54,7 +54,7 @@ public class BrowseViewModel : ViewModelBase, IActivatableViewModel
|
|||||||
IResource<HttpClient> limiter, FileHashCache hashCache,
|
IResource<HttpClient> limiter, FileHashCache hashCache,
|
||||||
IResource<DownloadDispatcher> dispatcherLimiter, DownloadDispatcher dispatcher, GameLocator gameLocator,
|
IResource<DownloadDispatcher> dispatcherLimiter, DownloadDispatcher dispatcher, GameLocator gameLocator,
|
||||||
ImageCache imageCache,
|
ImageCache imageCache,
|
||||||
DTOSerializer dtos, Configuration configuration)
|
DTOSerializer dtos, Wabbajack.Services.OSIntegrated.Configuration configuration)
|
||||||
{
|
{
|
||||||
LoadingLock = new LoadingLock();
|
LoadingLock = new LoadingLock();
|
||||||
Activator = new ViewModelActivator();
|
Activator = new ViewModelActivator();
|
||||||
|
@ -18,6 +18,7 @@ using Wabbajack.DTOs.JsonConverters;
|
|||||||
using Wabbajack.Installer;
|
using Wabbajack.Installer;
|
||||||
using Wabbajack.Paths;
|
using Wabbajack.Paths;
|
||||||
using Wabbajack.Paths.IO;
|
using Wabbajack.Paths.IO;
|
||||||
|
using Wabbajack.Services.OSIntegrated;
|
||||||
using Consts = Wabbajack.Compiler.Consts;
|
using Consts = Wabbajack.Compiler.Consts;
|
||||||
|
|
||||||
namespace Wabbajack.App.Screens;
|
namespace Wabbajack.App.Screens;
|
||||||
|
@ -24,9 +24,9 @@
|
|||||||
<TextBox Grid.Column="1" Grid.Row="1" IsEnabled="False" Height="20" x:Name="InstallPath" />
|
<TextBox Grid.Column="1" Grid.Row="1" IsEnabled="False" Height="20" x:Name="InstallPath" />
|
||||||
|
|
||||||
<Grid Grid.Column="1" Grid.Row="3" Grid.ColumnDefinitions="*, *, *" HorizontalAlignment="Center">
|
<Grid Grid.Column="1" Grid.Row="3" Grid.ColumnDefinitions="*, *, *" HorizontalAlignment="Center">
|
||||||
<Button Grid.Column="0" x:Name="WebsiteButton">Website</Button>
|
<Button Grid.Column="0" x:Name="WebsiteButton" Click="ShowWebsite">Website</Button>
|
||||||
<Button Grid.Column="1" x:Name="ReadmeButton">Readme</Button>
|
<Button Grid.Column="1" x:Name="ReadmeButton" Click="ShowReadme">Readme</Button>
|
||||||
<Button Grid.Column="2" x:Name="LocalFilesButton">Local Files</Button>
|
<Button Grid.Column="2" x:Name="LocalFilesButton" Click="ShowLocalFiles">Local Files</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<controls:LargeIconButton x:Name="PlayGame" Margin="40, 0, 0, 0" Grid.Row="0" Grid.Column="2"
|
<controls:LargeIconButton x:Name="PlayGame" Margin="40, 0, 0, 0" Grid.Row="0" Grid.Column="2"
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
|
using System;
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
using Wabbajack.App.Utilities;
|
||||||
using Wabbajack.App.Views;
|
using Wabbajack.App.Views;
|
||||||
|
using Wabbajack.Installer;
|
||||||
|
|
||||||
namespace Wabbajack.App.Screens;
|
namespace Wabbajack.App.Screens;
|
||||||
|
|
||||||
@ -25,4 +29,19 @@ public partial class LauncherView : ScreenBase<LauncherViewModel>
|
|||||||
.DisposeWith(disposables);
|
.DisposeWith(disposables);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ShowWebsite(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
OSUtil.OpenWebsite(ViewModel!.Setting!.StrippedModListData?.Website!);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowReadme(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
OSUtil.OpenWebsite(new Uri(ViewModel!.Setting!.StrippedModListData?.Readme!));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowLocalFiles(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
OSUtil.OpenFolder(ViewModel!.Setting!.Install);
|
||||||
|
}
|
||||||
}
|
}
|
@ -34,22 +34,28 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<Border x:Name="ResourcesBorder" Margin="5" BorderThickness="1" Classes="Settings">
|
<Border x:Name="ResourcesBorder" Margin="5" BorderThickness="1" Classes="ResourceSettings StandardBorder">
|
||||||
<Grid RowDefinitions="Auto, Auto">
|
<Grid RowDefinitions="Auto, Auto, Auto, Auto" ColumnDefinitions="140, 100, 140, 100">
|
||||||
<TextBlock FontSize="20" Grid.ColumnSpan="4">Resource Limits</TextBlock>
|
<TextBlock Grid.Row="0" Text="Resources" FontSize="20" Grid.ColumnSpan="4" Margin="4"></TextBlock>
|
||||||
|
<TextBlock Grid.Row="1" Grid.Column="0" Text="Name" FontWeight="Bold" Margin="4, 4"></TextBlock>
|
||||||
|
<TextBlock Grid.Row="1" Grid.Column="1" Text="Max Tasks" FontWeight="Bold" Margin="4, 4"></TextBlock>
|
||||||
|
<TextBlock Grid.Row="1" Grid.Column="2" Text="Max Throughput" FontWeight="Bold" Margin="4, 4"></TextBlock>
|
||||||
|
<TextBlock Grid.Row="1" Grid.Column="3" Text="Transferred" FontWeight="Bold" Margin="4, 4"></TextBlock>
|
||||||
|
|
||||||
<ItemsControl Grid.Row="1" x:Name="ResourceList">
|
<ItemsRepeater Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="4" x:Name="ResourcesList" Margin="0, 4">
|
||||||
<ItemsControl.ItemsPanel>
|
<ItemsRepeater.Layout>
|
||||||
<ItemsPanelTemplate>
|
<StackLayout></StackLayout>
|
||||||
<StackPanel Orientation="Vertical" />
|
</ItemsRepeater.Layout>
|
||||||
</ItemsPanelTemplate>
|
<ItemsRepeater.ItemTemplate>
|
||||||
</ItemsControl.ItemsPanel>
|
|
||||||
<ItemsControl.ItemTemplate>
|
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<controls:ResourceView />
|
<controls:ResourceView></controls:ResourceView>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsControl.ItemTemplate>
|
</ItemsRepeater.ItemTemplate>
|
||||||
</ItemsControl>
|
</ItemsRepeater>
|
||||||
|
|
||||||
|
<Button Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="4" HorizontalAlignment="Stretch" Margin="4" Click="SaveSettingsAndRestart">
|
||||||
|
<TextBlock Text="Save Settings and Restart Wabbajack" HorizontalAlignment="Center" TextAlignment="Center"></TextBlock>
|
||||||
|
</Button>
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using Wabbajack.App.Views;
|
using Wabbajack.App.Views;
|
||||||
|
using Wabbajack.Common;
|
||||||
|
|
||||||
namespace Wabbajack.App.Screens;
|
namespace Wabbajack.App.Screens;
|
||||||
|
|
||||||
@ -15,8 +17,27 @@ public partial class SettingsView : ScreenBase<SettingsViewModel>
|
|||||||
.DisposeWith(disposables);
|
.DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.NexusLogout, view => view.NexusLogOut)
|
this.BindCommand(ViewModel, vm => vm.NexusLogout, view => view.NexusLogOut)
|
||||||
.DisposeWith(disposables);
|
.DisposeWith(disposables);
|
||||||
this.OneWayBind(ViewModel, vm => vm.Resources, view => view.ResourceList.Items)
|
|
||||||
|
this.BindCommand(ViewModel, vm => vm.LoversLabLogin, view => view.LoversLabLogIn)
|
||||||
.DisposeWith(disposables);
|
.DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.LoversLabLogout, view => view.LoversLabLogOut)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
|
|
||||||
|
this.BindCommand(ViewModel, vm => vm.VectorPlexusLogin, view => view.VectorPlexusLogIn)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.VectorPlexusLogout, view => view.VectorPlexusLogOut)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
|
|
||||||
|
this.OneWayBind(ViewModel, vm => vm.Resources, view => view.ResourcesList.Items)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SaveSettingsAndRestart(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
ViewModel!.SaveResourceSettingsAndRestart().FireAndForget();
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,18 +1,25 @@
|
|||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reactive;
|
using System.Reactive;
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using System.Reactive.Subjects;
|
using System.Reactive.Subjects;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using Wabbajack.App.Controls;
|
using Wabbajack.App.Controls;
|
||||||
using Wabbajack.App.Messages;
|
using Wabbajack.App.Messages;
|
||||||
|
using Wabbajack.App.Models;
|
||||||
using Wabbajack.App.ViewModels;
|
using Wabbajack.App.ViewModels;
|
||||||
|
using Wabbajack.Common;
|
||||||
using Wabbajack.Paths;
|
using Wabbajack.Paths;
|
||||||
using Wabbajack.Paths.IO;
|
using Wabbajack.Paths.IO;
|
||||||
using Wabbajack.RateLimiter;
|
using Wabbajack.RateLimiter;
|
||||||
|
using Wabbajack.Services.OSIntegrated;
|
||||||
using Wabbajack.Services.OSIntegrated.TokenProviders;
|
using Wabbajack.Services.OSIntegrated.TokenProviders;
|
||||||
|
|
||||||
namespace Wabbajack.App.Screens;
|
namespace Wabbajack.App.Screens;
|
||||||
@ -22,16 +29,26 @@ public class SettingsViewModel : ViewModelBase
|
|||||||
private readonly Subject<AbsolutePath> _fileSystemEvents = new();
|
private readonly Subject<AbsolutePath> _fileSystemEvents = new();
|
||||||
private readonly ILogger<SettingsViewModel> _logger;
|
private readonly ILogger<SettingsViewModel> _logger;
|
||||||
public readonly IEnumerable<ResourceViewModel> Resources;
|
public readonly IEnumerable<ResourceViewModel> Resources;
|
||||||
|
private readonly ResourceSettingsManager _resourceSettingsManager;
|
||||||
|
|
||||||
public SettingsViewModel(ILogger<SettingsViewModel> logger, Configuration configuration,
|
public SettingsViewModel(ILogger<SettingsViewModel> logger, Configuration configuration,
|
||||||
NexusApiTokenProvider nexusProvider, IEnumerable<IResource> resources)
|
ResourceSettingsManager resourceSettingsManager,
|
||||||
|
NexusApiTokenProvider nexusProvider, IEnumerable<IResource> resources, LoversLabTokenProvider llProvider, VectorPlexusTokenProvider vpProvider)
|
||||||
{
|
{
|
||||||
|
_resourceSettingsManager = resourceSettingsManager;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
Resources = resources.Select(r => new ResourceViewModel(r)).ToArray();
|
Resources = resources.Select(r => new ResourceViewModel(r))
|
||||||
|
.OrderBy(o => o.Name)
|
||||||
|
.ToArray();
|
||||||
Activator = new ViewModelActivator();
|
Activator = new ViewModelActivator();
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
foreach (var resource in Resources)
|
||||||
|
{
|
||||||
|
resource.Activator.Activate().DisposeWith(disposables);
|
||||||
|
}
|
||||||
|
|
||||||
configuration.EncryptedDataLocation.CreateDirectory();
|
configuration.EncryptedDataLocation.CreateDirectory();
|
||||||
Watcher = new FileSystemWatcher(configuration.EncryptedDataLocation.ToString());
|
Watcher = new FileSystemWatcher(configuration.EncryptedDataLocation.ToString());
|
||||||
Watcher.DisposeWith(disposables);
|
Watcher.DisposeWith(disposables);
|
||||||
@ -50,16 +67,61 @@ public class SettingsViewModel : ViewModelBase
|
|||||||
ReactiveCommand.Create(() => { MessageBus.Current.SendMessage(new NavigateTo(typeof(NexusLoginViewModel))); },
|
ReactiveCommand.Create(() => { MessageBus.Current.SendMessage(new NavigateTo(typeof(NexusLoginViewModel))); },
|
||||||
haveNexusToken.Select(x => !x));
|
haveNexusToken.Select(x => !x));
|
||||||
NexusLogout = ReactiveCommand.Create(nexusProvider.DeleteToken, haveNexusToken.Select(x => x));
|
NexusLogout = ReactiveCommand.Create(nexusProvider.DeleteToken, haveNexusToken.Select(x => x));
|
||||||
|
|
||||||
|
var haveLLToken = _fileSystemEvents
|
||||||
|
.StartWith(AbsolutePath.Empty)
|
||||||
|
.Select(_ => llProvider.HaveToken());
|
||||||
|
|
||||||
|
LoversLabLogin =
|
||||||
|
ReactiveCommand.Create(() => { MessageBus.Current.SendMessage(new NavigateTo(typeof(LoversLabOAuthLoginViewModel))); },
|
||||||
|
haveLLToken.Select(x => !x));
|
||||||
|
LoversLabLogout = ReactiveCommand.Create(llProvider.DeleteToken, haveLLToken.Select(x => x));
|
||||||
|
|
||||||
|
var haveVectorPlexusToken = _fileSystemEvents
|
||||||
|
.StartWith(AbsolutePath.Empty)
|
||||||
|
.Select(_ => vpProvider.HaveToken());
|
||||||
|
|
||||||
|
VectorPlexusLogin =
|
||||||
|
ReactiveCommand.Create(() => { MessageBus.Current.SendMessage(new NavigateTo(typeof(VectorPlexusOAuthLoginViewModel))); },
|
||||||
|
haveVectorPlexusToken.Select(x => !x));
|
||||||
|
VectorPlexusLogout = ReactiveCommand.Create(vpProvider.DeleteToken, haveVectorPlexusToken.Select(x => x));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReactiveCommand<Unit, Unit> NexusLogin { get; set; }
|
public ReactiveCommand<Unit, Unit> NexusLogin { get; set; }
|
||||||
public ReactiveCommand<Unit, Unit> NexusLogout { get; set; }
|
public ReactiveCommand<Unit, Unit> NexusLogout { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public ReactiveCommand<Unit, Unit> LoversLabLogin { get; set; }
|
||||||
|
public ReactiveCommand<Unit, Unit> LoversLabLogout { get; set; }
|
||||||
|
|
||||||
|
public ReactiveCommand<Unit, Unit> VectorPlexusLogin { get; set; }
|
||||||
|
public ReactiveCommand<Unit, Unit> VectorPlexusLogout { get; set; }
|
||||||
|
|
||||||
public FileSystemWatcher Watcher { get; set; }
|
public FileSystemWatcher Watcher { get; set; }
|
||||||
|
|
||||||
private void Pulse(object sender, FileSystemEventArgs e)
|
private void Pulse(object sender, FileSystemEventArgs e)
|
||||||
{
|
{
|
||||||
_fileSystemEvents.OnNext(e.FullPath?.ToAbsolutePath() ?? default);
|
_fileSystemEvents.OnNext(e.FullPath?.ToAbsolutePath() ?? default);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task SaveResourceSettingsAndRestart()
|
||||||
|
{
|
||||||
|
await _resourceSettingsManager.SaveSettings(Resources.ToDictionary(r => r.Name, r =>
|
||||||
|
new ResourceSettingsManager.ResourceSetting()
|
||||||
|
{
|
||||||
|
MaxTasks = r.MaxTasks,
|
||||||
|
MaxThroughput = r.MaxThroughput
|
||||||
|
}));
|
||||||
|
|
||||||
|
var proc = new Process()
|
||||||
|
{
|
||||||
|
StartInfo = new ProcessStartInfo()
|
||||||
|
{
|
||||||
|
FileName = Process.GetCurrentProcess().MainModule!.FileName
|
||||||
|
}
|
||||||
|
};
|
||||||
|
proc.Start();
|
||||||
|
Environment.Exit(0);
|
||||||
|
}
|
||||||
}
|
}
|
@ -198,9 +198,16 @@ public class StandardInstallationViewModel : ViewModelBase
|
|||||||
_logger.LogInformation("Installer created, starting the installation process");
|
_logger.LogInformation("Installer created, starting the installation process");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(_config.ModList.Readme))
|
||||||
|
OSUtil.OpenWebsite(new Uri(_config.ModList.Readme));
|
||||||
|
|
||||||
var result = await Task.Run(async () => await _installer.Begin(CancellationToken.None));
|
var result = await Task.Run(async () => await _installer.Begin(CancellationToken.None));
|
||||||
if (!result) throw new Exception("Installation failed");
|
if (!result) throw new Exception("Installation failed");
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(_config.ModList.Readme))
|
||||||
|
OSUtil.OpenWebsite(new Uri(_config.ModList.Readme));
|
||||||
|
|
||||||
if (result) await SaveConfigAndContinue(_config);
|
if (result) await SaveConfigAndContinue(_config);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -219,13 +226,15 @@ public class StandardInstallationViewModel : ViewModelBase
|
|||||||
await image.CopyToAsync(os);
|
await image.CopyToAsync(os);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
await _installStateManager.SetLastState(new InstallationConfigurationSetting
|
await _installStateManager.SetLastState(new InstallationConfigurationSetting
|
||||||
{
|
{
|
||||||
Downloads = config.Downloads,
|
Downloads = config.Downloads,
|
||||||
Install = config.Install,
|
Install = config.Install,
|
||||||
Metadata = config.Metadata,
|
Metadata = config.Metadata,
|
||||||
ModList = config.ModlistArchive,
|
ModList = config.ModlistArchive,
|
||||||
Image = path
|
Image = path,
|
||||||
|
StrippedModListData = config.ModList.Strip()
|
||||||
});
|
});
|
||||||
|
|
||||||
MessageBus.Current.SendMessage(new ConfigureLauncher(config.Install));
|
MessageBus.Current.SendMessage(new ConfigureLauncher(config.Install));
|
||||||
|
@ -93,17 +93,6 @@ public static class ServiceExtensions
|
|||||||
CachePath = KnownFolders.WabbajackAppLocal.Combine("cef_cache").ToString()
|
CachePath = KnownFolders.WabbajackAppLocal.Combine("cef_cache").ToString()
|
||||||
});
|
});
|
||||||
|
|
||||||
services.AddSingleton(s => new Configuration
|
|
||||||
{
|
|
||||||
EncryptedDataLocation = KnownFolders.WabbajackAppLocal.Combine("encrypted"),
|
|
||||||
ModListsDownloadLocation = KnownFolders.EntryPoint.Combine("downloaded_mod_lists"),
|
|
||||||
SavedSettingsLocation = KnownFolders.WabbajackAppLocal.Combine("saved_settings"),
|
|
||||||
LogLocation = KnownFolders.EntryPoint.Combine("logs"),
|
|
||||||
ImageCacheLocation = KnownFolders.WabbajackAppLocal.Combine("image_cache")
|
|
||||||
});
|
|
||||||
|
|
||||||
services.AddSingleton<SettingsManager>();
|
|
||||||
|
|
||||||
services.AddSingleton(s =>
|
services.AddSingleton(s =>
|
||||||
{
|
{
|
||||||
App.FrameworkInitialized += App_FrameworkInitialized;
|
App.FrameworkInitialized += App_FrameworkInitialized;
|
||||||
|
@ -10,6 +10,7 @@ using DynamicData;
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Wabbajack.Paths;
|
using Wabbajack.Paths;
|
||||||
using Wabbajack.Paths.IO;
|
using Wabbajack.Paths.IO;
|
||||||
|
using Wabbajack.Services.OSIntegrated;
|
||||||
|
|
||||||
namespace Wabbajack.App.Utilities;
|
namespace Wabbajack.App.Utilities;
|
||||||
|
|
||||||
|
38
Wabbajack.App/Utilities/OSUtil.cs
Normal file
38
Wabbajack.App/Utilities/OSUtil.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Wabbajack.Common;
|
||||||
|
using Wabbajack.Paths;
|
||||||
|
using Wabbajack.Paths.IO;
|
||||||
|
|
||||||
|
namespace Wabbajack.App.Utilities;
|
||||||
|
|
||||||
|
public static class OSUtil
|
||||||
|
{
|
||||||
|
public static void OpenWebsite(Uri uri)
|
||||||
|
{
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
|
{
|
||||||
|
var helper = new ProcessHelper()
|
||||||
|
{
|
||||||
|
Path = "cmd.exe".ToRelativePath().RelativeTo(KnownFolders.WindowsSystem32),
|
||||||
|
Arguments = new[] {"/C", $"rundll32 url.dll,FileProtocolHandler {uri}"}
|
||||||
|
};
|
||||||
|
helper.Start().FireAndForget();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void OpenFolder(AbsolutePath path)
|
||||||
|
{
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
|
{
|
||||||
|
var helper = new ProcessHelper()
|
||||||
|
{
|
||||||
|
Path = "explorer.exe".ToRelativePath().RelativeTo(KnownFolders.Windows),
|
||||||
|
Arguments = new object[] {path}
|
||||||
|
};
|
||||||
|
helper.Start().FireAndForget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -20,6 +20,7 @@ using Wabbajack.DTOs.SavedSettings;
|
|||||||
using Wabbajack.Installer;
|
using Wabbajack.Installer;
|
||||||
using Wabbajack.Paths;
|
using Wabbajack.Paths;
|
||||||
using Wabbajack.Paths.IO;
|
using Wabbajack.Paths.IO;
|
||||||
|
using Wabbajack.Services.OSIntegrated;
|
||||||
|
|
||||||
namespace Wabbajack.App.ViewModels;
|
namespace Wabbajack.App.ViewModels;
|
||||||
|
|
||||||
@ -124,7 +125,8 @@ public class InstallConfigurationViewModel : ViewModelBase, IActivatableViewMode
|
|||||||
ModList = ModListPath,
|
ModList = ModListPath,
|
||||||
Downloads = Download,
|
Downloads = Download,
|
||||||
Install = Install,
|
Install = Install,
|
||||||
Metadata = metadata
|
Metadata = metadata,
|
||||||
|
StrippedModListData = ModList?.Strip()
|
||||||
});
|
});
|
||||||
|
|
||||||
await _settingsManager.Save("last-install-path", ModListPath);
|
await _settingsManager.Save("last-install-path", ModListPath);
|
||||||
|
@ -97,5 +97,7 @@ public class NexusLoginViewModel : GuidedWebViewModel
|
|||||||
Cookies = cookies,
|
Cookies = cookies,
|
||||||
ApiKey = key
|
ApiKey = key
|
||||||
});
|
});
|
||||||
|
|
||||||
|
MessageBus.Current.SendMessage(new NavigateBack());
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -9,8 +9,11 @@ using System.Web;
|
|||||||
using CefNet;
|
using CefNet;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Wabbajack.App.Extensions;
|
using Wabbajack.App.Extensions;
|
||||||
|
using Wabbajack.App.Messages;
|
||||||
using Wabbajack.DTOs.Logins;
|
using Wabbajack.DTOs.Logins;
|
||||||
using Wabbajack.Services.OSIntegrated;
|
using Wabbajack.Services.OSIntegrated;
|
||||||
|
using Xunit.Sdk;
|
||||||
|
using MessageBus = ReactiveUI.MessageBus;
|
||||||
|
|
||||||
namespace Wabbajack.App.ViewModels;
|
namespace Wabbajack.App.ViewModels;
|
||||||
|
|
||||||
@ -87,6 +90,8 @@ public abstract class OAuthLoginViewModel<TLoginType> : GuidedWebViewModel
|
|||||||
Cookies = cookies,
|
Cookies = cookies,
|
||||||
ResultState = data!
|
ResultState = data!
|
||||||
});
|
});
|
||||||
|
|
||||||
|
MessageBus.Current.SendMessage(new NavigateBack());
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AsyncSchemeHandler : CefSchemeHandlerFactory
|
private class AsyncSchemeHandler : CefSchemeHandlerFactory
|
||||||
|
@ -46,7 +46,6 @@ internal class Program
|
|||||||
services.AddSingleton(new ParallelOptions {MaxDegreeOfParallelism = Environment.ProcessorCount});
|
services.AddSingleton(new ParallelOptions {MaxDegreeOfParallelism = Environment.ProcessorCount});
|
||||||
services.AddSingleton<Client>();
|
services.AddSingleton<Client>();
|
||||||
services.AddSingleton<Networking.WabbajackClientApi.Client>();
|
services.AddSingleton<Networking.WabbajackClientApi.Client>();
|
||||||
services.AddSingleton<Configuration>();
|
|
||||||
services.AddSingleton(s => new GitHubClient(new ProductHeaderValue("wabbajack")));
|
services.AddSingleton(s => new GitHubClient(new ProductHeaderValue("wabbajack")));
|
||||||
|
|
||||||
services.AddOSIntegrated();
|
services.AddOSIntegrated();
|
||||||
|
@ -4,6 +4,7 @@ using Wabbajack.Networking.WabbajackClientApi;
|
|||||||
using Wabbajack.Services.OSIntegrated;
|
using Wabbajack.Services.OSIntegrated;
|
||||||
using Xunit.DependencyInjection;
|
using Xunit.DependencyInjection;
|
||||||
using Xunit.DependencyInjection.Logging;
|
using Xunit.DependencyInjection.Logging;
|
||||||
|
using Configuration = Wabbajack.Services.OSIntegrated.Configuration;
|
||||||
|
|
||||||
namespace Wabbajack.Compiler.Test;
|
namespace Wabbajack.Compiler.Test;
|
||||||
|
|
||||||
|
@ -66,4 +66,20 @@ public class ModList
|
|||||||
/// Whether the Modlist is NSFW or not
|
/// Whether the Modlist is NSFW or not
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsNSFW { get; set; }
|
public bool IsNSFW { get; set; }
|
||||||
|
|
||||||
|
public ModList Strip()
|
||||||
|
{
|
||||||
|
return new ModList
|
||||||
|
{
|
||||||
|
Author = Author,
|
||||||
|
Description = Description,
|
||||||
|
GameType = GameType,
|
||||||
|
Name = Name,
|
||||||
|
Readme = Readme,
|
||||||
|
WabbajackVersion = WabbajackVersion,
|
||||||
|
Website = Website,
|
||||||
|
Version = Version,
|
||||||
|
IsNSFW = IsNSFW,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
@ -20,5 +20,5 @@ public class InstallationConfigurationSetting
|
|||||||
public ModlistMetadata? Metadata { get; set; }
|
public ModlistMetadata? Metadata { get; set; }
|
||||||
|
|
||||||
public AbsolutePath Image { get; set; }
|
public AbsolutePath Image { get; set; }
|
||||||
|
public ModList? StrippedModListData { get; set; }
|
||||||
}
|
}
|
@ -4,6 +4,7 @@ using Wabbajack.Downloaders.IPS4OAuth2Downloader;
|
|||||||
using Wabbajack.Downloaders.MediaFire;
|
using Wabbajack.Downloaders.MediaFire;
|
||||||
using Wabbajack.Downloaders.ModDB;
|
using Wabbajack.Downloaders.ModDB;
|
||||||
using Wabbajack.DTOs.JsonConverters;
|
using Wabbajack.DTOs.JsonConverters;
|
||||||
|
using Wabbajack.Networking.WabbajackClientApi;
|
||||||
|
|
||||||
namespace Wabbajack.Downloaders;
|
namespace Wabbajack.Downloaders;
|
||||||
|
|
||||||
@ -23,6 +24,7 @@ public static class ServiceExtensions
|
|||||||
.AddIPS4OAuth2Downloaders()
|
.AddIPS4OAuth2Downloaders()
|
||||||
.AddWabbajackCDNDownloader()
|
.AddWabbajackCDNDownloader()
|
||||||
.AddGameFileDownloader()
|
.AddGameFileDownloader()
|
||||||
|
.AddWabbajackClient()
|
||||||
.AddSingleton<DownloadDispatcher>();
|
.AddSingleton<DownloadDispatcher>();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,9 +4,10 @@ namespace Wabbajack.Networking.WabbajackClientApi;
|
|||||||
|
|
||||||
public static class ServiceExtensions
|
public static class ServiceExtensions
|
||||||
{
|
{
|
||||||
public static void AddWabbajackClient(this IServiceCollection services)
|
public static IServiceCollection AddWabbajackClient(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddSingleton<Configuration>();
|
services.AddSingleton<Configuration>();
|
||||||
services.AddSingleton<Client>();
|
services.AddSingleton<Client>();
|
||||||
|
return services;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -11,6 +11,9 @@ public static class KnownFolders
|
|||||||
public static AbsolutePath AppDataLocal =>
|
public static AbsolutePath AppDataLocal =>
|
||||||
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData).ToAbsolutePath();
|
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData).ToAbsolutePath();
|
||||||
|
|
||||||
|
public static AbsolutePath WindowsSystem32 => Environment.GetFolderPath(Environment.SpecialFolder.System).ToAbsolutePath();
|
||||||
|
|
||||||
public static AbsolutePath WabbajackAppLocal => AppDataLocal.Combine("Wabbajack");
|
public static AbsolutePath WabbajackAppLocal => AppDataLocal.Combine("Wabbajack");
|
||||||
public static AbsolutePath CurrentDirectory => Directory.GetCurrentDirectory().ToAbsolutePath();
|
public static AbsolutePath CurrentDirectory => Directory.GetCurrentDirectory().ToAbsolutePath();
|
||||||
|
public static AbsolutePath Windows => Environment.GetFolderPath(Environment.SpecialFolder.Windows).ToAbsolutePath();
|
||||||
}
|
}
|
@ -2,6 +2,7 @@ using System;
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Channels;
|
using System.Threading.Channels;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -10,9 +11,9 @@ namespace Wabbajack.RateLimiter;
|
|||||||
|
|
||||||
public class Resource<T> : IResource<T>
|
public class Resource<T> : IResource<T>
|
||||||
{
|
{
|
||||||
private readonly Channel<PendingReport> _channel;
|
private Channel<PendingReport> _channel;
|
||||||
private readonly SemaphoreSlim _semaphore;
|
private SemaphoreSlim _semaphore;
|
||||||
private readonly ConcurrentDictionary<ulong, Job<T>> _tasks;
|
private ConcurrentDictionary<ulong, Job<T>> _tasks;
|
||||||
private ulong _nextId;
|
private ulong _nextId;
|
||||||
private long _totalUsed;
|
private long _totalUsed;
|
||||||
|
|
||||||
@ -22,7 +23,6 @@ public class Resource<T> : IResource<T>
|
|||||||
Name = humanName ?? "<unknown>";
|
Name = humanName ?? "<unknown>";
|
||||||
MaxTasks = maxTasks ?? Environment.ProcessorCount;
|
MaxTasks = maxTasks ?? Environment.ProcessorCount;
|
||||||
MaxThroughput = maxThroughput;
|
MaxThroughput = maxThroughput;
|
||||||
|
|
||||||
_semaphore = new SemaphoreSlim(MaxTasks);
|
_semaphore = new SemaphoreSlim(MaxTasks);
|
||||||
_channel = Channel.CreateBounded<PendingReport>(10);
|
_channel = Channel.CreateBounded<PendingReport>(10);
|
||||||
_tasks = new ConcurrentDictionary<ulong, Job<T>>();
|
_tasks = new ConcurrentDictionary<ulong, Job<T>>();
|
||||||
@ -30,6 +30,23 @@ public class Resource<T> : IResource<T>
|
|||||||
var tsk = StartTask(CancellationToken.None);
|
var tsk = StartTask(CancellationToken.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Resource(string humanName, Func<Task<(int MaxTasks, long MaxThroughput)>> settingGetter)
|
||||||
|
{
|
||||||
|
Name = humanName;
|
||||||
|
_tasks = new ConcurrentDictionary<ulong, Job<T>>();
|
||||||
|
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
var (maxTasks, maxThroughput) = await settingGetter();
|
||||||
|
MaxTasks = maxTasks;
|
||||||
|
MaxThroughput = maxThroughput;
|
||||||
|
_semaphore = new SemaphoreSlim(MaxTasks);
|
||||||
|
_channel = Channel.CreateBounded<PendingReport>(10);
|
||||||
|
|
||||||
|
await StartTask(CancellationToken.None);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public int MaxTasks { get; set; }
|
public int MaxTasks { get; set; }
|
||||||
public long MaxThroughput { get; set; }
|
public long MaxThroughput { get; set; }
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
@ -87,7 +104,7 @@ public class Resource<T> : IResource<T>
|
|||||||
await foreach (var item in _channel.Reader.ReadAllAsync(token))
|
await foreach (var item in _channel.Reader.ReadAllAsync(token))
|
||||||
{
|
{
|
||||||
Interlocked.Add(ref _totalUsed, item.Size);
|
Interlocked.Add(ref _totalUsed, item.Size);
|
||||||
if (MaxThroughput == long.MaxValue)
|
if (MaxThroughput is long.MaxValue or 0)
|
||||||
{
|
{
|
||||||
item.Result.TrySetResult();
|
item.Result.TrySetResult();
|
||||||
sw.Restart();
|
sw.Restart();
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
using Wabbajack.Paths;
|
using Wabbajack.Paths;
|
||||||
|
|
||||||
namespace Wabbajack.App;
|
namespace Wabbajack.Services.OSIntegrated;
|
||||||
|
|
||||||
public class Configuration
|
public class Configuration
|
||||||
{
|
{
|
62
Wabbajack.Services.OSIntegrated/ResourceSettingsManager.cs
Normal file
62
Wabbajack.Services.OSIntegrated/ResourceSettingsManager.cs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Wabbajack.RateLimiter;
|
||||||
|
using Wabbajack.Services.OSIntegrated;
|
||||||
|
|
||||||
|
namespace Wabbajack.App.Models;
|
||||||
|
|
||||||
|
public class ResourceSettingsManager
|
||||||
|
{
|
||||||
|
private readonly SettingsManager _manager;
|
||||||
|
private Dictionary<string,ResourceSetting>? _settings;
|
||||||
|
|
||||||
|
public ResourceSettingsManager(SettingsManager manager)
|
||||||
|
{
|
||||||
|
_manager = manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SemaphoreSlim _lock = new(1);
|
||||||
|
|
||||||
|
public async Task<ResourceSetting> GetSettings(string name)
|
||||||
|
{
|
||||||
|
|
||||||
|
await _lock.WaitAsync();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_settings ??= await _manager.Load<Dictionary<string, ResourceSetting>>("resource_settings");
|
||||||
|
|
||||||
|
if (_settings.TryGetValue(name, out var found)) return found;
|
||||||
|
|
||||||
|
var newSetting = new ResourceSetting
|
||||||
|
{
|
||||||
|
MaxTasks = Environment.ProcessorCount,
|
||||||
|
MaxThroughput = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
_settings.Add(name, newSetting);
|
||||||
|
|
||||||
|
await _manager.Save("resource_settings", _settings);
|
||||||
|
|
||||||
|
return _settings[name];
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_lock.Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ResourceSetting
|
||||||
|
{
|
||||||
|
public long MaxTasks { get; set; }
|
||||||
|
public long MaxThroughput { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SaveSettings(Dictionary<string, ResourceSetting> settings)
|
||||||
|
{
|
||||||
|
await _manager.Save("resource_settings", settings);
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ using System.Net.Http;
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Wabbajack.App.Models;
|
||||||
using Wabbajack.Compiler;
|
using Wabbajack.Compiler;
|
||||||
using Wabbajack.Downloaders;
|
using Wabbajack.Downloaders;
|
||||||
using Wabbajack.Downloaders.GameFile;
|
using Wabbajack.Downloaders.GameFile;
|
||||||
@ -54,17 +55,28 @@ public static class ServiceExtensions
|
|||||||
: new BinaryPatchCache(KnownFolders.EntryPoint.Combine("patchCache.sqlite")));
|
: new BinaryPatchCache(KnownFolders.EntryPoint.Combine("patchCache.sqlite")));
|
||||||
|
|
||||||
service.AddSingleton(new ParallelOptions {MaxDegreeOfParallelism = Environment.ProcessorCount});
|
service.AddSingleton(new ParallelOptions {MaxDegreeOfParallelism = Environment.ProcessorCount});
|
||||||
|
|
||||||
|
Func<Task<(int MaxTasks, long MaxThroughput)>> GetSettings(IServiceProvider provider, string name)
|
||||||
|
{
|
||||||
|
return async () =>
|
||||||
|
{
|
||||||
|
var s = await provider.GetService<ResourceSettingsManager>()!.GetSettings(name);
|
||||||
|
return ((int) s.MaxTasks, s.MaxThroughput);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
service.AddAllSingleton<IResource, IResource<DownloadDispatcher>>(s =>
|
service.AddAllSingleton<IResource, IResource<DownloadDispatcher>>(s =>
|
||||||
new Resource<DownloadDispatcher>("Downloads", 12));
|
new Resource<DownloadDispatcher>("Downloads", GetSettings(s, "Downloads")));
|
||||||
service.AddAllSingleton<IResource, IResource<HttpClient>>(s => new Resource<HttpClient>("Web Requests", 12));
|
|
||||||
service.AddAllSingleton<IResource, IResource<Context>>(s => new Resource<Context>("VFS", 12));
|
service.AddAllSingleton<IResource, IResource<HttpClient>>(s => new Resource<HttpClient>("Web Requests", GetSettings(s, "Web Requests")));
|
||||||
|
service.AddAllSingleton<IResource, IResource<Context>>(s => new Resource<Context>("VFS", GetSettings(s, "VFS")));
|
||||||
service.AddAllSingleton<IResource, IResource<FileHashCache>>(s =>
|
service.AddAllSingleton<IResource, IResource<FileHashCache>>(s =>
|
||||||
new Resource<FileHashCache>("File Hashing", 12));
|
new Resource<FileHashCache>("File Hashing", GetSettings(s, "File Hashing")));
|
||||||
service.AddAllSingleton<IResource, IResource<FileExtractor.FileExtractor>>(s =>
|
service.AddAllSingleton<IResource, IResource<FileExtractor.FileExtractor>>(s =>
|
||||||
new Resource<FileExtractor.FileExtractor>("File Extractor", 12));
|
new Resource<FileExtractor.FileExtractor>("File Extractor", GetSettings(s, "File Extractor")));
|
||||||
|
|
||||||
service.AddAllSingleton<IResource, IResource<ACompiler>>(s =>
|
service.AddAllSingleton<IResource, IResource<ACompiler>>(s =>
|
||||||
new Resource<ACompiler>("Compiler", 12));
|
new Resource<ACompiler>("Compiler", GetSettings(s, "Compiler")));
|
||||||
|
|
||||||
service.AddSingleton<LoggingRateLimiterReporter>();
|
service.AddSingleton<LoggingRateLimiterReporter>();
|
||||||
|
|
||||||
@ -122,6 +134,21 @@ public static class ServiceExtensions
|
|||||||
OSVersion = Environment.OSVersion.VersionString,
|
OSVersion = Environment.OSVersion.VersionString,
|
||||||
Version = version
|
Version = version
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Settings
|
||||||
|
|
||||||
|
service.AddSingleton(s => new Configuration
|
||||||
|
{
|
||||||
|
EncryptedDataLocation = KnownFolders.WabbajackAppLocal.Combine("encrypted"),
|
||||||
|
ModListsDownloadLocation = KnownFolders.EntryPoint.Combine("downloaded_mod_lists"),
|
||||||
|
SavedSettingsLocation = KnownFolders.WabbajackAppLocal.Combine("saved_settings"),
|
||||||
|
LogLocation = KnownFolders.EntryPoint.Combine("logs"),
|
||||||
|
ImageCacheLocation = KnownFolders.WabbajackAppLocal.Combine("image_cache")
|
||||||
|
});
|
||||||
|
|
||||||
|
service.AddSingleton<SettingsManager>();
|
||||||
|
service.AddSingleton<ResourceSettingsManager>();
|
||||||
|
|
||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ using Wabbajack.DTOs.JsonConverters;
|
|||||||
using Wabbajack.Paths;
|
using Wabbajack.Paths;
|
||||||
using Wabbajack.Paths.IO;
|
using Wabbajack.Paths.IO;
|
||||||
|
|
||||||
namespace Wabbajack.App.Models;
|
namespace Wabbajack.Services.OSIntegrated;
|
||||||
|
|
||||||
public class SettingsManager
|
public class SettingsManager
|
||||||
{
|
{
|
||||||
@ -35,7 +35,11 @@ public class SettingsManager
|
|||||||
var tmp = GetPath(key).WithExtension(Ext.Temp);
|
var tmp = GetPath(key).WithExtension(Ext.Temp);
|
||||||
await using (var s = tmp.Open(FileMode.Create, FileAccess.Write))
|
await using (var s = tmp.Open(FileMode.Create, FileAccess.Write))
|
||||||
{
|
{
|
||||||
await JsonSerializer.SerializeAsync(s, value, _dtos.Options);
|
var opts = new JsonSerializerOptions(_dtos.Options)
|
||||||
|
{
|
||||||
|
WriteIndented = true
|
||||||
|
};
|
||||||
|
await JsonSerializer.SerializeAsync(s, value, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
await tmp.MoveToAsync(GetPath(key), true, CancellationToken.None);
|
await tmp.MoveToAsync(GetPath(key), true, CancellationToken.None);
|
Loading…
Reference in New Issue
Block a user