This commit is contained in:
Timothy Baldridge 2022-01-25 21:54:23 -07:00
parent de64e5f35e
commit a55a64c7a9
34 changed files with 281 additions and 36 deletions

View File

@ -18,6 +18,8 @@ public class ProcessHelper
public readonly Subject<(StreamType Type, string Line)> Output = new Subject<(StreamType Type, string)>(); public readonly Subject<(StreamType Type, string Line)> Output = new Subject<(StreamType Type, string)>();
private readonly Subject<string> _input = new();
public IObserver<string> Input => _input;
public AbsolutePath Path { get; set; } public AbsolutePath Path { get; set; }
public IEnumerable<object> Arguments { get; set; } = Enumerable.Empty<object>(); public IEnumerable<object> Arguments { get; set; } = Enumerable.Empty<object>();
@ -71,6 +73,14 @@ public class ProcessHelper
}; };
p.ErrorDataReceived += ErrorEventHandler; p.ErrorDataReceived += ErrorEventHandler;
var din = _input.Subscribe(s =>
{
lock (p)
{
p.StandardInput.Write(s);
}
});
p.Start(); p.Start();
p.BeginErrorReadLine(); p.BeginErrorReadLine();
@ -91,6 +101,7 @@ public class ProcessHelper
var result = await finished.Task; var result = await finished.Task;
// Do this to make sure everything flushes // Do this to make sure everything flushes
p.WaitForExit(); p.WaitForExit();
din.Dispose();
p.CancelErrorRead(); p.CancelErrorRead();
p.CancelOutputRead(); p.CancelOutputRead();
p.OutputDataReceived -= OutputDataReceived; p.OutputDataReceived -= OutputDataReceived;

View File

@ -1,4 +1,5 @@
using Wabbajack.DTOs.BSA.ArchiveStates; using Wabbajack.DTOs.BrowserMessages;
using Wabbajack.DTOs.BSA.ArchiveStates;
using Wabbajack.DTOs.BSA.FileStates; using Wabbajack.DTOs.BSA.FileStates;
using Wabbajack.DTOs.DownloadStates; using Wabbajack.DTOs.DownloadStates;
@ -13,6 +14,7 @@ internal class Program
new PolymorphicGenerator<IArchive>().GenerateAll(cfile); new PolymorphicGenerator<IArchive>().GenerateAll(cfile);
new PolymorphicGenerator<Directive>().GenerateAll(cfile); new PolymorphicGenerator<Directive>().GenerateAll(cfile);
new PolymorphicGenerator<AFile>().GenerateAll(cfile); new PolymorphicGenerator<AFile>().GenerateAll(cfile);
new PolymorphicGenerator<IMessage>().GenerateAll(cfile);
cfile.Write(@"..\Wabbajack.DTOs\JsonConverters\Generated.cs"); cfile.Write(@"..\Wabbajack.DTOs\JsonConverters\Generated.cs");

View File

@ -0,0 +1,11 @@
using Wabbajack.DTOs.JsonConverters;
namespace Wabbajack.DTOs.BrowserMessages;
[JsonName("DownloadProgress")]
public class DownloadProgress : IMessage
{
public bool IsDone { get; set; }
public long BytesPerSecond { get; set; }
public long BytesCompleted { get; set; }
}

View File

@ -0,0 +1,6 @@
namespace Wabbajack.DTOs.BrowserMessages;
public interface IMessage
{
}

View File

@ -0,0 +1,16 @@
using System;
using Wabbajack.DTOs.JsonConverters;
using Wabbajack.Paths;
namespace Wabbajack.DTOs.BrowserMessages;
/// <summary>
/// Show a manual download page for the given Url
/// </summary>
[JsonName("ManualDownload")]
public class ManualDownload : IMessage
{
public string Prompt { get; set; }
public Uri Url { get; set; }
public AbsolutePath Path { get; set; }
}

View File

@ -0,0 +1,9 @@
using Wabbajack.DTOs.JsonConverters;
namespace Wabbajack.DTOs.BrowserMessages;
[JsonName("Terminate")]
public class Terminate : IMessage
{
}

View File

Before

Width:  |  Height:  |  Size: 172 KiB

After

Width:  |  Height:  |  Size: 172 KiB

View File

@ -54,6 +54,7 @@ navigator.__proto__ = newProto;
}", frame.Url, 0); }", frame.Url, 0);
} }
protected override void OnCefProcessMessageReceived(CefProcessMessageReceivedEventArgs e) protected override void OnCefProcessMessageReceived(CefProcessMessageReceivedEventArgs e)
{ {
base.OnCefProcessMessageReceived(e); base.OnCefProcessMessageReceived(e);

View File

@ -0,0 +1,52 @@
using System;
using CefNet;
using CefNet.Avalonia;
using CefNet.Internal;
using Wabbajack.Paths;
namespace Wabbajack.Networking.Browser;
public class CustomWebView : WebView
{
private CustomGlue Glue { get; }
public CustomWebView() : base()
{
Glue = new CustomGlue(this);
}
protected override WebViewGlue CreateWebViewGlue()
{
return Glue;
}
}
class CustomGlue : AvaloniaWebViewGlue
{
private readonly CustomWebView _view;
public Func<Uri, AbsolutePath>? RedirectDownloadsFn { get; set; }
public CustomGlue(CustomWebView view) : base(view)
{
_view = view;
}
protected override void OnBeforeDownload(CefBrowser browser, CefDownloadItem downloadItem, string suggestedName,
CefBeforeDownloadCallback callback)
{
if (RedirectDownloadsFn == null)
{
base.OnBeforeDownload(browser, downloadItem, suggestedName, callback);
return;
}
var path = RedirectDownloadsFn!(new Uri(downloadItem.OriginalUrl));
callback.Continue(path.ToString(), false);
}
protected override void OnDownloadUpdated(CefBrowser browser, CefDownloadItem downloadItem, CefDownloadItemCallback callback)
{
downloadItem.
base.OnDownloadUpdated(browser, downloadItem, callback);
}
}

View File

@ -1,13 +1,16 @@
using System; using System;
using System.ComponentModel;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Threading; using Avalonia.Threading;
using CefNet; using CefNet;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Wabbajack.CLI.TypeConverters;
using Wabbajack.CLI.Verbs; using Wabbajack.CLI.Verbs;
using Wabbajack.Networking.Browser.Verbs; using Wabbajack.Networking.Browser.Verbs;
using Wabbajack.Networking.Browser.ViewModels; using Wabbajack.Networking.Browser.ViewModels;
using Wabbajack.Networking.Browser.Views; using Wabbajack.Networking.Browser.Views;
using Wabbajack.Paths;
using Wabbajack.Paths.IO; using Wabbajack.Paths.IO;
using Wabbajack.Services.OSIntegrated; using Wabbajack.Services.OSIntegrated;
@ -24,6 +27,9 @@ public static class ServiceExtensions
public static IServiceCollection AddAppServices(this IServiceCollection services) public static IServiceCollection AddAppServices(this IServiceCollection services)
{ {
TypeDescriptor.AddAttributes(typeof(AbsolutePath),
new TypeConverterAttribute(typeof(AbsolutePathTypeConverter)));
var resources = KnownFolders.EntryPoint; var resources = KnownFolders.EntryPoint;
services.AddSingleton<MainWindow>(); services.AddSingleton<MainWindow>();
services.AddSingleton<MainWindowViewModel>(); services.AddSingleton<MainWindowViewModel>();
@ -31,6 +37,7 @@ public static class ServiceExtensions
services.AddSingleton<IVerb, NexusLogin>(); services.AddSingleton<IVerb, NexusLogin>();
services.AddSingleton<IVerb, LoverLabLogin>(); services.AddSingleton<IVerb, LoverLabLogin>();
services.AddSingleton<IVerb, VectorPlexusLogin>(); services.AddSingleton<IVerb, VectorPlexusLogin>();
services.AddSingleton<IVerb, ManualDownload>();
services.AddOSIntegrated(); services.AddOSIntegrated();
services.AddSingleton(s => new CefSettings services.AddSingleton(s => new CefSettings

View File

@ -0,0 +1,25 @@
using System;
using System.ComponentModel;
using System.Globalization;
using Wabbajack.Paths;
namespace Wabbajack.CLI.TypeConverters;
public class AbsolutePathTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value,
Type destinationType)
{
return (AbsolutePath) (string) value;
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return (AbsolutePath) (string) value;
}
}

View File

@ -0,0 +1,25 @@
using System;
using System.ComponentModel;
using System.Globalization;
using Wabbajack.DTOs.GitHub;
namespace Wabbajack.Networking.Browser.TypeConverters;
public class ModListCategoryConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value,
Type destinationType)
{
throw new NotImplementedException();
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return Enum.Parse<List>((string) value);
}
}

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.CommandLine; using System.CommandLine;
using System.CommandLine.Invocation; using System.CommandLine.Invocation;
using System.Globalization;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Json; using System.Net.Http.Json;
@ -36,8 +37,9 @@ where TLoginType : OAuth2LoginState, new()
public override Command MakeCommand() public override Command MakeCommand()
{ {
var textInfo = new CultureInfo("en-US", false).TextInfo;
var command = new Command($"{_namePrefix}-login"); var command = new Command($"{_namePrefix}-login");
command.Description = "Prompt the user to log into the nexus"; command.Description = $"Prompt the user to log into {textInfo.ToTitleCase(_namePrefix.Replace("-", " "))}";
command.Handler = CommandHandler.Create(Run); command.Handler = CommandHandler.Create(Run);
return command; return command;
} }

View File

@ -0,0 +1,42 @@
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;
}
}

View File

@ -6,10 +6,11 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:avalonia="clr-namespace:CefNet.Avalonia;assembly=CefNet.Avalonia" xmlns:avalonia="clr-namespace:CefNet.Avalonia;assembly=CefNet.Avalonia"
xmlns:reactiveUi="http://reactiveui.net" xmlns:reactiveUi="http://reactiveui.net"
xmlns:browser="clr-namespace:Wabbajack.Networking.Browser"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="600" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="600"
x:Class="Wabbajack.Networking.Browser.Views.MainWindow" x:Class="Wabbajack.Networking.Browser.Views.MainWindow"
Icon="/Assets/avalonia-logo.ico" Icon="/Assets/avalonia-logo.ico"
Title="Wabbajack.Networking.Browser" Title="Wabbajack.Networking.Browser.Host"
Width="800" Width="800"
Height="600" Height="600"
@ -25,6 +26,6 @@
<Grid RowDefinitions="Auto, *" <Grid RowDefinitions="Auto, *"
ColumnDefinitions="Auto, *"> ColumnDefinitions="Auto, *">
<TextBlock Grid.Row="0" Grid.Column="0" Margin="8" x:Name="Instructions" VerticalAlignment="Center" HorizontalAlignment="Left"></TextBlock> <TextBlock Grid.Row="0" Grid.Column="0" Margin="8" x:Name="Instructions" VerticalAlignment="Center" HorizontalAlignment="Left"></TextBlock>
<avalonia:WebView Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="2" x:FieldModifier="public" x:Name="Browser" Margin="4" InitialUrl="https://www.google.com"></avalonia:WebView> <browser:CustomWebView Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="2" x:FieldModifier="public" x:Name="Browser" Margin="4" InitialUrl="https://www.google.com"></browser:CustomWebView>
</Grid> </Grid>
</reactiveUi:ReactiveWindow> </reactiveUi:ReactiveWindow>

View File

@ -0,0 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<LangVersion>10</LangVersion>
<RootNamespace>Wabbajack.Networking.Browser</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Folder Include="Models\" />
<AvaloniaResource Include="Assets\**" />
<None Remove=".gitignore" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.10" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.10" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="0.10.10" />
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.10" />
<PackageReference Include="CefNet.Avalonia" Version="97.1.22018.1433" />
<PackageReference Include="Fizzler.Systems.HtmlAgilityPack" Version="1.2.1" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.40" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.2-mauipre.1.22054.8" />
<PackageReference Include="ReactiveUI.Fody" Version="17.1.17" />
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.21561.1" />
<PackageReference Include="XamlNameReferenceGenerator" Version="1.3.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Wabbajack.Common\Wabbajack.Common.csproj" />
<ProjectReference Include="..\Wabbajack.Paths.IO\Wabbajack.Paths.IO.csproj" />
<ProjectReference Include="..\Wabbajack.Services.OSIntegrated\Wabbajack.Services.OSIntegrated.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,10 @@
using Wabbajack.Paths;
using Wabbajack.Paths.IO;
namespace Wabbajack.Networking.Browser.Client;
public class Configuration
{
public AbsolutePath HostExecutable { get; set; } =
KnownFolders.EntryPoint.Combine("Wabbajack.Networking.Browser.Host.exe");
}

View File

@ -1,32 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<LangVersion>latest</LangVersion> <RootNamespace>Wabbajack.Networking.Browser.Client</RootNamespace>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Folder Include="Models\" />
<AvaloniaResource Include="Assets\**" />
<None Remove=".gitignore" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.10" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.10" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="0.10.10" />
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.10" />
<PackageReference Include="CefNet.Avalonia" Version="97.1.22018.1433" />
<PackageReference Include="Fizzler.Systems.HtmlAgilityPack" Version="1.2.1" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.40" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.2-mauipre.1.22054.8" />
<PackageReference Include="ReactiveUI.Fody" Version="17.1.17" />
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.21561.1" />
<PackageReference Include="XamlNameReferenceGenerator" Version="1.3.4" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Wabbajack.Common\Wabbajack.Common.csproj" /> <ProjectReference Include="..\Wabbajack.Common\Wabbajack.Common.csproj" />
<ProjectReference Include="..\Wabbajack.Networking.Browser.Host\Wabbajack.Networking.Browser.Host.csproj" />
<ProjectReference Include="..\Wabbajack.Paths.IO\Wabbajack.Paths.IO.csproj" /> <ProjectReference Include="..\Wabbajack.Paths.IO\Wabbajack.Paths.IO.csproj" />
<ProjectReference Include="..\Wabbajack.Services.OSIntegrated\Wabbajack.Services.OSIntegrated.csproj" /> <ProjectReference Include="..\Wabbajack.Paths\Wabbajack.Paths.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -125,7 +125,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wabbajack.App.Blazor", "Wab
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{18E36813-CB53-4172-8FF3-EFE3B9B30A5F}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{18E36813-CB53-4172-8FF3-EFE3B9B30A5F}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wabbajack.Networking.Browser", "Wabbajack.Networking.Browser\Wabbajack.Networking.Browser.csproj", "{44860A8E-C3E4-4BF0-8EAB-BFA2D6DA217A}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wabbajack.Networking.Browser.Host", "Wabbajack.Networking.Browser.Host\Wabbajack.Networking.Browser.Host.csproj", "{44860A8E-C3E4-4BF0-8EAB-BFA2D6DA217A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wabbajack.Networking.Browser", "Wabbajack.Networking.Browser\Wabbajack.Networking.Browser.csproj", "{860A06B3-AE35-4C69-95E5-EC9E8D6630CF}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -345,6 +347,10 @@ Global
{44860A8E-C3E4-4BF0-8EAB-BFA2D6DA217A}.Debug|Any CPU.Build.0 = Debug|Any CPU {44860A8E-C3E4-4BF0-8EAB-BFA2D6DA217A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{44860A8E-C3E4-4BF0-8EAB-BFA2D6DA217A}.Release|Any CPU.ActiveCfg = Release|Any CPU {44860A8E-C3E4-4BF0-8EAB-BFA2D6DA217A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{44860A8E-C3E4-4BF0-8EAB-BFA2D6DA217A}.Release|Any CPU.Build.0 = Release|Any CPU {44860A8E-C3E4-4BF0-8EAB-BFA2D6DA217A}.Release|Any CPU.Build.0 = Release|Any CPU
{860A06B3-AE35-4C69-95E5-EC9E8D6630CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{860A06B3-AE35-4C69-95E5-EC9E8D6630CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{860A06B3-AE35-4C69-95E5-EC9E8D6630CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{860A06B3-AE35-4C69-95E5-EC9E8D6630CF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -387,6 +393,7 @@ Global
{AB9A5C22-10CC-4EE0-A808-FB1DC9E24247} = {F01F8595-5FD7-4506-8469-F4A5522DACC1} {AB9A5C22-10CC-4EE0-A808-FB1DC9E24247} = {F01F8595-5FD7-4506-8469-F4A5522DACC1}
{D6351587-CAF6-4CB6-A2BD-5368E69F297C} = {F01F8595-5FD7-4506-8469-F4A5522DACC1} {D6351587-CAF6-4CB6-A2BD-5368E69F297C} = {F01F8595-5FD7-4506-8469-F4A5522DACC1}
{44860A8E-C3E4-4BF0-8EAB-BFA2D6DA217A} = {F01F8595-5FD7-4506-8469-F4A5522DACC1} {44860A8E-C3E4-4BF0-8EAB-BFA2D6DA217A} = {F01F8595-5FD7-4506-8469-F4A5522DACC1}
{860A06B3-AE35-4C69-95E5-EC9E8D6630CF} = {F01F8595-5FD7-4506-8469-F4A5522DACC1}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0AA30275-0F38-4A7D-B645-F5505178DDE8} SolutionGuid = {0AA30275-0F38-4A7D-B645-F5505178DDE8}