mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Completely rework CLI's DI process
This commit is contained in:
@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.CommandLine;
|
||||
using System.Threading.Tasks;
|
||||
@ -9,20 +10,26 @@ namespace Wabbajack.CLI;
|
||||
public class CommandLineBuilder
|
||||
{
|
||||
private readonly IConsole _console;
|
||||
private readonly IEnumerable<IVerb> _verbs;
|
||||
private readonly VerbRegistrar _verbs;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public CommandLineBuilder(IEnumerable<IVerb> verbs, IConsole console, LoggingRateLimiterReporter _)
|
||||
public CommandLineBuilder(VerbRegistrar verbs, IConsole console, LoggingRateLimiterReporter _, IServiceProvider serviceProvider)
|
||||
{
|
||||
_console = console;
|
||||
_verbs = verbs;
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public async Task<int> Run(string[] args)
|
||||
{
|
||||
var root = new RootCommand();
|
||||
foreach (var verb in _verbs)
|
||||
root.Add(verb.MakeCommand());
|
||||
|
||||
foreach (var verb in _verbs.Definitions)
|
||||
{
|
||||
var command = verb.MakeCommand();
|
||||
command.Handler = AVerb.WrapHandler(verb.VerbType, _serviceProvider);
|
||||
root.Add(command);
|
||||
}
|
||||
|
||||
return await root.InvokeAsync(args);
|
||||
}
|
||||
}
|
@ -14,7 +14,6 @@ using Wabbajack.DTOs.GitHub;
|
||||
using Wabbajack.DTOs.Interventions;
|
||||
using Wabbajack.Networking.Http;
|
||||
using Wabbajack.Networking.Http.Interfaces;
|
||||
using Wabbajack.Networking.WabbajackClientApi;
|
||||
using Wabbajack.Paths;
|
||||
using Wabbajack.Paths.IO;
|
||||
using Wabbajack.Server.Lib;
|
||||
@ -32,7 +31,7 @@ internal class Program
|
||||
new TypeConverterAttribute(typeof(AbsolutePathTypeConverter)));
|
||||
TypeDescriptor.AddAttributes(typeof(List),
|
||||
new TypeConverterAttribute(typeof(ModListCategoryConverter)));
|
||||
|
||||
|
||||
var host = Host.CreateDefaultBuilder(Array.Empty<string>())
|
||||
.ConfigureServices((host, services) =>
|
||||
{
|
||||
@ -48,31 +47,48 @@ internal class Program
|
||||
services.AddSingleton<Client>();
|
||||
services.AddSingleton<Networking.WabbajackClientApi.Client>();
|
||||
services.AddSingleton(s => new GitHubClient(new ProductHeaderValue("wabbajack")));
|
||||
services.AddSingleton<VerbRegistrar>();
|
||||
|
||||
services.AddOSIntegrated();
|
||||
services.AddServerLib();
|
||||
|
||||
|
||||
services.AddTransient<Context>();
|
||||
services.AddSingleton<IVerb, HashFile>();
|
||||
services.AddSingleton<IVerb, VFSIndexFolder>();
|
||||
services.AddSingleton<IVerb, Encrypt>();
|
||||
services.AddSingleton<IVerb, Decrypt>();
|
||||
services.AddSingleton<IVerb, ValidateLists>();
|
||||
services.AddSingleton<IVerb, DownloadCef>();
|
||||
services.AddSingleton<IVerb, DownloadUrl>();
|
||||
services.AddSingleton<IVerb, GenerateMetricsReports>();
|
||||
services.AddSingleton<IVerb, ForceHeal>();
|
||||
services.AddSingleton<IVerb, MirrorFile>();
|
||||
services.AddSingleton<IVerb, SteamLogin>();
|
||||
services.AddSingleton<IVerb, SteamAppDumpInfo>();
|
||||
services.AddSingleton<IVerb, SteamDownloadFile>();
|
||||
services.AddSingleton<IVerb, UploadToNexus>();
|
||||
|
||||
services.AddSingleton<Encrypt>();
|
||||
services.AddSingleton<HashFile>();
|
||||
services.AddSingleton<DownloadCef>();
|
||||
services.AddSingleton<Decrypt>();
|
||||
services.AddSingleton<DownloadUrl>();
|
||||
services.AddSingleton<ForceHeal>();
|
||||
services.AddSingleton<MirrorFile>();
|
||||
services.AddSingleton<SteamDownloadFile>();
|
||||
services.AddSingleton<SteamLogin>();
|
||||
services.AddSingleton<UploadToNexus>();
|
||||
services.AddSingleton<ValidateLists>();
|
||||
services.AddSingleton<VfsIndexFolder>();
|
||||
|
||||
services.AddSingleton<IUserInterventionHandler, UserInterventionHandler>();
|
||||
}).Build();
|
||||
|
||||
var service = host.Services.GetService<CommandLineBuilder>();
|
||||
var service = host.Services.GetRequiredService<CommandLineBuilder>();
|
||||
|
||||
var reg = host.Services.GetRequiredService<VerbRegistrar>();
|
||||
|
||||
reg.Register<Decrypt>(Decrypt.MakeCommand);
|
||||
reg.Register<DownloadCef>(DownloadCef.MakeCommand);
|
||||
|
||||
reg.Register<DownloadUrl>(DownloadUrl.MakeCommand);
|
||||
reg.Register<Encrypt>(Encrypt.MakeCommand);
|
||||
reg.Register<HashFile>(HashFile.MakeCommand);
|
||||
reg.Register<ForceHeal>(ForceHeal.MakeCommand);
|
||||
reg.Register<MirrorFile>(MirrorFile.MakeCommand);
|
||||
reg.Register<SteamDownloadFile>(SteamDownloadFile.MakeCommand);
|
||||
reg.Register<SteamLogin>(SteamLogin.MakeCommand);
|
||||
reg.Register<UploadToNexus>(UploadToNexus.MakeCommand);
|
||||
reg.Register<ValidateLists>(ValidateLists.MakeCommand);
|
||||
reg.Register<VfsIndexFolder>(VfsIndexFolder.MakeCommand);
|
||||
|
||||
return await service!.Run(args);
|
||||
}
|
||||
}
|
23
Wabbajack.CLI/VerbRegistrar.cs
Normal file
23
Wabbajack.CLI/VerbRegistrar.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.CommandLine;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Wabbajack.CLI.Verbs;
|
||||
|
||||
namespace Wabbajack.CLI;
|
||||
|
||||
public class VerbRegistrar
|
||||
{
|
||||
public List<VerbDefinition> Definitions { get; }= new();
|
||||
|
||||
public void Register<T>(Func<Command> makeCommand)
|
||||
{
|
||||
Definitions.Add(new VerbDefinition(makeCommand, typeof(T)));
|
||||
}
|
||||
}
|
||||
|
||||
public record VerbDefinition(Func<Command> MakeCommand, Type VerbType)
|
||||
{
|
||||
|
||||
}
|
32
Wabbajack.CLI/Verbs/AVerb.cs
Normal file
32
Wabbajack.CLI/Verbs/AVerb.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.CommandLine.Invocation;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Wabbajack.CLI.Verbs;
|
||||
|
||||
public abstract class AVerb
|
||||
{
|
||||
public static ICommandHandler WrapHandler(Type type, IServiceProvider provider)
|
||||
{
|
||||
return new WrappedHandler(type, provider);
|
||||
}
|
||||
protected abstract ICommandHandler GetHandler();
|
||||
|
||||
private class WrappedHandler : ICommandHandler
|
||||
{
|
||||
private readonly IServiceProvider _provider;
|
||||
private readonly Type _type;
|
||||
|
||||
public WrappedHandler(Type type, IServiceProvider provider)
|
||||
{
|
||||
_provider = provider;
|
||||
_type = type;
|
||||
}
|
||||
public Task<int> InvokeAsync(InvocationContext context)
|
||||
{
|
||||
var verb = (AVerb)_provider.GetRequiredService(_type);
|
||||
return verb.GetHandler().InvokeAsync(context);
|
||||
}
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ using Wabbajack.Services.OSIntegrated;
|
||||
|
||||
namespace Wabbajack.CLI.Verbs;
|
||||
|
||||
public class Decrypt : IVerb
|
||||
public class Decrypt : AVerb
|
||||
{
|
||||
private readonly ILogger<Decrypt> _logger;
|
||||
|
||||
@ -17,13 +17,12 @@ public class Decrypt : IVerb
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Command MakeCommand()
|
||||
public static Command MakeCommand()
|
||||
{
|
||||
var command = new Command("decrypt");
|
||||
command.Add(new Option<AbsolutePath>(new[] {"-o", "-output"}, "Output file path"));
|
||||
command.Add(new Option<string>(new[] {"-n", "-name"}, "Name of the key to load data from"));
|
||||
command.Description = "Decrypts a file from the Wabbajack encrypted storage";
|
||||
command.Handler = CommandHandler.Create(Run);
|
||||
return command;
|
||||
}
|
||||
|
||||
@ -37,4 +36,9 @@ public class Decrypt : IVerb
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override ICommandHandler GetHandler()
|
||||
{
|
||||
return CommandHandler.Create(Run);
|
||||
}
|
||||
}
|
@ -20,7 +20,7 @@ using Version = System.Version;
|
||||
|
||||
namespace Wabbajack.CLI.Verbs;
|
||||
|
||||
public class DownloadCef : IVerb
|
||||
public class DownloadCef : AVerb
|
||||
{
|
||||
private readonly DownloadDispatcher _dispatcher;
|
||||
private readonly FileExtractor.FileExtractor _fileExtractor;
|
||||
@ -36,13 +36,12 @@ public class DownloadCef : IVerb
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
public Command MakeCommand()
|
||||
public static Command MakeCommand()
|
||||
{
|
||||
var command = new Command("download-cef");
|
||||
command.Add(new Option<AbsolutePath>(new[] {"-f", "-folder"}, "Path to Wabbajack"));
|
||||
command.Add(new Option<bool>(new[] {"--force"}, "Force the download even if the output already exists"));
|
||||
command.Description = "Downloads CEF into this folder";
|
||||
command.Handler = CommandHandler.Create(Run);
|
||||
return command;
|
||||
}
|
||||
|
||||
@ -111,4 +110,9 @@ public class DownloadCef : IVerb
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override ICommandHandler GetHandler()
|
||||
{
|
||||
return CommandHandler.Create(Run);
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@ using Wabbajack.Paths;
|
||||
|
||||
namespace Wabbajack.CLI.Verbs;
|
||||
|
||||
public class DownloadUrl : IVerb
|
||||
public class DownloadUrl : AVerb
|
||||
{
|
||||
private readonly DownloadDispatcher _dispatcher;
|
||||
private readonly ILogger<DownloadUrl> _logger;
|
||||
@ -21,13 +21,12 @@ public class DownloadUrl : IVerb
|
||||
_dispatcher = dispatcher;
|
||||
}
|
||||
|
||||
public Command MakeCommand()
|
||||
public static Command MakeCommand()
|
||||
{
|
||||
var command = new Command("download-url");
|
||||
command.Add(new Option<Uri>(new[] {"-u", "-url"}, "Url to parse"));
|
||||
command.Add(new Option<AbsolutePath>(new[] {"-o", "-output"}, "Output file"));
|
||||
command.Description = "Downloads a file to a given output";
|
||||
command.Handler = CommandHandler.Create(Run);
|
||||
return command;
|
||||
}
|
||||
|
||||
@ -45,4 +44,9 @@ public class DownloadUrl : IVerb
|
||||
await _dispatcher.Download(archive, output, CancellationToken.None);
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override ICommandHandler GetHandler()
|
||||
{
|
||||
return CommandHandler.Create(Run);
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ using Wabbajack.Services.OSIntegrated;
|
||||
|
||||
namespace Wabbajack.CLI.Verbs;
|
||||
|
||||
public class Encrypt : IVerb
|
||||
public class Encrypt : AVerb
|
||||
{
|
||||
private readonly ILogger<Encrypt> _logger;
|
||||
|
||||
@ -17,16 +17,15 @@ public class Encrypt : IVerb
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Command MakeCommand()
|
||||
public static Command MakeCommand()
|
||||
{
|
||||
var command = new Command("encrypt");
|
||||
command.Add(new Option<AbsolutePath>(new[] {"-i", "-input"}, "Path to the file to enrypt"));
|
||||
command.Add(new Option<string>(new[] {"-n", "-name"}, "Name of the key to store the data into"));
|
||||
command.Description = "Encrypts a file and stores it in the Wabbajack encrypted storage";
|
||||
command.Handler = CommandHandler.Create(Run);
|
||||
return command;
|
||||
}
|
||||
|
||||
|
||||
public async Task<int> Run(AbsolutePath input, string name)
|
||||
{
|
||||
var data = await input.ReadAllBytesAsync();
|
||||
@ -35,4 +34,9 @@ public class Encrypt : IVerb
|
||||
.RelativeTo(KnownFolders.WabbajackAppLocal.Combine("encrypted")));
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override ICommandHandler GetHandler()
|
||||
{
|
||||
return CommandHandler.Create(Run);
|
||||
}
|
||||
}
|
@ -24,7 +24,7 @@ using Wabbajack.VFS;
|
||||
|
||||
namespace Wabbajack.CLI.Verbs;
|
||||
|
||||
public class ForceHeal : IVerb
|
||||
public class ForceHeal : AVerb
|
||||
{
|
||||
private readonly ILogger<ForceHeal> _logger;
|
||||
private readonly Client _client;
|
||||
@ -42,13 +42,12 @@ public class ForceHeal : IVerb
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
public Command MakeCommand()
|
||||
public static Command MakeCommand()
|
||||
{
|
||||
var command = new Command("force-heal");
|
||||
command.Add(new Option<AbsolutePath>(new[] {"-n", "-new-file"}, "New File"));
|
||||
command.Add(new Option<string>(new[] {"-o", "-old-file"}, "Old File"));
|
||||
command.Description = "Creates a patch from New file to Old File and uploads it";
|
||||
command.Handler = CommandHandler.Create(Run);
|
||||
return command;
|
||||
}
|
||||
|
||||
@ -119,4 +118,9 @@ public class ForceHeal : IVerb
|
||||
State = state!
|
||||
};
|
||||
}
|
||||
|
||||
protected override ICommandHandler GetHandler()
|
||||
{
|
||||
return CommandHandler.Create(Run);
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.CommandLine;
|
||||
using System.CommandLine.Invocation;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.DTOs.JsonConverters;
|
||||
using Wabbajack.DTOs.ServerResponses;
|
||||
using Wabbajack.Paths;
|
||||
|
||||
namespace Wabbajack.CLI.Verbs;
|
||||
|
||||
public class GenerateMetricsReports : IVerb
|
||||
{
|
||||
private readonly HttpClient _client;
|
||||
private readonly DTOSerializer _dtos;
|
||||
|
||||
public GenerateMetricsReports(HttpClient client, DTOSerializer dtos)
|
||||
{
|
||||
_client = client;
|
||||
_dtos = dtos;
|
||||
}
|
||||
public Command MakeCommand()
|
||||
{
|
||||
var command = new Command("generate-metrics-report");
|
||||
command.Add(new Option<AbsolutePath>(new[] {"-o", "-output"}, "Output folder"));
|
||||
command.Description = "Generates usage metrics and outputs a html report about them";
|
||||
command.Handler = CommandHandler.Create(Run);
|
||||
return command;
|
||||
|
||||
|
||||
}
|
||||
|
||||
private async Task<int> Run(AbsolutePath output)
|
||||
{
|
||||
var subjects = await GetMetrics("one day ago", "now", "finish_install")
|
||||
.Where(d => d.Action != d.Subject)
|
||||
.Select(async d => d.GroupingSubject)
|
||||
.ToHashSet();
|
||||
|
||||
var allTime = await GetMetrics("10 days ago", "now", "finish_install")
|
||||
.Where(d => subjects.Contains(d.GroupingSubject))
|
||||
.ToList();
|
||||
|
||||
var grouped = allTime.GroupBy(g => (g.Timestamp.ToString("yyyy-MM-dd"), g.GroupingSubject)).ToArray();
|
||||
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private async IAsyncEnumerable<MetricResult> GetMetrics(string start, string end, string action)
|
||||
{
|
||||
await using var response = await _client.GetStreamAsync(new Uri($"https://build.wabbajack.org/metrics/report?action={action}&from={start}&end={end}"));
|
||||
|
||||
var sr = new StreamReader(response, leaveOpen: false);
|
||||
|
||||
while (true)
|
||||
{
|
||||
var line = await sr.ReadLineAsync();
|
||||
if (line == null) break;
|
||||
yield return _dtos.Deserialize<MetricResult>(line)!;
|
||||
}
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@ using Wabbajack.Paths.IO;
|
||||
|
||||
namespace Wabbajack.CLI.Verbs;
|
||||
|
||||
public class HashFile : IVerb
|
||||
public class HashFile : AVerb
|
||||
{
|
||||
private readonly ILogger<HashFile> _logger;
|
||||
|
||||
@ -18,22 +18,25 @@ public class HashFile : IVerb
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Command MakeCommand()
|
||||
|
||||
public static Command MakeCommand()
|
||||
{
|
||||
var command = new Command("hash-file");
|
||||
command.Add(new Option<AbsolutePath>(new[] {"-i", "-input"}, "Path to the file to hash"));
|
||||
command.Description = "Hashes a file with Wabbajack's xxHash64 implementation";
|
||||
command.Handler = CommandHandler.Create(Run);
|
||||
return command;
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected override ICommandHandler GetHandler()
|
||||
{
|
||||
return CommandHandler.Create(Run);
|
||||
}
|
||||
|
||||
public async Task<int> Run(AbsolutePath input)
|
||||
{
|
||||
await using var istream = input.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
var hash = await istream.HashingCopy(Stream.Null, CancellationToken.None);
|
||||
_logger.LogInformation($"{input} hash: {hash} {hash.ToHex()} {(long) hash}");
|
||||
_logger.LogInformation("{Input} hash: {Hash} {HashAsHex} {HashAsLong}", input, hash, hash.ToHex(), (long)hash);
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
using System.CommandLine;
|
||||
|
||||
namespace Wabbajack.CLI.Verbs;
|
||||
|
||||
public interface IVerb
|
||||
{
|
||||
public Command MakeCommand();
|
||||
}
|
44
Wabbajack.CLI/Verbs/ManualDownload.cs
Normal file
44
Wabbajack.CLI/Verbs/ManualDownload.cs
Normal file
@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.CommandLine;
|
||||
using System.CommandLine.Invocation;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Wabbajack.Networking.Browser;
|
||||
using Wabbajack.Paths;
|
||||
using Wabbajack.RateLimiter;
|
||||
|
||||
namespace Wabbajack.CLI.Verbs;
|
||||
|
||||
public class ManualDownload
|
||||
{
|
||||
private readonly ILogger<ManualDownload> _logger;
|
||||
private readonly Client _client;
|
||||
private readonly IResource<HttpClient> _limiter;
|
||||
|
||||
public ManualDownload(ILogger<ManualDownload> logger, Client client, IResource<HttpClient> limiter)
|
||||
{
|
||||
_logger = logger;
|
||||
_client = client;
|
||||
_limiter = limiter;
|
||||
}
|
||||
public Command MakeCommand()
|
||||
{
|
||||
var command = new Command("manual-download");
|
||||
command.Add(new Option<AbsolutePath>(new[] {"-p", "-prompt"}, "Text prompt to show the user"));
|
||||
command.Add(new Option<AbsolutePath>(new[] {"-u", "-url"}, "Uri to show the user"));
|
||||
command.Add(new Option<AbsolutePath>(new[] {"-o", "-outputPath"}, "Output Path for the downloaded file"));
|
||||
command.Description = "Shows a browser and instructs the user to download a file, exist when the file is downloaded";
|
||||
command.Handler = CommandHandler.Create(Run);
|
||||
return command;
|
||||
}
|
||||
|
||||
public async Task<int> Run(string prompt, Uri url, AbsolutePath outputPath, CancellationToken token)
|
||||
{
|
||||
_logger.LogInformation("Opening browser");
|
||||
using var job = await _limiter.Begin($"Downloading {url}", 0, token);
|
||||
await _client.ManualDownload(prompt, url, outputPath, token, job);
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@ using Wabbajack.Paths;
|
||||
|
||||
namespace Wabbajack.CLI.Verbs;
|
||||
|
||||
public class MirrorFile : IVerb
|
||||
public class MirrorFile : AVerb
|
||||
{
|
||||
private readonly ILogger<MirrorFile> _logger;
|
||||
private readonly Client _client;
|
||||
@ -17,12 +17,11 @@ public class MirrorFile : IVerb
|
||||
_logger = logger;
|
||||
_client = wjClient;
|
||||
}
|
||||
public Command MakeCommand()
|
||||
public static Command MakeCommand()
|
||||
{
|
||||
var command = new Command("mirror-file");
|
||||
command.Add(new Option<AbsolutePath>(new[] {"-i", "-input"}, "File to Mirror"));
|
||||
command.Description = "Mirrors a file to the Wabbajack CDN";
|
||||
command.Handler = CommandHandler.Create(Run);
|
||||
return command;
|
||||
}
|
||||
|
||||
@ -34,5 +33,9 @@ public class MirrorFile : IVerb
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
protected override ICommandHandler GetHandler()
|
||||
{
|
||||
return CommandHandler.Create(Run);
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@ using Wabbajack.Paths;
|
||||
|
||||
namespace Wabbajack.CLI.Verbs;
|
||||
|
||||
public class SteamDownloadFile : IVerb
|
||||
public class SteamDownloadFile : AVerb
|
||||
{
|
||||
private readonly ILogger<SteamDownloadFile> _logger;
|
||||
private readonly Client _client;
|
||||
@ -33,7 +33,7 @@ public class SteamDownloadFile : IVerb
|
||||
_dtos = dtos;
|
||||
_wjClient = wjClient;
|
||||
}
|
||||
public Command MakeCommand()
|
||||
public static Command MakeCommand()
|
||||
{
|
||||
var command = new Command("steam-download-file");
|
||||
command.Description = "Dumps information to the console about the given app";
|
||||
@ -43,7 +43,6 @@ public class SteamDownloadFile : IVerb
|
||||
command.Add(new Option<string>(new[] {"-v", "-version"}, "Version of the game to download for"));
|
||||
command.Add(new Option<string>(new[] {"-f", "-file"}, "File to download (relative path)"));
|
||||
command.Add(new Option<string>(new[] {"-o", "-output"}, "Output location"));
|
||||
command.Handler = CommandHandler.Create(Run);
|
||||
return command;
|
||||
}
|
||||
|
||||
@ -93,4 +92,9 @@ public class SteamDownloadFile : IVerb
|
||||
|
||||
|
||||
}
|
||||
|
||||
protected override ICommandHandler GetHandler()
|
||||
{
|
||||
return CommandHandler.Create(Run);
|
||||
}
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
using System;
|
||||
using System.CommandLine;
|
||||
using System.CommandLine.Invocation;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using SteamKit2;
|
||||
using Wabbajack.DTOs;
|
||||
using Wabbajack.DTOs.JsonConverters;
|
||||
using Wabbajack.Networking.Http.Interfaces;
|
||||
using Wabbajack.Networking.Steam;
|
||||
using JsonSerializer = System.Text.Json.JsonSerializer;
|
||||
|
||||
namespace Wabbajack.CLI.Verbs;
|
||||
|
||||
public class SteamAppDumpInfo : IVerb
|
||||
{
|
||||
private readonly ILogger<SteamAppDumpInfo> _logger;
|
||||
private readonly Client _client;
|
||||
private readonly ITokenProvider<SteamLoginState> _token;
|
||||
private readonly DepotDownloader _downloader;
|
||||
private readonly DTOSerializer _dtos;
|
||||
|
||||
public SteamAppDumpInfo(ILogger<SteamAppDumpInfo> logger, Client steamClient, ITokenProvider<SteamLoginState> token,
|
||||
DepotDownloader downloader, DTOSerializer dtos)
|
||||
{
|
||||
_logger = logger;
|
||||
_client = steamClient;
|
||||
_token = token;
|
||||
_downloader = downloader;
|
||||
_dtos = dtos;
|
||||
}
|
||||
public Command MakeCommand()
|
||||
{
|
||||
var command = new Command("steam-app-dump-info");
|
||||
command.Description = "Dumps information to the console about the given app";
|
||||
|
||||
command.Add(new Option<string>(new[] {"-g", "-game", "-gameName"}, "Wabbajack game name"));
|
||||
command.Handler = CommandHandler.Create(Run);
|
||||
return command;
|
||||
}
|
||||
|
||||
public async Task<int> Run(string gameName)
|
||||
{
|
||||
if (!GameRegistry.TryGetByFuzzyName(gameName, out var game))
|
||||
{
|
||||
_logger.LogError("Can't find game {GameName} in game registry", gameName);
|
||||
return 1;
|
||||
}
|
||||
|
||||
await _client.Login();
|
||||
var appId = (uint) game.SteamIDs.First();
|
||||
|
||||
if (!await _downloader.AccountHasAccess(appId))
|
||||
{
|
||||
_logger.LogError("Your account does not have access to this Steam App");
|
||||
return 1;
|
||||
}
|
||||
|
||||
var appData = await _downloader.GetAppInfo((uint)game.SteamIDs.First());
|
||||
|
||||
Console.WriteLine("App Depots: ");
|
||||
|
||||
Console.WriteLine(_dtos.Serialize(appData, true));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -9,7 +9,7 @@ using Wabbajack.Paths;
|
||||
|
||||
namespace Wabbajack.CLI.Verbs;
|
||||
|
||||
public class SteamLogin : IVerb
|
||||
public class SteamLogin : AVerb
|
||||
{
|
||||
private readonly ILogger<SteamLogin> _logger;
|
||||
private readonly Client _client;
|
||||
@ -21,13 +21,12 @@ public class SteamLogin : IVerb
|
||||
_client = steamClient;
|
||||
_token = token;
|
||||
}
|
||||
public Command MakeCommand()
|
||||
public static Command MakeCommand()
|
||||
{
|
||||
var command = new Command("steam-login");
|
||||
command.Description = "Logs into Steam via interactive prompts";
|
||||
|
||||
command.Add(new Option<string>(new[] {"-u", "-user"}, "Username for login"));
|
||||
command.Handler = CommandHandler.Create(Run);
|
||||
return command;
|
||||
}
|
||||
|
||||
@ -54,5 +53,9 @@ public class SteamLogin : IVerb
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
protected override ICommandHandler GetHandler()
|
||||
{
|
||||
return CommandHandler.Create(Run);
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ using Wabbajack.Paths.IO;
|
||||
|
||||
namespace Wabbajack.CLI.Verbs;
|
||||
|
||||
public class UploadToNexus : IVerb
|
||||
public class UploadToNexus : AVerb
|
||||
{
|
||||
private readonly ILogger<UploadToNexus> _logger;
|
||||
private readonly NexusApi _client;
|
||||
@ -25,12 +25,11 @@ public class UploadToNexus : IVerb
|
||||
_client = wjClient;
|
||||
_dtos = dtos;
|
||||
}
|
||||
public Command MakeCommand()
|
||||
public static Command MakeCommand()
|
||||
{
|
||||
var command = new Command("upload-to-nexus");
|
||||
command.Add(new Option<AbsolutePath>(new[] {"-d", "-definition"}, "Definition JSON file"));
|
||||
command.Description = "Uploads a file to the Nexus defined by the given .json definition file";
|
||||
command.Handler = CommandHandler.Create(Run);
|
||||
return command;
|
||||
}
|
||||
|
||||
@ -43,5 +42,9 @@ public class UploadToNexus : IVerb
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
protected override ICommandHandler GetHandler()
|
||||
{
|
||||
return CommandHandler.Create(Run);
|
||||
}
|
||||
}
|
@ -7,22 +7,20 @@ using Wabbajack.VFS;
|
||||
|
||||
namespace Wabbajack.CLI.Verbs;
|
||||
|
||||
public class VFSIndexFolder : IVerb
|
||||
public class VfsIndexFolder : AVerb
|
||||
{
|
||||
private readonly Context _context;
|
||||
|
||||
public VFSIndexFolder(Context context)
|
||||
public VfsIndexFolder(Context context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public Command MakeCommand()
|
||||
public static Command MakeCommand()
|
||||
{
|
||||
var command = new Command("vfs-index");
|
||||
command.Add(new Option<AbsolutePath>(new[] {"-f", "--folder"}, "Folder to index"));
|
||||
command.Description = "Index and cache the contents of a folder";
|
||||
|
||||
command.Handler = CommandHandler.Create(Run);
|
||||
return command;
|
||||
}
|
||||
|
||||
@ -31,4 +29,9 @@ public class VFSIndexFolder : IVerb
|
||||
await _context.AddRoot(folder, CancellationToken.None);
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override ICommandHandler GetHandler()
|
||||
{
|
||||
return CommandHandler.Create(Run);
|
||||
}
|
||||
}
|
@ -35,7 +35,7 @@ using Wabbajack.Server.Lib.TokenProviders;
|
||||
|
||||
namespace Wabbajack.CLI.Verbs;
|
||||
|
||||
public class ValidateLists : IVerb
|
||||
public class ValidateLists : AVerb
|
||||
{
|
||||
private static readonly Uri MirrorPrefix = new("https://mirror.wabbajack.org");
|
||||
private readonly WriteOnlyClient _discord;
|
||||
@ -70,7 +70,7 @@ public class ValidateLists : IVerb
|
||||
_random = new Random();
|
||||
}
|
||||
|
||||
public Command MakeCommand()
|
||||
public static Command MakeCommand()
|
||||
{
|
||||
var command = new Command("validate-lists");
|
||||
command.Add(new Option<List[]>(new[] {"-l", "-lists"}, "Lists of lists to validate") {IsRequired = true});
|
||||
@ -84,7 +84,6 @@ public class ValidateLists : IVerb
|
||||
{IsRequired = false});
|
||||
|
||||
command.Description = "Gets a list of modlists, validates them and exports a result list";
|
||||
command.Handler = CommandHandler.Create(Run);
|
||||
return command;
|
||||
}
|
||||
|
||||
@ -514,4 +513,9 @@ public class ValidateLists : IVerb
|
||||
await client.ConnectAsync(token);
|
||||
return client;
|
||||
}
|
||||
|
||||
protected override ICommandHandler GetHandler()
|
||||
{
|
||||
return CommandHandler.Create(Run);
|
||||
}
|
||||
}
|
@ -24,6 +24,7 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Wabbajack.Downloaders.Dispatcher\Wabbajack.Downloaders.Dispatcher.csproj" />
|
||||
<ProjectReference Include="..\Wabbajack.Hashing.xxHash64\Wabbajack.Hashing.xxHash64.csproj" />
|
||||
<ProjectReference Include="..\Wabbajack.Networking.Browser\Wabbajack.Networking.Browser.csproj" />
|
||||
<ProjectReference Include="..\Wabbajack.Networking.Discord\Wabbajack.Networking.Discord.csproj" />
|
||||
<ProjectReference Include="..\Wabbajack.Networking.GitHub\Wabbajack.Networking.GitHub.csproj" />
|
||||
<ProjectReference Include="..\Wabbajack.Paths.IO\Wabbajack.Paths.IO.csproj" />
|
||||
|
@ -8,4 +8,5 @@ public class DownloadProgress : IMessage
|
||||
public bool IsDone { get; set; }
|
||||
public long BytesPerSecond { get; set; }
|
||||
public long BytesCompleted { get; set; }
|
||||
public long? ExpectedSize { get; set; }
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
@ -10,6 +12,8 @@ using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
using Wabbajack.DTOs.BrowserMessages;
|
||||
using Wabbajack.DTOs.JsonConverters;
|
||||
using Wabbajack.Networking.Browser.ViewModels;
|
||||
using Wabbajack.Networking.Browser.Views;
|
||||
|
||||
@ -52,6 +56,22 @@ namespace Wabbajack.Networking.Browser
|
||||
}
|
||||
|
||||
base.OnFrameworkInitializationCompleted();
|
||||
|
||||
|
||||
var dtos = Services.GetRequiredService<DTOSerializer>();
|
||||
var msgProcessor = Task.Run(async () =>
|
||||
{
|
||||
await using var input = Console.OpenStandardInput();
|
||||
while (true)
|
||||
{
|
||||
var msg = await JsonSerializer.DeserializeAsync<IMessage>(input);
|
||||
switch (msg)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private void Startup(object sender, ControlledApplicationLifetimeStartupEventArgs e)
|
||||
|
@ -46,7 +46,6 @@ class CustomGlue : AvaloniaWebViewGlue
|
||||
|
||||
protected override void OnDownloadUpdated(CefBrowser browser, CefDownloadItem downloadItem, CefDownloadItemCallback callback)
|
||||
{
|
||||
downloadItem.
|
||||
base.OnDownloadUpdated(browser, downloadItem, callback);
|
||||
}
|
||||
}
|
@ -6,8 +6,6 @@ using Avalonia.Threading;
|
||||
using CefNet;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Wabbajack.CLI.TypeConverters;
|
||||
using Wabbajack.CLI.Verbs;
|
||||
using Wabbajack.Networking.Browser.Verbs;
|
||||
using Wabbajack.Networking.Browser.ViewModels;
|
||||
using Wabbajack.Networking.Browser.Views;
|
||||
using Wabbajack.Paths;
|
||||
@ -33,11 +31,7 @@ public static class ServiceExtensions
|
||||
var resources = KnownFolders.EntryPoint;
|
||||
services.AddSingleton<MainWindow>();
|
||||
services.AddSingleton<MainWindowViewModel>();
|
||||
|
||||
services.AddSingleton<IVerb, NexusLogin>();
|
||||
services.AddSingleton<IVerb, LoverLabLogin>();
|
||||
services.AddSingleton<IVerb, VectorPlexusLogin>();
|
||||
services.AddSingleton<IVerb, ManualDownload>();
|
||||
|
||||
services.AddOSIntegrated();
|
||||
|
||||
services.AddSingleton(s => new CefSettings
|
||||
|
@ -1,136 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.CommandLine;
|
||||
using System.CommandLine.Invocation;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using CefNet;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Wabbajack.CLI.Verbs;
|
||||
using Wabbajack.DTOs.Logins;
|
||||
using Wabbajack.Services.OSIntegrated;
|
||||
|
||||
namespace Wabbajack.Networking.Browser.Verbs;
|
||||
|
||||
public abstract class AOAuthLoginVerb<TLoginType> : AVerb
|
||||
where TLoginType : OAuth2LoginState, new()
|
||||
{
|
||||
private readonly EncryptedJsonTokenProvider<TLoginType> _tokenProvider;
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly string _namePrefix;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public AOAuthLoginVerb(ILogger logger, string namePrefix, EncryptedJsonTokenProvider<TLoginType> tokenProvider, HttpClient client)
|
||||
{
|
||||
_logger = logger;
|
||||
_tokenProvider = tokenProvider;
|
||||
_httpClient = client;
|
||||
_namePrefix = namePrefix;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override Command MakeCommand()
|
||||
{
|
||||
var textInfo = new CultureInfo("en-US", false).TextInfo;
|
||||
var command = new Command($"{_namePrefix}-login");
|
||||
command.Description = $"Prompt the user to log into {textInfo.ToTitleCase(_namePrefix.Replace("-", " "))}";
|
||||
command.Handler = CommandHandler.Create(Run);
|
||||
return command;
|
||||
}
|
||||
|
||||
private async Task Run(CancellationToken token)
|
||||
{
|
||||
var tlogin = new TLoginType();
|
||||
|
||||
await Browser.WaitForReady();
|
||||
|
||||
var handler = new AsyncSchemeHandler();
|
||||
Browser.RequestContext.RegisterSchemeHandlerFactory("wabbajack", "", handler);
|
||||
|
||||
Instructions = $"Please log in and allow Wabbajack to access your {tlogin.SiteName} account";
|
||||
|
||||
var scopes = string.Join(" ", tlogin.Scopes);
|
||||
var state = Guid.NewGuid().ToString();
|
||||
|
||||
await Browser.NavigateTo(new Uri(tlogin.AuthorizationEndpoint +
|
||||
$"?response_type=code&client_id={tlogin.ClientID}&state={state}&scope={scopes}"));
|
||||
|
||||
var uri = await handler.Task.WaitAsync(token);
|
||||
|
||||
var cookies = await Browser.Cookies(tlogin.AuthorizationEndpoint.Host, token);
|
||||
|
||||
var parsed = HttpUtility.ParseQueryString(uri.Query);
|
||||
if (parsed.Get("state") != state)
|
||||
{
|
||||
_logger.LogCritical("Bad OAuth state, this shouldn't happen");
|
||||
throw new Exception("Bad OAuth State");
|
||||
}
|
||||
|
||||
if (parsed.Get("code") == null)
|
||||
{
|
||||
_logger.LogCritical("Bad code result from OAuth");
|
||||
throw new Exception("Bad code result from OAuth");
|
||||
}
|
||||
|
||||
var authCode = parsed.Get("code");
|
||||
|
||||
var formData = new KeyValuePair<string?, string?>[]
|
||||
{
|
||||
new("grant_type", "authorization_code"),
|
||||
new("code", authCode),
|
||||
new("client_id", tlogin.ClientID)
|
||||
};
|
||||
|
||||
var msg = new HttpRequestMessage();
|
||||
msg.Method = HttpMethod.Post;
|
||||
msg.RequestUri = tlogin.TokenEndpoint;
|
||||
msg.Headers.Add("User-Agent",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36");
|
||||
msg.Headers.Add("Cookie", string.Join(";", cookies.Select(c => $"{c.Name}={c.Value}")));
|
||||
msg.Content = new FormUrlEncodedContent(formData.ToList());
|
||||
|
||||
using var response = await _httpClient.SendAsync(msg, token);
|
||||
var data = await response.Content.ReadFromJsonAsync<OAuthResultState>(cancellationToken: token);
|
||||
|
||||
await _tokenProvider.SetToken(new TLoginType
|
||||
{
|
||||
Cookies = cookies,
|
||||
ResultState = data!
|
||||
});
|
||||
}
|
||||
|
||||
private class AsyncSchemeHandler : CefSchemeHandlerFactory
|
||||
{
|
||||
private readonly TaskCompletionSource<Uri> _tcs = new();
|
||||
|
||||
public Task<Uri> Task => _tcs.Task;
|
||||
|
||||
protected override CefResourceHandler Create(CefBrowser browser, CefFrame frame, string schemeName,
|
||||
CefRequest request)
|
||||
{
|
||||
return new Handler(_tcs);
|
||||
}
|
||||
}
|
||||
|
||||
private class Handler : CefResourceHandler
|
||||
{
|
||||
private readonly TaskCompletionSource<Uri> _tcs;
|
||||
|
||||
public Handler(TaskCompletionSource<Uri> tcs)
|
||||
{
|
||||
_tcs = tcs;
|
||||
}
|
||||
|
||||
protected override bool ProcessRequest(CefRequest request, CefCallback callback)
|
||||
{
|
||||
_tcs.TrySetResult(new Uri(request.Url));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
using System.CommandLine;
|
||||
using Avalonia.Threading;
|
||||
using CefNet.Avalonia;
|
||||
using ReactiveUI;
|
||||
using Wabbajack.Networking.Browser;
|
||||
|
||||
namespace Wabbajack.CLI.Verbs;
|
||||
|
||||
public abstract class AVerb : IVerb
|
||||
{
|
||||
public abstract Command MakeCommand();
|
||||
|
||||
public string Instructions
|
||||
{
|
||||
set
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
|
||||
Program.MainWindowVM.Instructions = value;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public WebView Browser => Program.MainWindow.Browser;
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
using System.CommandLine;
|
||||
|
||||
namespace Wabbajack.CLI.Verbs;
|
||||
|
||||
public interface IVerb
|
||||
{
|
||||
public Command MakeCommand();
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
using System.Net.Http;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Wabbajack.DTOs.Logins;
|
||||
using Wabbajack.Services.OSIntegrated;
|
||||
|
||||
namespace Wabbajack.Networking.Browser.Verbs;
|
||||
|
||||
public class LoverLabLogin : AOAuthLoginVerb<LoversLabLoginState>
|
||||
{
|
||||
public LoverLabLogin(ILogger<LoverLabLogin> logger, EncryptedJsonTokenProvider<LoversLabLoginState> tokenProvider, HttpClient client) :
|
||||
base(logger, "vector-plexus", tokenProvider, client)
|
||||
{
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
using System;
|
||||
using System.CommandLine;
|
||||
using System.CommandLine.Invocation;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Wabbajack.CLI.Verbs;
|
||||
using Wabbajack.Paths;
|
||||
using Wabbajack.Paths.IO;
|
||||
using Wabbajack.Services.OSIntegrated;
|
||||
|
||||
namespace Wabbajack.Networking.Browser.Verbs;
|
||||
|
||||
public class ManualDownload : AVerb
|
||||
{
|
||||
private readonly ILogger<ManualDownload> _logger;
|
||||
|
||||
public ManualDownload(ILogger<ManualDownload> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
|
||||
}
|
||||
|
||||
public override Command MakeCommand()
|
||||
{
|
||||
var command = new Command("manual-download");
|
||||
command.Description = "Prompt the user to download a file";
|
||||
command.Add(new Option<Uri>(new[] {"-u", "-url"}, "Uri"));
|
||||
command.Add(new Option<AbsolutePath>);
|
||||
command.Handler = CommandHandler.Create(Run);
|
||||
return command;
|
||||
}
|
||||
|
||||
public async Task<int> Run(Uri url)
|
||||
{
|
||||
await Browser.WaitForReady();
|
||||
await Browser.NavigateTo(url);
|
||||
|
||||
|
||||
await Task.Delay(100000);
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
using System;
|
||||
using System.CommandLine;
|
||||
using System.CommandLine.Invocation;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Fizzler.Systems.HtmlAgilityPack;
|
||||
using ReactiveUI;
|
||||
using Wabbajack.CLI.Verbs;
|
||||
using Wabbajack.DTOs.Logins;
|
||||
using Wabbajack.Networking.Http.Interfaces;
|
||||
|
||||
namespace Wabbajack.Networking.Browser.Verbs;
|
||||
|
||||
public class NexusLogin : AVerb
|
||||
{
|
||||
private readonly ITokenProvider<NexusApiState> _tokenProvider;
|
||||
|
||||
public NexusLogin(ITokenProvider<NexusApiState> tokenProvider)
|
||||
{
|
||||
_tokenProvider = tokenProvider;
|
||||
}
|
||||
public override Command MakeCommand()
|
||||
{
|
||||
var command = new Command("nexus-login");
|
||||
command.Description = "Prompt the user to log into the nexus";
|
||||
command.Handler = CommandHandler.Create(Run);
|
||||
return command;
|
||||
}
|
||||
|
||||
private async Task Run(CancellationToken token)
|
||||
{
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
Instructions = "Please log into the Nexus";
|
||||
|
||||
await Browser.WaitForReady();
|
||||
|
||||
await Browser.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"));
|
||||
|
||||
Cookie[] cookies = { };
|
||||
while (true)
|
||||
{
|
||||
cookies = await Browser.Cookies("nexusmods.com", token);
|
||||
if (cookies.Any(c => c.Name == "member_id"))
|
||||
break;
|
||||
|
||||
token.ThrowIfCancellationRequested();
|
||||
await Task.Delay(500, token);
|
||||
}
|
||||
|
||||
Instructions = "Getting API Key...";
|
||||
|
||||
await Browser.NavigateTo(new Uri("https://www.nexusmods.com/users/myaccount?tab=api"));
|
||||
|
||||
|
||||
await Browser.NavigateTo(new Uri("https://www.nexusmods.com/users/myaccount?tab=api"));
|
||||
|
||||
var key = "";
|
||||
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
key = (await Browser.GetDom(token))
|
||||
.DocumentNode
|
||||
.QuerySelectorAll("input[value=wabbajack]")
|
||||
.SelectMany(p => p.ParentNode.ParentNode.QuerySelectorAll("textarea.application-key"))
|
||||
.Select(node => node.InnerHtml)
|
||||
.FirstOrDefault() ?? "";
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
break;
|
||||
|
||||
try
|
||||
{
|
||||
await Browser.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;"
|
||||
);
|
||||
Instructions = "Generating API Key, Please Wait...";
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
token.ThrowIfCancellationRequested();
|
||||
}
|
||||
|
||||
Instructions = "Success, saving information...";
|
||||
await _tokenProvider.SetToken(new NexusApiState
|
||||
{
|
||||
Cookies = cookies,
|
||||
ApiKey = key
|
||||
});
|
||||
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
using System.Net.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Wabbajack.DTOs.Logins;
|
||||
using Wabbajack.Services.OSIntegrated;
|
||||
|
||||
namespace Wabbajack.Networking.Browser.Verbs;
|
||||
|
||||
public class VectorPlexusLogin : AOAuthLoginVerb<VectorPlexusLoginState>
|
||||
{
|
||||
public VectorPlexusLogin(ILogger<LoverLabLogin> logger, EncryptedJsonTokenProvider<VectorPlexusLoginState> tokenProvider, HttpClient client) :
|
||||
base(logger, "lovers-lab", tokenProvider, client)
|
||||
{
|
||||
}
|
||||
}
|
@ -1,44 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.CommandLine;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using ReactiveUI;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using Wabbajack.CLI.Verbs;
|
||||
using Wabbajack.Common;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
|
||||
namespace Wabbajack.Networking.Browser.ViewModels
|
||||
{
|
||||
public class MainWindowViewModel : ViewModelBase
|
||||
{
|
||||
private readonly IEnumerable<IVerb> _verbs;
|
||||
|
||||
public MainWindowViewModel(IEnumerable<IVerb> verbs)
|
||||
public MainWindowViewModel()
|
||||
{
|
||||
_verbs = verbs;
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
ExecuteCommand().FireAndForget();
|
||||
Disposable.Empty.DisposeWith(disposables);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
[Reactive]
|
||||
public string Instructions { get; set; }
|
||||
|
||||
private async Task ExecuteCommand()
|
||||
{
|
||||
while (Program.MainWindow.Browser == null)
|
||||
await Task.Delay(250);
|
||||
|
||||
var root = new RootCommand();
|
||||
foreach (var verb in _verbs)
|
||||
root.Add(verb.MakeCommand());
|
||||
|
||||
var code = await root.InvokeAsync(Program.Args);
|
||||
Environment.Exit(code);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.CommandLine;
|
||||
using System.Reactive.Linq;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Mixins;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.ReactiveUI;
|
||||
using Avalonia.Threading;
|
||||
using CefNet.Avalonia;
|
||||
using ReactiveUI;
|
||||
using Wabbajack.CLI.Verbs;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Networking.Browser.ViewModels;
|
||||
|
||||
namespace Wabbajack.Networking.Browser.Views
|
||||
|
@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>10</LangVersion>
|
||||
|
65
Wabbajack.Networking.Browser/Client.cs
Normal file
65
Wabbajack.Networking.Browser/Client.cs
Normal file
@ -0,0 +1,65 @@
|
||||
using System.Diagnostics;
|
||||
using System.Text.Json;
|
||||
using Wabbajack.DTOs.BrowserMessages;
|
||||
using Wabbajack.DTOs.JsonConverters;
|
||||
using Wabbajack.Paths;
|
||||
using Wabbajack.RateLimiter;
|
||||
|
||||
namespace Wabbajack.Networking.Browser;
|
||||
|
||||
|
||||
public class Client
|
||||
{
|
||||
private readonly Configuration _config;
|
||||
private readonly DTOSerializer _dtos;
|
||||
|
||||
public Client(Configuration config, DTOSerializer dtos)
|
||||
{
|
||||
_config = config;
|
||||
_dtos = dtos;
|
||||
}
|
||||
|
||||
public async Task ManualDownload(string prompt, Uri uri, AbsolutePath dest, CancellationToken token, IJob job)
|
||||
{
|
||||
var process = new Process()
|
||||
{
|
||||
StartInfo = new ProcessStartInfo()
|
||||
{
|
||||
FileName = _config.HostExecutable.ToString(),
|
||||
RedirectStandardError = true,
|
||||
RedirectStandardInput = true,
|
||||
RedirectStandardOutput = true
|
||||
}
|
||||
};
|
||||
|
||||
var ptask = process.Start();
|
||||
|
||||
var reader = Task.Run(async () =>
|
||||
{
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
var msg = await JsonSerializer.DeserializeAsync<IMessage>(process.StandardOutput.BaseStream,
|
||||
_dtos.Options, token);
|
||||
if (msg is DownloadProgress dp)
|
||||
{
|
||||
job.ReportNoWait((int) dp.BytesCompleted);
|
||||
job.Size = dp.ExpectedSize;
|
||||
if (dp.IsDone)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, token);
|
||||
|
||||
await process.StandardInput.WriteAsync(JsonSerializer.Serialize(new DTOs.BrowserMessages.ManualDownload()
|
||||
{
|
||||
Prompt = prompt,
|
||||
Url = uri,
|
||||
Path = dest
|
||||
}));
|
||||
|
||||
await process.WaitForExitAsync(token);
|
||||
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
using Wabbajack.Paths;
|
||||
using Wabbajack.Paths.IO;
|
||||
|
||||
namespace Wabbajack.Networking.Browser.Client;
|
||||
namespace Wabbajack.Networking.Browser;
|
||||
|
||||
public class Configuration
|
||||
{
|
||||
|
@ -10,4 +10,5 @@ public interface IJob
|
||||
public long Current { get; }
|
||||
public string Description { get; }
|
||||
public ValueTask Report(int processedSize, CancellationToken token);
|
||||
public void ReportNoWait(int processedSize);
|
||||
}
|
Reference in New Issue
Block a user