mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Woot, we can log into the Nexus through 3.0 code
This commit is contained in:
parent
149dd9b07e
commit
9f87d91918
@ -15,6 +15,7 @@ using Wabbajack.DTOs;
|
|||||||
using Wabbajack.LoginManagers;
|
using Wabbajack.LoginManagers;
|
||||||
using Wabbajack.Models;
|
using Wabbajack.Models;
|
||||||
using Wabbajack.Services.OSIntegrated;
|
using Wabbajack.Services.OSIntegrated;
|
||||||
|
using Wabbajack.UserIntervention;
|
||||||
using Wabbajack.Util;
|
using Wabbajack.Util;
|
||||||
|
|
||||||
namespace Wabbajack
|
namespace Wabbajack
|
||||||
@ -47,6 +48,9 @@ namespace Wabbajack
|
|||||||
RxApp.MainThreadScheduler = new DispatcherScheduler(Dispatcher.CurrentDispatcher);
|
RxApp.MainThreadScheduler = new DispatcherScheduler(Dispatcher.CurrentDispatcher);
|
||||||
|
|
||||||
services.AddOSIntegrated();
|
services.AddOSIntegrated();
|
||||||
|
|
||||||
|
services.AddSingleton<CefService>();
|
||||||
|
|
||||||
services.AddTransient<MainWindow>();
|
services.AddTransient<MainWindow>();
|
||||||
services.AddTransient<MainWindowVM>();
|
services.AddTransient<MainWindowVM>();
|
||||||
services.AddSingleton<SystemParametersConstructor>();
|
services.AddSingleton<SystemParametersConstructor>();
|
||||||
@ -60,6 +64,10 @@ namespace Wabbajack
|
|||||||
services.AddTransient<ModeSelectionVM>();
|
services.AddTransient<ModeSelectionVM>();
|
||||||
services.AddTransient<ModListGalleryVM>();
|
services.AddTransient<ModListGalleryVM>();
|
||||||
services.AddTransient<InstallerVM>();
|
services.AddTransient<InstallerVM>();
|
||||||
|
|
||||||
|
services.AddTransient<WebBrowserVM>();
|
||||||
|
|
||||||
|
services.AddTransient<NexusLoginHandler>();
|
||||||
|
|
||||||
// Login Managers
|
// Login Managers
|
||||||
services.AddAllSingleton<INeedsLogin, NexusLoginManager>();
|
services.AddAllSingleton<INeedsLogin, NexusLoginManager>();
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using Wabbajack.Paths;
|
using Wabbajack.Paths;
|
||||||
|
using Wabbajack.Paths.IO;
|
||||||
|
|
||||||
namespace Wabbajack;
|
namespace Wabbajack;
|
||||||
|
|
||||||
@ -9,6 +10,7 @@ public static class Consts
|
|||||||
public static Uri WabbajackBuildServerUri => new("https://build.wabbajack.org");
|
public static Uri WabbajackBuildServerUri => new("https://build.wabbajack.org");
|
||||||
public static Version CurrentMinimumWabbajackVersion { get; set; } = Version.Parse("2.3.0.0");
|
public static Version CurrentMinimumWabbajackVersion { get; set; } = Version.Parse("2.3.0.0");
|
||||||
public static bool UseNetworkWorkaroundMode { get; set; } = false;
|
public static bool UseNetworkWorkaroundMode { get; set; } = false;
|
||||||
|
public static AbsolutePath CefCacheLocation { get; } = KnownFolders.WabbajackAppLocal.Combine("Cef");
|
||||||
|
|
||||||
public static byte SettingsVersion = 0;
|
public static byte SettingsVersion = 0;
|
||||||
|
|
||||||
|
@ -2,10 +2,12 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using Wabbajack.Common;
|
using Wabbajack.Common;
|
||||||
|
using Wabbajack.DTOs.Interventions;
|
||||||
using Wabbajack.Interventions;
|
using Wabbajack.Interventions;
|
||||||
|
|
||||||
namespace Wabbajack
|
namespace Wabbajack
|
||||||
@ -18,6 +20,12 @@ namespace Wabbajack
|
|||||||
|
|
||||||
private bool _handled;
|
private bool _handled;
|
||||||
public bool Handled { get => _handled; set => this.RaiseAndSetIfChanged(ref _handled, value); }
|
public bool Handled { get => _handled; set => this.RaiseAndSetIfChanged(ref _handled, value); }
|
||||||
|
public CancellationToken Token { get; }
|
||||||
|
public void SetException(Exception exception)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
public abstract void Cancel();
|
public abstract void Cancel();
|
||||||
public ICommand CancelCommand { get; }
|
public ICommand CancelCommand { get; }
|
||||||
|
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
using ReactiveUI;
|
|
||||||
|
|
||||||
namespace Wabbajack.Interventions
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Defines a message that requires user interaction. The user must perform some action
|
|
||||||
/// or make a choice.
|
|
||||||
/// </summary>
|
|
||||||
public interface IUserIntervention : IReactiveObject
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The user didn't make a choice, so this action should be aborted
|
|
||||||
/// </summary>
|
|
||||||
void Cancel();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the interaction has been handled and no longer needs attention
|
|
||||||
/// Note: This needs to be Reactive so that users can monitor its status
|
|
||||||
/// </summary>
|
|
||||||
bool Handled { get; }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -11,7 +11,8 @@ public class NavigateToGlobal
|
|||||||
Installer,
|
Installer,
|
||||||
Settings,
|
Settings,
|
||||||
Compiler,
|
Compiler,
|
||||||
ModListContents
|
ModListContents,
|
||||||
|
WebBrowser
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScreenType Screen { get; }
|
public ScreenType Screen { get; }
|
||||||
|
@ -1,16 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
using Wabbajack.DTOs.Interventions;
|
||||||
using Wabbajack.Networking.Http.Interfaces;
|
using Wabbajack.Networking.Http.Interfaces;
|
||||||
|
|
||||||
namespace Wabbajack.Messages;
|
namespace Wabbajack.Messages;
|
||||||
|
|
||||||
public class NexusLogin
|
public class NexusLogin : IUserIntervention
|
||||||
{
|
{
|
||||||
private TaskCompletionSource CompletionSource { get; }
|
private readonly CancellationTokenSource _source;
|
||||||
|
public TaskCompletionSource CompletionSource { get; }
|
||||||
|
public CancellationToken Token => _source.Token;
|
||||||
|
public void SetException(Exception exception)
|
||||||
|
{
|
||||||
|
CompletionSource.SetException(exception);
|
||||||
|
_source.Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
public NexusLogin()
|
public NexusLogin()
|
||||||
{
|
{
|
||||||
CompletionSource = new TaskCompletionSource();
|
CompletionSource = new TaskCompletionSource();
|
||||||
|
_source = new CancellationTokenSource();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Task Send()
|
public static Task Send()
|
||||||
@ -19,4 +31,12 @@ public class NexusLogin
|
|||||||
MessageBus.Current.SendMessage(msg);
|
MessageBus.Current.SendMessage(msg);
|
||||||
return msg.CompletionSource.Task;
|
return msg.CompletionSource.Task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Cancel()
|
||||||
|
{
|
||||||
|
_source.Cancel();
|
||||||
|
CompletionSource.TrySetCanceled();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Handled => CompletionSource.Task.IsCompleted;
|
||||||
}
|
}
|
70
Wabbajack.App.Wpf/Models/CefService.cs
Normal file
70
Wabbajack.App.Wpf/Models/CefService.cs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using CefSharp;
|
||||||
|
using CefSharp.Wpf;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace Wabbajack.Models;
|
||||||
|
|
||||||
|
public class CefService
|
||||||
|
{
|
||||||
|
private readonly ILogger<CefService> _logger;
|
||||||
|
private bool Inited { get; set; } = false;
|
||||||
|
|
||||||
|
public Func<IBrowser, IFrame, string, IRequest, IResourceHandler>? SchemeHandler { get; set; }
|
||||||
|
|
||||||
|
public CefService(ILogger<CefService> logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
Inited = false;
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IWebBrowser CreateBrowser()
|
||||||
|
{
|
||||||
|
return new ChromiumWebBrowser();
|
||||||
|
}
|
||||||
|
private void Init()
|
||||||
|
{
|
||||||
|
if (Inited || Cef.IsInitialized) return;
|
||||||
|
Inited = true;
|
||||||
|
var settings = new CefSettings
|
||||||
|
{
|
||||||
|
CachePath = Consts.CefCacheLocation.ToString(),
|
||||||
|
JavascriptFlags = "--noexpose_wasm"
|
||||||
|
};
|
||||||
|
settings.RegisterScheme(new CefCustomScheme()
|
||||||
|
{
|
||||||
|
SchemeName = "wabbajack",
|
||||||
|
SchemeHandlerFactory = new SchemeHandlerFactor(_logger, this)
|
||||||
|
});
|
||||||
|
|
||||||
|
_logger.LogInformation("Initializing Cef");
|
||||||
|
if (!Cef.Initialize(settings))
|
||||||
|
{
|
||||||
|
_logger.LogError("Cannot initialize CEF");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SchemeHandlerFactor : ISchemeHandlerFactory
|
||||||
|
{
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
private readonly CefService _service;
|
||||||
|
|
||||||
|
internal SchemeHandlerFactor(ILogger logger, CefService service)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_service = service;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Scheme handler Got: {Scheme} : {Url}", schemeName, request.Url);
|
||||||
|
if (_service.SchemeHandler != null && schemeName == "wabbajack")
|
||||||
|
{
|
||||||
|
return _service.SchemeHandler!(browser, frame, schemeName, request);
|
||||||
|
}
|
||||||
|
return new ResourceHandler();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -103,7 +103,7 @@ public class LoggerProvider : ILoggerProvider
|
|||||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception,
|
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception,
|
||||||
Func<TState, Exception?, string> formatter)
|
Func<TState, Exception?, string> formatter)
|
||||||
{
|
{
|
||||||
Debug.WriteLine(formatter(state, exception));
|
Debug.WriteLine($"{logLevel} - {formatter(state, exception)}");
|
||||||
_provider._messages.OnNext(new LogMessage<TState>(DateTime.UtcNow, _provider.NextMessageId(), logLevel,
|
_provider._messages.OnNext(new LogMessage<TState>(DateTime.UtcNow, _provider.NextMessageId(), logLevel,
|
||||||
eventId, state, exception, formatter));
|
eventId, state, exception, formatter));
|
||||||
}
|
}
|
||||||
|
111
Wabbajack.App.Wpf/UserIntervention/NexusLoginHandler.cs
Normal file
111
Wabbajack.App.Wpf/UserIntervention/NexusLoginHandler.cs
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using ReactiveUI;
|
||||||
|
using Wabbajack.DTOs.Logins;
|
||||||
|
using Wabbajack.LibCefHelpers;
|
||||||
|
using Wabbajack.Messages;
|
||||||
|
using Wabbajack.Networking.Http.Interfaces;
|
||||||
|
using Wabbajack.Services.OSIntegrated.TokenProviders;
|
||||||
|
|
||||||
|
namespace Wabbajack.UserIntervention;
|
||||||
|
|
||||||
|
public class NexusLoginHandler : WebUserInterventionBase
|
||||||
|
{
|
||||||
|
private readonly ITokenProvider<NexusApiState> _provider;
|
||||||
|
|
||||||
|
public NexusLoginHandler(ILogger<NexusLoginHandler> logger, WebBrowserVM browserVM, ITokenProvider<NexusApiState> provider) : base(logger, browserVM)
|
||||||
|
{
|
||||||
|
_provider = provider;
|
||||||
|
}
|
||||||
|
public async Task Begin()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Messages.NavigateTo.Send(Browser);
|
||||||
|
UpdateStatus("Please log into the Nexus");
|
||||||
|
await Driver.WaitForInitialized();
|
||||||
|
|
||||||
|
await NavigateTo(new Uri("https://users.nexusmods.com/auth/continue?client_id=nexus&redirect_uri=https://www.nexusmods.com/oauth/callback&response_type=code&referrer=//www.nexusmods.com"));
|
||||||
|
|
||||||
|
Helpers.Cookie[] cookies = {};
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
cookies = await Driver.GetCookies("nexusmods.com");
|
||||||
|
if (cookies.Any(c => c.Name == "member_id"))
|
||||||
|
break;
|
||||||
|
Message.Token.ThrowIfCancellationRequested();
|
||||||
|
await Task.Delay(500, Message.Token);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
await NavigateTo(new Uri("https://www.nexusmods.com/users/myaccount?tab=api"));
|
||||||
|
|
||||||
|
UpdateStatus("Looking for API Key");
|
||||||
|
|
||||||
|
var key = "";
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
key = await Driver.EvaluateJavaScript(
|
||||||
|
"document.querySelector(\"input[value=wabbajack]\").parentElement.parentElement.querySelector(\"textarea.application-key\").innerHTML");
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(key))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Driver.EvaluateJavaScript(
|
||||||
|
"var found = document.querySelector(\"input[value=wabbajack]\").parentElement.parentElement.querySelector(\"form button[type=submit]\");" +
|
||||||
|
"found.onclick= function() {return true;};" +
|
||||||
|
"found.class = \" \"; " +
|
||||||
|
"found.click();" +
|
||||||
|
"found.remove(); found = undefined;"
|
||||||
|
);
|
||||||
|
UpdateStatus("Generating API Key, Please Wait...");
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
|
||||||
|
Message.Token.ThrowIfCancellationRequested();
|
||||||
|
await Task.Delay(500, Message.Token);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
await _provider.SetToken(new NexusApiState()
|
||||||
|
{
|
||||||
|
ApiKey = key,
|
||||||
|
Cookies = cookies.Select(c => new Cookie()
|
||||||
|
{
|
||||||
|
Domain = c.Domain,
|
||||||
|
Name = c.Name,
|
||||||
|
Path = c.Path,
|
||||||
|
Value = c.Value
|
||||||
|
}).ToArray()
|
||||||
|
});
|
||||||
|
|
||||||
|
((NexusLogin)Message).CompletionSource.SetResult();
|
||||||
|
Messages.NavigateTo.Send(PrevPane);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogError(ex, "While logging into Nexus Mods");
|
||||||
|
Message.SetException(ex);
|
||||||
|
Messages.NavigateTo.Send(PrevPane);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Wabbajack.DTOs.Interventions;
|
||||||
|
using Wabbajack.Interventions;
|
||||||
|
using Wabbajack.WebAutomation;
|
||||||
|
|
||||||
|
namespace Wabbajack.UserIntervention;
|
||||||
|
|
||||||
|
public class WebUserInterventionBase
|
||||||
|
{
|
||||||
|
protected readonly WebBrowserVM Browser;
|
||||||
|
protected readonly ILogger Logger;
|
||||||
|
protected IUserIntervention Message;
|
||||||
|
protected ViewModel PrevPane;
|
||||||
|
protected IWebDriver Driver;
|
||||||
|
|
||||||
|
public WebUserInterventionBase(ILogger logger, WebBrowserVM browser)
|
||||||
|
{
|
||||||
|
Logger = logger;
|
||||||
|
Browser = browser;
|
||||||
|
Driver = new CefSharpWrapper(logger, browser.Browser);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Configure(ViewModel prevPane, IUserIntervention message)
|
||||||
|
{
|
||||||
|
Message = message;
|
||||||
|
PrevPane = prevPane;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void UpdateStatus(string status)
|
||||||
|
{
|
||||||
|
Browser.Instructions = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async Task NavigateTo(Uri uri)
|
||||||
|
{
|
||||||
|
await Driver.NavigateTo(uri, Message.Token);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -12,6 +12,7 @@ using System.Reactive.Disposables;
|
|||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using DynamicData.Binding;
|
using DynamicData.Binding;
|
||||||
using ReactiveUI.Fody.Helpers;
|
using ReactiveUI.Fody.Helpers;
|
||||||
|
using Wabbajack.DTOs.Interventions;
|
||||||
|
|
||||||
namespace Wabbajack
|
namespace Wabbajack
|
||||||
{
|
{
|
||||||
|
@ -1,13 +1,6 @@
|
|||||||
using System;
|
using System.Threading.Tasks;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using ReactiveUI;
|
|
||||||
using Wabbajack.Common;
|
|
||||||
using Wabbajack.Installer;
|
using Wabbajack.Installer;
|
||||||
using Wabbajack;
|
using Wabbajack.DTOs.Interventions;
|
||||||
using Wabbajack.Interventions;
|
|
||||||
|
|
||||||
namespace Wabbajack
|
namespace Wabbajack
|
||||||
{
|
{
|
||||||
|
@ -13,6 +13,7 @@ using Wabbajack.Common;
|
|||||||
using Wabbajack.Installer;
|
using Wabbajack.Installer;
|
||||||
using Wabbajack;
|
using Wabbajack;
|
||||||
using Wabbajack.DTOs;
|
using Wabbajack.DTOs;
|
||||||
|
using Wabbajack.DTOs.Interventions;
|
||||||
using Wabbajack.Interventions;
|
using Wabbajack.Interventions;
|
||||||
using Wabbajack.Util;
|
using Wabbajack.Util;
|
||||||
|
|
||||||
@ -194,7 +195,7 @@ namespace Wabbajack
|
|||||||
*/
|
*/
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IUserIntervention InterventionConverter(IUserIntervention intervention)
|
public IUserIntervention InterventionConverter(IUserIntervention intervention)
|
||||||
{
|
{
|
||||||
switch (intervention)
|
switch (intervention)
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using ReactiveUI.Fody.Helpers;
|
using ReactiveUI.Fody.Helpers;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
@ -16,10 +17,12 @@ using Wabbajack.Common;
|
|||||||
using Wabbajack.Downloaders.GameFile;
|
using Wabbajack.Downloaders.GameFile;
|
||||||
using Wabbajack;
|
using Wabbajack;
|
||||||
using Wabbajack.Interventions;
|
using Wabbajack.Interventions;
|
||||||
|
using Wabbajack.LoginManagers;
|
||||||
using Wabbajack.Messages;
|
using Wabbajack.Messages;
|
||||||
using Wabbajack.Models;
|
using Wabbajack.Models;
|
||||||
using Wabbajack.Networking.WabbajackClientApi;
|
using Wabbajack.Networking.WabbajackClientApi;
|
||||||
using Wabbajack.Paths;
|
using Wabbajack.Paths;
|
||||||
|
using Wabbajack.UserIntervention;
|
||||||
using Wabbajack.View_Models;
|
using Wabbajack.View_Models;
|
||||||
|
|
||||||
namespace Wabbajack
|
namespace Wabbajack
|
||||||
@ -44,12 +47,16 @@ namespace Wabbajack
|
|||||||
public readonly Lazy<SettingsVM> SettingsPane;
|
public readonly Lazy<SettingsVM> SettingsPane;
|
||||||
public readonly ModListGalleryVM Gallery;
|
public readonly ModListGalleryVM Gallery;
|
||||||
public readonly ModeSelectionVM ModeSelectionVM;
|
public readonly ModeSelectionVM ModeSelectionVM;
|
||||||
|
public readonly WebBrowserVM WebBrowserVM;
|
||||||
public readonly Lazy<ModListContentsVM> ModListContentsVM;
|
public readonly Lazy<ModListContentsVM> ModListContentsVM;
|
||||||
public readonly UserInterventionHandlers UserInterventionHandlers;
|
public readonly UserInterventionHandlers UserInterventionHandlers;
|
||||||
private readonly Client _wjClient;
|
private readonly Client _wjClient;
|
||||||
private readonly ILogger<MainWindowVM> _logger;
|
private readonly ILogger<MainWindowVM> _logger;
|
||||||
private readonly ResourceMonitor _resourceMonitor;
|
private readonly ResourceMonitor _resourceMonitor;
|
||||||
|
|
||||||
|
private List<ViewModel> PreviousPanes = new();
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
|
||||||
public ICommand CopyVersionCommand { get; }
|
public ICommand CopyVersionCommand { get; }
|
||||||
public ICommand ShowLoginManagerVM { get; }
|
public ICommand ShowLoginManagerVM { get; }
|
||||||
public ICommand OpenSettingsCommand { get; }
|
public ICommand OpenSettingsCommand { get; }
|
||||||
@ -64,11 +71,12 @@ namespace Wabbajack
|
|||||||
|
|
||||||
public MainWindowVM(ILogger<MainWindowVM> logger, MainSettings settings, Client wjClient,
|
public MainWindowVM(ILogger<MainWindowVM> logger, MainSettings settings, Client wjClient,
|
||||||
IServiceProvider serviceProvider, ModeSelectionVM modeSelectionVM, ModListGalleryVM modListGalleryVM, ResourceMonitor resourceMonitor,
|
IServiceProvider serviceProvider, ModeSelectionVM modeSelectionVM, ModListGalleryVM modListGalleryVM, ResourceMonitor resourceMonitor,
|
||||||
InstallerVM installer)
|
InstallerVM installer, WebBrowserVM webBrowserVM)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_wjClient = wjClient;
|
_wjClient = wjClient;
|
||||||
_resourceMonitor = resourceMonitor;
|
_resourceMonitor = resourceMonitor;
|
||||||
|
_serviceProvider = serviceProvider;
|
||||||
ConverterRegistration.Register();
|
ConverterRegistration.Register();
|
||||||
Settings = settings;
|
Settings = settings;
|
||||||
Installer = installer;
|
Installer = installer;
|
||||||
@ -76,12 +84,25 @@ namespace Wabbajack
|
|||||||
SettingsPane = new Lazy<SettingsVM>(() => new SettingsVM(serviceProvider.GetRequiredService<ILogger<SettingsVM>>(), this, serviceProvider));
|
SettingsPane = new Lazy<SettingsVM>(() => new SettingsVM(serviceProvider.GetRequiredService<ILogger<SettingsVM>>(), this, serviceProvider));
|
||||||
Gallery = modListGalleryVM;
|
Gallery = modListGalleryVM;
|
||||||
ModeSelectionVM = modeSelectionVM;
|
ModeSelectionVM = modeSelectionVM;
|
||||||
|
WebBrowserVM = webBrowserVM;
|
||||||
ModListContentsVM = new Lazy<ModListContentsVM>(() => new ModListContentsVM(serviceProvider.GetRequiredService<ILogger<ModListContentsVM>>(), this));
|
ModListContentsVM = new Lazy<ModListContentsVM>(() => new ModListContentsVM(serviceProvider.GetRequiredService<ILogger<ModListContentsVM>>(), this));
|
||||||
UserInterventionHandlers = new UserInterventionHandlers(serviceProvider.GetRequiredService<ILogger<UserInterventionHandlers>>(), this);
|
UserInterventionHandlers = new UserInterventionHandlers(serviceProvider.GetRequiredService<ILogger<UserInterventionHandlers>>(), this);
|
||||||
|
|
||||||
MessageBus.Current.Listen<NavigateToGlobal>()
|
MessageBus.Current.Listen<NavigateToGlobal>()
|
||||||
.Subscribe(m => HandleNavigateTo(m.Screen))
|
.Subscribe(m => HandleNavigateTo(m.Screen))
|
||||||
.DisposeWith(CompositeDisposable);
|
.DisposeWith(CompositeDisposable);
|
||||||
|
|
||||||
|
MessageBus.Current.Listen<NavigateTo>()
|
||||||
|
.Subscribe(m => HandleNavigateTo(m.ViewModel))
|
||||||
|
.DisposeWith(CompositeDisposable);
|
||||||
|
|
||||||
|
MessageBus.Current.Listen<NavigateBack>()
|
||||||
|
.Subscribe(HandleNavigateBack)
|
||||||
|
.DisposeWith(CompositeDisposable);
|
||||||
|
|
||||||
|
MessageBus.Current.Listen<NexusLogin>()
|
||||||
|
.Subscribe(m => HandleNexusLogin(m))
|
||||||
|
.DisposeWith(CompositeDisposable);
|
||||||
|
|
||||||
_resourceMonitor.Updates
|
_resourceMonitor.Updates
|
||||||
.Select(r => string.Join(", ", r.Where(r => r.Throughput > 0)
|
.Select(r => string.Join(", ", r.Where(r => r.Throughput > 0)
|
||||||
@ -169,6 +190,24 @@ namespace Wabbajack
|
|||||||
execute: () => NavigateToGlobal.Send(NavigateToGlobal.ScreenType.Settings));
|
execute: () => NavigateToGlobal.Send(NavigateToGlobal.ScreenType.Settings));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void HandleNavigateTo(ViewModel objViewModel)
|
||||||
|
{
|
||||||
|
ActivePane = objViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleNexusLogin(NexusLogin nexusLogin)
|
||||||
|
{
|
||||||
|
var handler = _serviceProvider.GetRequiredService<NexusLoginHandler>();
|
||||||
|
handler.Configure(ActivePane, nexusLogin);
|
||||||
|
handler.Begin().FireAndForget();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleNavigateBack(NavigateBack navigateBack)
|
||||||
|
{
|
||||||
|
ActivePane = PreviousPanes.Last();
|
||||||
|
PreviousPanes.RemoveAt(PreviousPanes.Count - 1);
|
||||||
|
}
|
||||||
|
|
||||||
private void HandleNavigateTo(NavigateToGlobal.ScreenType s)
|
private void HandleNavigateTo(NavigateToGlobal.ScreenType s)
|
||||||
{
|
{
|
||||||
ActivePane = s switch
|
ActivePane = s switch
|
||||||
@ -181,6 +220,7 @@ namespace Wabbajack
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static bool IsStartingFromModlist(out AbsolutePath modlistPath)
|
private static bool IsStartingFromModlist(out AbsolutePath modlistPath)
|
||||||
{
|
{
|
||||||
/* TODO
|
/* TODO
|
||||||
|
@ -2,9 +2,11 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Wabbajack.Common;
|
using Wabbajack.Common;
|
||||||
using Wabbajack;
|
using Wabbajack;
|
||||||
|
using Wabbajack.DTOs.Interventions;
|
||||||
using Wabbajack.Interventions;
|
using Wabbajack.Interventions;
|
||||||
|
|
||||||
namespace Wabbajack
|
namespace Wabbajack
|
||||||
@ -16,6 +18,11 @@ namespace Wabbajack
|
|||||||
public MO2InstallerVM Installer { get; }
|
public MO2InstallerVM Installer { get; }
|
||||||
|
|
||||||
public bool Handled => ((IUserIntervention)Source).Handled;
|
public bool Handled => ((IUserIntervention)Source).Handled;
|
||||||
|
public CancellationToken Token { get; }
|
||||||
|
public void SetException(Exception exception)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
public int CpuID => 0;
|
public int CpuID => 0;
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ using Microsoft.Extensions.Logging;
|
|||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using Wabbajack.Common;
|
using Wabbajack.Common;
|
||||||
using Wabbajack;
|
using Wabbajack;
|
||||||
|
using Wabbajack.DTOs.Interventions;
|
||||||
using Wabbajack.Interventions;
|
using Wabbajack.Interventions;
|
||||||
using Wabbajack.Messages;
|
using Wabbajack.Messages;
|
||||||
|
|
||||||
@ -23,12 +24,13 @@ namespace Wabbajack
|
|||||||
MainWindow = mvm;
|
MainWindow = mvm;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task WrapBrowserJob(IUserIntervention intervention, Func<WebBrowserVM, CancellationTokenSource, Task> toDo)
|
private async Task WrapBrowserJob(IUserIntervention intervention, WebBrowserVM vm, Func<WebBrowserVM, CancellationTokenSource, Task> toDo)
|
||||||
{
|
{
|
||||||
var wait = await _browserLock.WaitAsync();
|
var wait = await _browserLock.WaitAsync();
|
||||||
var cancel = new CancellationTokenSource();
|
var cancel = new CancellationTokenSource();
|
||||||
var oldPane = MainWindow.ActivePane;
|
var oldPane = MainWindow.ActivePane;
|
||||||
using var vm = await WebBrowserVM.GetNew(_logger);
|
|
||||||
|
// TODO: FIX using var vm = await WebBrowserVM.GetNew(_logger);
|
||||||
NavigateTo.Send(vm);
|
NavigateTo.Send(vm);
|
||||||
vm.BackCommand = ReactiveCommand.Create(() =>
|
vm.BackCommand = ReactiveCommand.Create(() =>
|
||||||
{
|
{
|
||||||
|
@ -13,19 +13,22 @@ using ReactiveUI;
|
|||||||
using ReactiveUI.Fody.Helpers;
|
using ReactiveUI.Fody.Helpers;
|
||||||
using Wabbajack;
|
using Wabbajack;
|
||||||
using Wabbajack.LibCefHelpers;
|
using Wabbajack.LibCefHelpers;
|
||||||
|
using Wabbajack.Messages;
|
||||||
|
using Wabbajack.Models;
|
||||||
using Wabbajack.WebAutomation;
|
using Wabbajack.WebAutomation;
|
||||||
|
|
||||||
namespace Wabbajack
|
namespace Wabbajack
|
||||||
{
|
{
|
||||||
public class WebBrowserVM : ViewModel, IBackNavigatingVM, IDisposable
|
public class WebBrowserVM : ViewModel, IBackNavigatingVM, IDisposable
|
||||||
{
|
{
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger<WebBrowserVM> _logger;
|
||||||
|
private readonly CefService _cefService;
|
||||||
|
|
||||||
[Reactive]
|
[Reactive]
|
||||||
public string Instructions { get; set; }
|
public string Instructions { get; set; }
|
||||||
|
|
||||||
public IWebBrowser Browser { get; } = new ChromiumWebBrowser();
|
public IWebBrowser Browser { get; }
|
||||||
public CefSharpWrapper Driver => new(_logger, Browser);
|
public CefSharpWrapper Driver { get; set; }
|
||||||
|
|
||||||
[Reactive]
|
[Reactive]
|
||||||
public ViewModel NavigateBackTarget { get; set; }
|
public ViewModel NavigateBackTarget { get; set; }
|
||||||
@ -36,17 +39,17 @@ namespace Wabbajack
|
|||||||
public Subject<bool> IsBackEnabledSubject { get; } = new Subject<bool>();
|
public Subject<bool> IsBackEnabledSubject { get; } = new Subject<bool>();
|
||||||
public IObservable<bool> IsBackEnabled { get; }
|
public IObservable<bool> IsBackEnabled { get; }
|
||||||
|
|
||||||
private WebBrowserVM(ILogger logger, string url = "http://www.wabbajack.org")
|
public WebBrowserVM(ILogger<WebBrowserVM> logger, CefService cefService)
|
||||||
{
|
{
|
||||||
|
// CefService is required so that Cef is initalized
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
IsBackEnabled = IsBackEnabledSubject.StartWith(true);
|
_cefService = cefService;
|
||||||
Instructions = "Wabbajack Web Browser";
|
Instructions = "Wabbajack Web Browser";
|
||||||
}
|
|
||||||
|
BackCommand = ReactiveCommand.Create(NavigateBack.Send);
|
||||||
|
Browser = cefService.CreateBrowser();
|
||||||
|
Driver = new CefSharpWrapper(_logger, Browser);
|
||||||
|
|
||||||
public static async Task<WebBrowserVM> GetNew(ILogger logger, string url = "http://www.wabbajack.org")
|
|
||||||
{
|
|
||||||
// Make sure libraries are extracted first
|
|
||||||
return new WebBrowserVM(logger, url);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
|
@ -35,6 +35,7 @@ namespace Wabbajack.WebAutomation
|
|||||||
_browser.LoadingStateChanged -= handler;
|
_browser.LoadingStateChanged -= handler;
|
||||||
tcs.SetResult(true);
|
tcs.SetResult(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
_browser.LoadingStateChanged += handler;
|
_browser.LoadingStateChanged += handler;
|
||||||
_browser.Load(uri.ToString());
|
_browser.Load(uri.ToString());
|
||||||
token?.Register(() => tcs.TrySetCanceled());
|
token?.Register(() => tcs.TrySetCanceled());
|
||||||
|
@ -14,6 +14,7 @@ namespace Wabbajack.WebAutomation
|
|||||||
Task NavigateTo(Uri uri, CancellationToken? token = null);
|
Task NavigateTo(Uri uri, CancellationToken? token = null);
|
||||||
Task<string> EvaluateJavaScript(string text);
|
Task<string> EvaluateJavaScript(string text);
|
||||||
Task<Helpers.Cookie[]> GetCookies(string domainPrefix);
|
Task<Helpers.Cookie[]> GetCookies(string domainPrefix);
|
||||||
public Action<Uri>? DownloadHandler { get; set; }
|
public Action<Uri>? DownloadHandler { get; set; }
|
||||||
|
public Task WaitForInitialized();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,6 +102,11 @@ public class ForceHeal : IVerb
|
|||||||
|
|
||||||
var ini = meta.LoadIniFile();
|
var ini = meta.LoadIniFile();
|
||||||
var state = await _downloadDispatcher.ResolveArchive(ini["General"].ToDictionary(d => d.KeyName, d => d.Value));
|
var state = await _downloadDispatcher.ResolveArchive(ini["General"].ToDictionary(d => d.KeyName, d => d.Value));
|
||||||
|
if (state == null)
|
||||||
|
{
|
||||||
|
_logger.LogError("Cannot resolve state from meta for {File}", file);
|
||||||
|
throw new Exception($"Cannot resolve state from meta for {file}");
|
||||||
|
}
|
||||||
|
|
||||||
_logger.LogInformation("Hashing {File}", file.FileName);
|
_logger.LogInformation("Hashing {File}", file.FileName);
|
||||||
var hash = await _fileHashCache.FileHashCachedAsync(file, CancellationToken.None);
|
var hash = await _fileHashCache.FileHashCachedAsync(file, CancellationToken.None);
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace Wabbajack.DTOs.Interventions;
|
namespace Wabbajack.DTOs.Interventions;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -15,4 +18,11 @@ public interface IUserIntervention
|
|||||||
/// Whether the interaction has been handled and no longer needs attention
|
/// Whether the interaction has been handled and no longer needs attention
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool Handled { get; }
|
bool Handled { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Token that can be used to trigger cancellation when Cancel() is called.
|
||||||
|
/// </summary>
|
||||||
|
public CancellationToken Token { get; }
|
||||||
|
|
||||||
|
void SetException(Exception exception);
|
||||||
}
|
}
|
@ -8,4 +8,5 @@ public abstract class GithubAuthTokenProvider : ITokenProvider<string>
|
|||||||
public abstract ValueTask<string> Get();
|
public abstract ValueTask<string> Get();
|
||||||
public abstract ValueTask SetToken(string val);
|
public abstract ValueTask SetToken(string val);
|
||||||
public abstract ValueTask<bool> Delete();
|
public abstract ValueTask<bool> Delete();
|
||||||
|
public abstract bool HaveToken();
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user