Whole app now useses Async IO exclusively

This commit is contained in:
Timothy Baldridge 2020-05-25 11:34:25 -06:00
parent 191f321dc2
commit b2a112bd37
37 changed files with 218 additions and 213 deletions

View File

@ -96,16 +96,16 @@ namespace Compression.BSA.Test
var tempFile = ((RelativePath)"tmp.bsa").RelativeToEntryPoint(); var tempFile = ((RelativePath)"tmp.bsa").RelativeToEntryPoint();
var size = bsa.Size; var size = bsa.Size;
await using var a = BSADispatch.OpenRead(bsa); await using var a = await BSADispatch.OpenRead(bsa);
await a.Files.PMap(Queue, file => await a.Files.PMap(Queue, async file =>
{ {
var absName = _tempDir.Combine(file.Path); var absName = _tempDir.Combine(file.Path);
ViaJson(file.State); ViaJson(file.State);
absName.Parent.CreateDirectory(); absName.Parent.CreateDirectory();
using (var fs = absName.Create()) await using (var fs = await absName.Create())
{ {
file.CopyDataTo(fs); await file.CopyDataTo(fs);
} }
Assert.Equal(file.Size, absName.Size); Assert.Equal(file.Size, absName.Size);
@ -123,7 +123,7 @@ namespace Compression.BSA.Test
var streams = await a.Files.PMap(Queue, async file => var streams = await a.Files.PMap(Queue, async file =>
{ {
var absPath = _tempDir.Combine(file.Path); var absPath = _tempDir.Combine(file.Path);
var str = absPath.OpenRead(); var str = await absPath.OpenRead();
await w.AddFile(ViaJson(file.State), str); await w.AddFile(ViaJson(file.State), str);
return str; return str;
}); });
@ -132,7 +132,7 @@ namespace Compression.BSA.Test
} }
TestContext.WriteLine($"Verifying {bsa}"); TestContext.WriteLine($"Verifying {bsa}");
await using var b = BSADispatch.OpenRead(tempFile); await using var b = await BSADispatch.OpenRead(tempFile);
TestContext.WriteLine($"Performing A/B tests on {bsa}"); TestContext.WriteLine($"Performing A/B tests on {bsa}");
Assert.Equal(a.State.ToJson(), b.State.ToJson()); Assert.Equal(a.State.ToJson(), b.State.ToJson());

View File

@ -8,16 +8,16 @@ namespace Wabbajack.Test
[Fact] [Fact]
public async Task CanSaveAndLoadSettings() public async Task CanSaveAndLoadSettings()
{ {
MainSettings.TryLoadTypicalSettings(out var settings); var (settings, loadedSettings) = await MainSettings.TryLoadTypicalSettings();
if (settings == null) if (settings == null || !loadedSettings)
{ {
settings = new MainSettings(); settings = new MainSettings();
} }
MainSettings.SaveSettings(settings); await MainSettings.SaveSettings(settings);
Assert.True(MainSettings.TryLoadTypicalSettings(out settings)); Assert.True((await MainSettings.TryLoadTypicalSettings()).loaded);
} }
} }

View File

@ -14,8 +14,8 @@ namespace Wabbajack.CLI.Verbs
protected override async Task<ExitCode> Run() protected override async Task<ExitCode> Run()
{ {
await using var bsa = BSADispatch.OpenRead(Input.RelativeTo(AbsolutePath.GetCurrentDirectory())); await using var bsa = await BSADispatch.OpenRead(Input.RelativeTo(AbsolutePath.GetCurrentDirectory()));
bsa.Dump(line => Console.WriteLine(line)); bsa.Dump(Console.WriteLine);
return ExitCode.Ok; return ExitCode.Ok;
} }
} }

View File

@ -18,7 +18,7 @@ namespace Wabbajack.CLI.Verbs
protected override async Task<ExitCode> Run() protected override async Task<ExitCode> Run()
{ {
File.ReadAllBytes(Input).ToEcryptedData(Name); await File.ReadAllBytes(Input).ToEcryptedData(Name);
return 0; return 0;
} }
} }

View File

@ -81,10 +81,10 @@ namespace Wabbajack.Lib
return id; return id;
} }
internal FileStream IncludeFile(out RelativePath id) internal AbsolutePath IncludeFile(out RelativePath id)
{ {
id = IncludeId(); id = IncludeId();
return ModListOutputFolder.Combine(id).Create(); return ModListOutputFolder.Combine(id);
} }
internal async Task<RelativePath> IncludeFile(string data) internal async Task<RelativePath> IncludeFile(string data)
@ -144,34 +144,32 @@ namespace Wabbajack.Lib
ModList.Image = (RelativePath)"modlist-image.png"; ModList.Image = (RelativePath)"modlist-image.png";
} }
using (var of = ModListOutputFolder.Combine("modlist").Create()) using (var of = await ModListOutputFolder.Combine("modlist").Create())
ModList.ToJson(of); ModList.ToJson(of);
ModListOutputFile.Delete(); ModListOutputFile.Delete();
using (var fs = ModListOutputFile.Create()) using (var fs = await ModListOutputFile.Create())
{ {
using (var za = new ZipArchive(fs, ZipArchiveMode.Create)) using (var za = new ZipArchive(fs, ZipArchiveMode.Create))
{ {
ModListOutputFolder.EnumerateFiles() await ModListOutputFolder.EnumerateFiles()
.DoProgress("Compressing ModList", .DoProgress("Compressing ModList",
f => async f =>
{ {
var ze = za.CreateEntry((string)f.FileName); var ze = za.CreateEntry((string)f.FileName);
using var os = ze.Open(); await using var os = ze.Open();
using var ins = f.OpenRead(); await using var ins = await f.OpenRead();
ins.CopyTo(os); await ins.CopyToAsync(os);
}); });
// Copy in modimage // Copy in modimage
if (ModListImage.Exists) if (ModListImage.Exists)
{ {
var ze = za.CreateEntry((string)ModList.Image); var ze = za.CreateEntry((string)ModList.Image);
using (var os = ze.Open()) await using var os = ze.Open();
using (var ins = ModListImage.OpenRead()) await using var ins = await ModListImage.OpenRead();
{ await ins.CopyToAsync(os);
ins.CopyTo(os);
}
} }
} }
} }
@ -180,7 +178,7 @@ namespace Wabbajack.Lib
var metadata = new DownloadMetadata var metadata = new DownloadMetadata
{ {
Size = ModListOutputFile.Size, Size = ModListOutputFile.Size,
Hash = ModListOutputFile.FileHash(), Hash = await ModListOutputFile.FileHashAsync(),
NumberOfArchives = ModList.Archives.Count, NumberOfArchives = ModList.Archives.Count,
SizeOfArchives = ModList.Archives.Sum(a => a.Size), SizeOfArchives = ModList.Archives.Sum(a => a.Size),
NumberOfInstalledFiles = ModList.Directives.Count, NumberOfInstalledFiles = ModList.Directives.Count,

View File

@ -71,7 +71,7 @@ namespace Wabbajack.Lib
public async Task<byte[]> LoadBytesFromPath(RelativePath path) public async Task<byte[]> LoadBytesFromPath(RelativePath path)
{ {
await using var e = ExtractedModListFiles![path].OpenRead(); await using var e = await ExtractedModListFiles![path].OpenRead();
return await e.ReadAllAsync(); return await e.ReadAllAsync();
} }
@ -213,7 +213,7 @@ namespace Wabbajack.Lib
toFile.Delete(); toFile.Delete();
// Patch it // Patch it
await using (var outStream = toFile.Create()) await using (var outStream = await toFile.Create())
{ {
Utils.ApplyPatch(oldData, () => new MemoryStream(patchData), outStream); Utils.ApplyPatch(oldData, () => new MemoryStream(patchData), outStream);
} }

View File

@ -62,7 +62,7 @@ namespace Wabbajack.Lib.CompilationSteps
if (source.AbsolutePath.Size >= (long) 2 << 31) if (source.AbsolutePath.Size >= (long) 2 << 31)
{ {
await using var bsa = BSADispatch.OpenRead(source.AbsolutePath); await using var bsa = await BSADispatch.OpenRead(source.AbsolutePath);
if (bsa.State is BSAStateObject) if (bsa.State is BSAStateObject)
{ {
Utils.Error( Utils.Error(
@ -95,7 +95,7 @@ namespace Wabbajack.Lib.CompilationSteps
} }
CreateBSA directive; CreateBSA directive;
await using (var bsa = BSADispatch.OpenRead(source.AbsolutePath)) await using (var bsa = await BSADispatch.OpenRead(source.AbsolutePath))
{ {
directive = new CreateBSA( directive = new CreateBSA(
state: bsa.State, state: bsa.State,

View File

@ -14,7 +14,7 @@ namespace Wabbajack.Lib.CompilationSteps
public override async ValueTask<Directive?> Run(RawSourceFile source) public override async ValueTask<Directive?> Run(RawSourceFile source)
{ {
var inline = source.EvolveTo<InlineFile>(); var inline = source.EvolveTo<InlineFile>();
await using var file = source.File.StagedFile.OpenRead(); await using var file = await source.File.StagedFile.OpenRead();
inline.SourceDataID = await _compiler.IncludeFile(await file.ReadAllAsync()); inline.SourceDataID = await _compiler.IncludeFile(await file.ReadAllAsync());
return inline; return inline;
} }

View File

@ -124,7 +124,7 @@ namespace Wabbajack.Lib.Downloaders
using var stream = await ResolveDownloadStream(a); using var stream = await ResolveDownloadStream(a);
if (stream == null) return false; if (stream == null) return false;
await using var fromStream = await stream.Content.ReadAsStreamAsync(); await using var fromStream = await stream.Content.ReadAsStreamAsync();
await using var toStream = destination.Create(); await using var toStream = await destination.Create();
await fromStream.CopyToAsync(toStream); await fromStream.CopyToAsync(toStream);
return true; return true;
} }

View File

@ -81,7 +81,7 @@ namespace Wabbajack.Lib.Downloaders
await Task.Delay(500, cancel); await Task.Delay(500, cancel);
} }
cookies.ToEcryptedJson(_encryptedKeyName); await cookies.ToEcryptedJson(_encryptedKeyName);
return cookies; return cookies;
} }

View File

@ -110,7 +110,7 @@ namespace Wabbajack.Lib.Downloaders
try try
{ {
var result = last_line.FromJsonString<BethesdaNetData>(); var result = last_line.FromJsonString<BethesdaNetData>();
result.ToEcryptedJson(DataName); await result.ToEcryptedJson(DataName);
return result; return result;
} }
catch (Exception ex) catch (Exception ex)
@ -180,7 +180,7 @@ namespace Wabbajack.Lib.Downloaders
private const uint CKM_Magic = 0x52415442; // BTAR private const uint CKM_Magic = 0x52415442; // BTAR
private async Task ConvertCKMToZip(AbsolutePath src, AbsolutePath dest) private async Task ConvertCKMToZip(AbsolutePath src, AbsolutePath dest)
{ {
using var reader = new BinaryReader(src.OpenRead()); using var reader = new BinaryReader(await src.OpenRead());
var magic = reader.ReadUInt32(); var magic = reader.ReadUInt32();
if (magic != CKM_Magic) if (magic != CKM_Magic)
throw new InvalidDataException("Invalid magic format in CKM parsing"); throw new InvalidDataException("Invalid magic format in CKM parsing");
@ -193,7 +193,7 @@ namespace Wabbajack.Lib.Downloaders
if (minorVersion < 2 || minorVersion > 4) if (minorVersion < 2 || minorVersion > 4)
throw new InvalidDataException("Archive minor version is unknown. Should be 2, 3, or 4."); throw new InvalidDataException("Archive minor version is unknown. Should be 2, 3, or 4.");
await using var fos = dest.Create(); await using var fos = await dest.Create();
using var archive = new ZipArchive(fos, ZipArchiveMode.Create); using var archive = new ZipArchive(fos, ZipArchiveMode.Create);
while (reader.PeekChar() != -1) while (reader.PeekChar() != -1)
{ {

View File

@ -129,7 +129,7 @@ namespace Wabbajack.Lib.Downloaders
Utils.Log($"Applying patch to {archive.Name}"); Utils.Log($"Applying patch to {archive.Name}");
await using(var src = await result.NewFile.Path.OpenShared()) await using(var src = await result.NewFile.Path.OpenShared())
await using (var final = destination.Create()) await using (var final = await destination.Create())
{ {
Utils.ApplyPatch(src, () => tempFile.Path.OpenShared().Result, final); Utils.ApplyPatch(src, () => tempFile.Path.OpenShared().Result, final);
} }

View File

@ -71,8 +71,8 @@ namespace Wabbajack.Lib.Downloaders
public override async Task<bool> Download(Archive a, AbsolutePath destination) public override async Task<bool> Download(Archive a, AbsolutePath destination)
{ {
await using var src = SourcePath.OpenRead(); await using var src = await SourcePath.OpenRead();
await using var dest = destination.Create(); await using var dest = await destination.Create();
var size = SourcePath.Size; var size = SourcePath.Size;
await src.CopyToWithStatusAsync(size, dest, "Copying from Game folder"); await src.CopyToWithStatusAsync(size, dest, "Copying from Game folder");

View File

@ -81,7 +81,7 @@ namespace Wabbajack.Lib.Downloaders
destination.Parent.CreateDirectory(); destination.Parent.CreateDirectory();
} }
using (var fs = download ? destination.Create() : null) using (var fs = download ? await destination.Create() : null)
{ {
var client = Client ?? new Common.Http.Client(); var client = Client ?? new Common.Http.Client();
client.Headers.Add(("User-Agent", Consts.UserAgent)); client.Headers.Add(("User-Agent", Consts.UserAgent));

View File

@ -57,7 +57,7 @@ namespace Wabbajack.Lib.Downloaders
{ {
destination.Parent.CreateDirectory(); destination.Parent.CreateDirectory();
var definition = await GetDefinition(); var definition = await GetDefinition();
using var fs = destination.Create(); await using var fs = await destination.Create();
using var mmfile = MemoryMappedFile.CreateFromFile(fs, null, definition.Size, MemoryMappedFileAccess.ReadWrite, HandleInheritability.None, false); using var mmfile = MemoryMappedFile.CreateFromFile(fs, null, definition.Size, MemoryMappedFileAccess.ReadWrite, HandleInheritability.None, false);
var client = new Common.Http.Client(); var client = new Common.Http.Client();
using var queue = new WorkQueue(); using var queue = new WorkQueue();

View File

@ -114,7 +114,7 @@ namespace Wabbajack.Lib.Downloaders
var trackFolder = folder.Dir.Combine("tracks"); var trackFolder = folder.Dir.Combine("tracks");
await using (var fs = initialDownload.Create()) await using (var fs = await initialDownload.Create())
{ {
await client.Videos.Streams.CopyToAsync(stream, fs, new Progress($"Downloading {a.Name}"), await client.Videos.Streams.CopyToAsync(stream, fs, new Progress($"Downloading {a.Name}"),
CancellationToken.None); CancellationToken.None);
@ -128,7 +128,7 @@ namespace Wabbajack.Lib.Downloaders
await ExtractTrack(initialDownload, trackFolder, track); await ExtractTrack(initialDownload, trackFolder, track);
}); });
await using var dest = destination.Create(); await using var dest = await destination.Create();
using var ar = new ZipArchive(dest, ZipArchiveMode.Create); using var ar = new ZipArchive(dest, ZipArchiveMode.Create);
foreach (var track in trackFolder.EnumerateFiles().OrderBy(e => e)) foreach (var track in trackFolder.EnumerateFiles().OrderBy(e => e))
{ {
@ -136,7 +136,7 @@ namespace Wabbajack.Lib.Downloaders
var entry = ar.CreateEntry(Path.Combine("Data", "tracks", (string)track.RelativeTo(trackFolder)), CompressionLevel.NoCompression); var entry = ar.CreateEntry(Path.Combine("Data", "tracks", (string)track.RelativeTo(trackFolder)), CompressionLevel.NoCompression);
entry.LastWriteTime = meta.UploadDate; entry.LastWriteTime = meta.UploadDate;
await using var es = entry.Open(); await using var es = entry.Open();
await using var ins = track.OpenRead(); await using var ins = await track.OpenRead();
await ins.CopyToAsync(es); await ins.CopyToAsync(es);
} }

View File

@ -4,6 +4,8 @@ using System.Linq.Expressions;
using System.Reactive; using System.Reactive;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading.Tasks;
using DynamicData; using DynamicData;
using DynamicData.Kernel; using DynamicData.Kernel;
using ReactiveUI; using ReactiveUI;
@ -38,6 +40,20 @@ namespace Wabbajack
return source.ObserveOn(RxApp.MainThreadScheduler); return source.ObserveOn(RxApp.MainThreadScheduler);
} }
/// <summary>
/// Like IObservable.Select but supports async map functions
/// </summary>
/// <param name="source"></param>
/// <param name="f"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IObservable<TOut> SelectAsync<TIn, TOut>(this IObservable<TIn> source, Func<TIn, Task<TOut>> f)
{
return source.Select(itm => Observable.FromAsync(async () => await f(itm))).Merge(10);
}
public static IObservable<Unit> StartingExecution(this IReactiveCommand cmd) public static IObservable<Unit> StartingExecution(this IReactiveCommand cmd)
{ {
return cmd.IsExecuting return cmd.IsExecuting

View File

@ -484,8 +484,8 @@ namespace Wabbajack.Lib
Info($"Patching {entry.To}"); Info($"Patching {entry.To}");
Status($"Patching {entry.To}"); Status($"Patching {entry.To}");
var srcFile = byPath[string.Join("|", entry.ArchiveHashPath.Paths)]; var srcFile = byPath[string.Join("|", entry.ArchiveHashPath.Paths)];
await using var srcStream = srcFile.OpenRead(); await using var srcStream = await srcFile.OpenRead();
await using var outputStream = IncludeFile(out var id); await using var outputStream = await IncludeFile(out var id).Create();
entry.PatchID = id; entry.PatchID = id;
await using var destStream = await LoadDataForTo(entry.To, absolutePaths); await using var destStream = await LoadDataForTo(entry.To, absolutePaths);
await Utils.CreatePatch(srcStream, srcFile.Hash, destStream, entry.Hash, outputStream); await Utils.CreatePatch(srcStream, srcFile.Hash, destStream, entry.Hash, outputStream);
@ -496,18 +496,18 @@ namespace Wabbajack.Lib
private async Task<FileStream> LoadDataForTo(RelativePath to, Dictionary<RelativePath, AbsolutePath> absolutePaths) private async Task<FileStream> LoadDataForTo(RelativePath to, Dictionary<RelativePath, AbsolutePath> absolutePaths)
{ {
if (absolutePaths.TryGetValue(to, out var absolute)) if (absolutePaths.TryGetValue(to, out var absolute))
return absolute.OpenRead(); return await absolute.OpenRead();
if (to.StartsWith(Consts.BSACreationDir)) if (to.StartsWith(Consts.BSACreationDir))
{ {
var bsaId = (RelativePath)((string)to).Split('\\')[1]; var bsaId = (RelativePath)((string)to).Split('\\')[1];
var bsa = InstallDirectives.OfType<CreateBSA>().First(b => b.TempID == bsaId); var bsa = InstallDirectives.OfType<CreateBSA>().First(b => b.TempID == bsaId);
await using var a = BSADispatch.OpenRead(MO2Folder.Combine(bsa.To)); await using var a = await BSADispatch.OpenRead(MO2Folder.Combine(bsa.To));
var find = (RelativePath)Path.Combine(((string)to).Split('\\').Skip(2).ToArray()); var find = (RelativePath)Path.Combine(((string)to).Split('\\').Skip(2).ToArray());
var file = a.Files.First(e => e.Path == find); var file = a.Files.First(e => e.Path == find);
var returnStream = new TempStream(); var returnStream = new TempStream();
file.CopyDataTo(returnStream); await file.CopyDataTo(returnStream);
returnStream.Position = 0; returnStream.Position = 0;
return returnStream; return returnStream;
} }

View File

@ -84,7 +84,7 @@ namespace Wabbajack.Lib
if (cancel.IsCancellationRequested) return false; if (cancel.IsCancellationRequested) return false;
UpdateTracker.NextStep("Validating Game ESMs"); UpdateTracker.NextStep("Validating Game ESMs");
ValidateGameESMs(); await ValidateGameESMs();
if (cancel.IsCancellationRequested) return false; if (cancel.IsCancellationRequested) return false;
UpdateTracker.NextStep("Validating Modlist"); UpdateTracker.NextStep("Validating Modlist");
@ -238,14 +238,14 @@ namespace Wabbajack.Lib
}); });
} }
private void ValidateGameESMs() private async ValueTask ValidateGameESMs()
{ {
foreach (var esm in ModList.Directives.OfType<CleanedESM>().ToList()) foreach (var esm in ModList.Directives.OfType<CleanedESM>().ToList())
{ {
var filename = esm.To.FileName; var filename = esm.To.FileName;
var gameFile = GameFolder!.Value.Combine((RelativePath)"Data", filename); var gameFile = GameFolder!.Value.Combine((RelativePath)"Data", filename);
Utils.Log($"Validating {filename}"); Utils.Log($"Validating {filename}");
var hash = gameFile.FileHash(); var hash = await gameFile.FileHashAsync();
if (hash != esm.SourceESMHash) if (hash != esm.SourceESMHash)
{ {
Utils.ErrorThrow(new InvalidGameESMError(esm, hash, gameFile)); Utils.ErrorThrow(new InvalidGameESMError(esm, hash, gameFile));
@ -269,7 +269,7 @@ namespace Wabbajack.Lib
var streams = await bsa.FileStates.PMap(Queue, async state => var streams = await bsa.FileStates.PMap(Queue, async state =>
{ {
Status($"Adding {state.Path} to BSA"); Status($"Adding {state.Path} to BSA");
var fs = sourceDir.Combine(state.Path).OpenRead(); var fs = await sourceDir.Combine(state.Path).OpenRead();
await a.AddFile(state, fs); await a.AddFile(state, fs);
return fs; return fs;
}); });
@ -328,8 +328,8 @@ namespace Wabbajack.Lib
var patchData = await LoadBytesFromPath(directive.SourceDataID); var patchData = await LoadBytesFromPath(directive.SourceDataID);
var toFile = OutputFolder.Combine(directive.To); var toFile = OutputFolder.Combine(directive.To);
Status($"Patching {filename}"); Status($"Patching {filename}");
using var output = toFile.Create(); await using var output = await toFile.Create();
using var input = gameFile.OpenRead(); await using var input = await gameFile.OpenRead();
Utils.ApplyPatch(input, () => new MemoryStream(patchData), output); Utils.ApplyPatch(input, () => new MemoryStream(patchData), output);
} }

View File

@ -84,14 +84,14 @@ namespace Wabbajack.Lib.ModListRegistry
return metadata.OrderBy(m => (m.ValidationSummary?.HasFailures ?? false ? 1 : 0, m.Title)).ToList(); return metadata.OrderBy(m => (m.ValidationSummary?.HasFailures ?? false ? 1 : 0, m.Title)).ToList();
} }
public bool NeedsDownload(AbsolutePath modlistPath) public async ValueTask<bool> NeedsDownload(AbsolutePath modlistPath)
{ {
if (!modlistPath.Exists) return true; if (!modlistPath.Exists) return true;
if (DownloadMetadata?.Hash == null) if (DownloadMetadata?.Hash == null)
{ {
return true; return true;
} }
return DownloadMetadata.Hash != modlistPath.FileHashCached(true); return DownloadMetadata.Hash != await modlistPath.FileHashCachedAsync(true);
} }
} }

View File

@ -77,7 +77,7 @@ namespace Wabbajack.Lib.NexusApi
public static async Task<string> RequestAndCacheAPIKey() public static async Task<string> RequestAndCacheAPIKey()
{ {
var result = await Utils.Log(new RequestNexusAuthorization()).Task; var result = await Utils.Log(new RequestNexusAuthorization()).Task;
result.ToEcryptedJson("nexusapikey"); await result.ToEcryptedJson("nexusapikey");
return result; return result;
} }

View File

@ -270,7 +270,7 @@ namespace Wabbajack.Lib
var patchData = await installer.LoadBytesFromPath(m.PatchID); var patchData = await installer.LoadBytesFromPath(m.PatchID);
await using var fs = installer.OutputFolder.Combine(m.To).Create(); await using var fs = await installer.OutputFolder.Combine(m.To).Create();
Utils.ApplyPatch(new MemoryStream(srcData), () => new MemoryStream(patchData), fs); Utils.ApplyPatch(new MemoryStream(srcData), () => new MemoryStream(patchData), fs);
}); });
} }

View File

@ -36,18 +36,19 @@ namespace Wabbajack.BuildServer.Test
public AbsolutePath ServerUpdatesFolder => "updates".RelativeTo(AbsolutePath.EntryPoint); public AbsolutePath ServerUpdatesFolder => "updates".RelativeTo(AbsolutePath.EntryPoint);
public BuildServerFixture() public static async Task Start()
{ {
ServerArchivesFolder.DeleteDirectory().Wait(); var fixture = new BuildServerFixture();
ServerArchivesFolder.CreateDirectory(); fixture.ServerArchivesFolder.DeleteDirectory().Wait();
fixture.ServerArchivesFolder.CreateDirectory();
var builder = Program.CreateHostBuilder( var builder = Program.CreateHostBuilder(
new[] new[]
{ {
$"WabbajackSettings:DownloadDir={"tmp".RelativeTo(AbsolutePath.EntryPoint)}", $"WabbajackSettings:DownloadDir={"tmp".RelativeTo(AbsolutePath.EntryPoint)}",
$"WabbajackSettings:ArchiveDir={"archives".RelativeTo(AbsolutePath.EntryPoint)}", $"WabbajackSettings:ArchiveDir={"archives".RelativeTo(AbsolutePath.EntryPoint)}",
$"WabbajackSettings:TempFolder={ServerTempFolder}", $"WabbajackSettings:TempFolder={fixture.ServerTempFolder}",
$"WabbajackSettings:SQLConnection={PublicConnStr}", $"WabbajackSettings:SQLConnection={fixture.PublicConnStr}",
$"WabbajackSettings:BunnyCDN_User=TEST", $"WabbajackSettings:BunnyCDN_User=TEST",
$"WabbajackSettings:BunnyCDN_Password=TEST", $"WabbajackSettings:BunnyCDN_Password=TEST",
"WabbajackSettings:JobScheduler=false", "WabbajackSettings:JobScheduler=false",
@ -56,12 +57,12 @@ namespace Wabbajack.BuildServer.Test
"WabbajackSettings:RunFrontEndJobs=false", "WabbajackSettings:RunFrontEndJobs=false",
"WabbajackSettinss:DisableNexusForwarding=true" "WabbajackSettinss:DisableNexusForwarding=true"
}, true); }, true);
_host = builder.Build(); fixture._host = builder.Build();
_token = new CancellationTokenSource(); fixture._token = new CancellationTokenSource();
_task = _host.RunAsync(_token.Token); fixture._task = fixture._host.RunAsync(fixture._token.Token);
Consts.WabbajackBuildServerUri = new Uri("http://localhost:8080"); Consts.WabbajackBuildServerUri = new Uri("http://localhost:8080");
"ServerWhitelist.yaml".RelativeTo(ServerPublicFolder).WriteAllText( await "ServerWhitelist.yaml".RelativeTo(fixture.ServerPublicFolder).WriteAllTextAsync(
"GoogleIDs:\nAllowedPrefixes:\n - http://localhost"); "GoogleIDs:\nAllowedPrefixes:\n - http://localhost");
} }
@ -208,7 +209,7 @@ namespace Wabbajack.BuildServer.Test
var modListPath = "test_modlist.wabbajack".RelativeTo(Fixture.ServerPublicFolder); var modListPath = "test_modlist.wabbajack".RelativeTo(Fixture.ServerPublicFolder);
await using (var fs = modListPath.Create()) await using (var fs = await modListPath.Create())
{ {
using var za = new ZipArchive(fs, ZipArchiveMode.Create); using var za = new ZipArchive(fs, ZipArchiveMode.Create);
var entry = za.CreateEntry("modlist"); var entry = za.CreateEntry("modlist");
@ -254,7 +255,7 @@ namespace Wabbajack.BuildServer.Test
var metadataPath = "test_mod_list_metadata.json".RelativeTo(Fixture.ServerPublicFolder); var metadataPath = "test_mod_list_metadata.json".RelativeTo(Fixture.ServerPublicFolder);
ModListMetaData.ToJson(metadataPath); await ModListMetaData.ToJsonAsync(metadataPath);
return new Uri(MakeURL("test_mod_list_metadata.json")); return new Uri(MakeURL("test_mod_list_metadata.json"));
} }

View File

@ -99,7 +99,7 @@ namespace Wabbajack.BuildServer.Controllers
private async Task<FtpClient> GetBunnyCdnFtpClient() private async Task<FtpClient> GetBunnyCdnFtpClient()
{ {
var info = Utils.FromEncryptedJson<BunnyCdnFtpInfo>("bunny-cdn-ftp-info"); var info = await Utils.FromEncryptedJson<BunnyCdnFtpInfo>("bunny-cdn-ftp-info");
var client = new FtpClient(info.Hostname) {Credentials = new NetworkCredential(info.Username, info.Password)}; var client = new FtpClient(info.Hostname) {Credentials = new NetworkCredential(info.Username, info.Password)};
await client.ConnectAsync(); await client.ConnectAsync();
return client; return client;

View File

@ -99,7 +99,7 @@ namespace Wabbajack.Server.Services
_maintainer.TryGetPath(list.DownloadMetadata.Hash, out var modlistPath); _maintainer.TryGetPath(list.DownloadMetadata.Hash, out var modlistPath);
ModList modlist; ModList modlist;
await using (var fs = modlistPath.OpenRead()) await using (var fs = await modlistPath.OpenRead())
using (var zip = new ZipArchive(fs, ZipArchiveMode.Read)) using (var zip = new ZipArchive(fs, ZipArchiveMode.Read))
await using (var entry = zip.GetEntry("modlist")?.Open()) await using (var entry = zip.GetEntry("modlist")?.Open())
{ {

View File

@ -70,10 +70,10 @@ namespace Wabbajack.Server.Services
using var sigFile = new TempFile(); using var sigFile = new TempFile();
using var patchFile = new TempFile(); using var patchFile = new TempFile();
await using var srcStream = srcPath.OpenShared(); await using var srcStream = await srcPath.OpenShared();
await using var destStream = destPath.OpenShared(); await using var destStream = await destPath.OpenShared();
await using var sigStream = sigFile.Path.Create(); await using var sigStream = await sigFile.Path.Create();
await using var patchOutput = patchFile.Path.Create(); await using var patchOutput = await patchFile.Path.Create();
OctoDiff.Create(destStream, srcStream, sigStream, patchOutput); OctoDiff.Create(destStream, srcStream, sigStream, patchOutput);
await patchOutput.DisposeAsync(); await patchOutput.DisposeAsync();
var size = patchFile.Path.Size; var size = patchFile.Path.Size;
@ -132,7 +132,7 @@ namespace Wabbajack.Server.Services
private async Task<FtpClient> GetBunnyCdnFtpClient() private async Task<FtpClient> GetBunnyCdnFtpClient()
{ {
var info = Utils.FromEncryptedJson<BunnyCdnFtpInfo>("bunny-cdn-ftp-info"); var info = await Utils.FromEncryptedJson<BunnyCdnFtpInfo>("bunny-cdn-ftp-info");
var client = new FtpClient(info.Hostname) {Credentials = new NetworkCredential(info.Username, info.Password)}; var client = new FtpClient(info.Hostname) {Credentials = new NetworkCredential(info.Username, info.Password)};
await client.ConnectAsync(); await client.ConnectAsync();
return client; return client;

View File

@ -436,7 +436,7 @@ namespace Wabbajack.Test
await converted.Download(new Archive(state: null!) { Name = "mod.zip" }, filename.Path); await converted.Download(new Archive(state: null!) { Name = "mod.zip" }, filename.Path);
await using var fs = filename.Path.OpenRead(); await using var fs = await filename.Path.OpenRead();
using var archive = new ZipArchive(fs); using var archive = new ZipArchive(fs);
var entries = archive.Entries.Select(e => e.FullName).ToList(); var entries = archive.Entries.Select(e => e.FullName).ToList();
Assert.Equal(entries, new List<string> {@"Data\TestCK.esp", @"Data\TestCK.ini"}); Assert.Equal(entries, new List<string> {@"Data\TestCK.esp", @"Data\TestCK.ini"});

View File

@ -47,7 +47,7 @@ namespace Wabbajack.Test
public async Task CreateModlist() public async Task CreateModlist()
{ {
var profile = utils.AddProfile("Default"); var profile = utils.AddProfile("Default");
var mod = utils.AddMod(); var mod = await utils.AddMod();
await DownloadAndInstall( await DownloadAndInstall(
"https://github.com/ModOrganizer2/modorganizer/releases/download/v2.2.1/Mod.Organizer.2.2.1.7z", "https://github.com/ModOrganizer2/modorganizer/releases/download/v2.2.1/Mod.Organizer.2.2.1.7z",
@ -79,7 +79,7 @@ namespace Wabbajack.Test
await CompileAndInstall(profile); await CompileAndInstall(profile);
utils.VerifyAllFiles(); await utils.VerifyAllFiles();
await utils.InstallFolder.Combine(Consts.LOOTFolderFilesDir).DeleteDirectory(); await utils.InstallFolder.Combine(Consts.LOOTFolderFilesDir).DeleteDirectory();
@ -111,7 +111,7 @@ namespace Wabbajack.Test
private async Task<(AbsolutePath Download, AbsolutePath ModFolder)> DownloadAndInstall(Game game, int modId, string modName) private async Task<(AbsolutePath Download, AbsolutePath ModFolder)> DownloadAndInstall(Game game, int modId, string modName)
{ {
utils.AddMod(modName); await utils.AddMod(modName);
var client = await NexusApiClient.Get(); var client = await NexusApiClient.Get();
var resp = await client.GetModFiles(game, modId); var resp = await client.GetModFiles(game, modId);
var file = resp.files.FirstOrDefault(f => f.is_primary) ?? resp.files.FirstOrDefault(f => !string.IsNullOrEmpty(f.category_name)); var file = resp.files.FirstOrDefault(f => f.is_primary) ?? resp.files.FirstOrDefault(f => !string.IsNullOrEmpty(f.category_name));

View File

@ -27,8 +27,8 @@ namespace Wabbajack.Test
public async Task CheckValidInstallPath_HasModlist() public async Task CheckValidInstallPath_HasModlist()
{ {
await using var tempDir = await TempFolder.Create(); await using var tempDir = await TempFolder.Create();
await using var mo2 = tempDir.Dir.Combine("ModOrganizer.exe").Create(); await using var mo2 = await tempDir.Dir.Combine("ModOrganizer.exe").Create();
await using var molist = tempDir.Dir.Combine(((RelativePath)"modlist")).WithExtension(Consts.ModListExtension).Create(); await using var molist = await tempDir.Dir.Combine(((RelativePath)"modlist")).WithExtension(Consts.ModListExtension).Create();
Assert.False(MO2Installer.CheckValidInstallPath(tempDir.Dir, downloadFolder: null).Succeeded); Assert.False(MO2Installer.CheckValidInstallPath(tempDir.Dir, downloadFolder: null).Succeeded);
} }
@ -36,7 +36,7 @@ namespace Wabbajack.Test
public async Task CheckValidInstallPath_ProperOverwrite() public async Task CheckValidInstallPath_ProperOverwrite()
{ {
await using var tempDir = await TempFolder.Create(); await using var tempDir = await TempFolder.Create();
await using var tmp = tempDir.Dir.Combine(Consts.ModOrganizer2Exe).Create(); await using var tmp = await tempDir.Dir.Combine(Consts.ModOrganizer2Exe).Create();
Assert.True(MO2Installer.CheckValidInstallPath(tempDir.Dir, downloadFolder: null).Succeeded); Assert.True(MO2Installer.CheckValidInstallPath(tempDir.Dir, downloadFolder: null).Succeeded);
} }
@ -46,7 +46,7 @@ namespace Wabbajack.Test
await using var tempDir = await TempFolder.Create(); await using var tempDir = await TempFolder.Create();
await tempDir.Dir.DeleteDirectory(); await tempDir.Dir.DeleteDirectory();
tempDir.Dir.CreateDirectory(); tempDir.Dir.CreateDirectory();
await using var tmp = tempDir.Dir.Combine($"someFile.txt").Create(); await using var tmp = await tempDir.Dir.Combine($"someFile.txt").Create();
Assert.False(MO2Installer.CheckValidInstallPath(tempDir.Dir, downloadFolder: null).Succeeded); Assert.False(MO2Installer.CheckValidInstallPath(tempDir.Dir, downloadFolder: null).Succeeded);
} }
@ -56,7 +56,7 @@ namespace Wabbajack.Test
await using var tempDir = await TempFolder.Create(); await using var tempDir = await TempFolder.Create();
var downloadsFolder = tempDir.Dir.Combine("downloads"); var downloadsFolder = tempDir.Dir.Combine("downloads");
downloadsFolder.CreateDirectory(); downloadsFolder.CreateDirectory();
await using var tmp = tempDir.Dir.Combine($"downloads/someFile.txt").Create(); await using var tmp = await tempDir.Dir.Combine($"downloads/someFile.txt").Create();
Assert.True(MO2Installer.CheckValidInstallPath(tempDir.Dir, downloadFolder: downloadsFolder).Succeeded); Assert.True(MO2Installer.CheckValidInstallPath(tempDir.Dir, downloadFolder: downloadsFolder).Succeeded);
} }
#endregion #endregion

View File

@ -27,17 +27,17 @@ namespace Wabbajack.Test
{ {
var profile = utils.AddProfile(); var profile = utils.AddProfile();
var mod = utils.AddMod(); var mod = await utils.AddMod();
var testPex = utils.AddModFile(mod, @"Data\scripts\test.pex", 10); var testPex = await utils.AddModFile(mod, @"Data\scripts\test.pex", 10);
await utils.Configure(); await utils.Configure();
utils.AddManualDownload( await utils.AddManualDownload(
new Dictionary<string, byte[]> {{"/baz/biz.pex", await testPex.ReadAllBytesAsync()}}); new Dictionary<string, byte[]> {{"/baz/biz.pex", await testPex.ReadAllBytesAsync()}});
await CompileAndInstall(profile); await CompileAndInstall(profile);
utils.VerifyInstalledFile(mod, @"Data\scripts\test.pex"); await utils.VerifyInstalledFile(mod, @"Data\scripts\test.pex");
} }
[Fact] [Fact]
@ -45,19 +45,19 @@ namespace Wabbajack.Test
{ {
var profile = utils.AddProfile(); var profile = utils.AddProfile();
var mod = utils.AddMod(); var mod = await utils.AddMod();
var testPex = utils.AddModFile(mod, @"Data\scripts\test.pex", 10); var testPex = await utils.AddModFile(mod, @"Data\scripts\test.pex", 10);
await utils.Configure(); await utils.Configure();
utils.AddManualDownload( await utils.AddManualDownload(
new Dictionary<string, byte[]> {{"/baz/biz.pex", await testPex.ReadAllBytesAsync()}}); new Dictionary<string, byte[]> {{"/baz/biz.pex", await testPex.ReadAllBytesAsync()}});
await utils.DownloadsFolder.Combine("some_other_file.7z").WriteAllTextAsync("random data"); await utils.DownloadsFolder.Combine("some_other_file.7z").WriteAllTextAsync("random data");
await CompileAndInstall(profile); await CompileAndInstall(profile);
utils.VerifyInstalledFile(mod, @"Data\scripts\test.pex"); await utils.VerifyInstalledFile(mod, @"Data\scripts\test.pex");
} }
[Fact] [Fact]
@ -65,17 +65,17 @@ namespace Wabbajack.Test
{ {
var profile = utils.AddProfile(); var profile = utils.AddProfile();
var mod = utils.AddMod(); var mod = await utils.AddMod();
var testPex = utils.AddGameFile(@"enbstuff\test.pex", 10); var testPex = await utils.AddGameFile(@"enbstuff\test.pex", 10);
await utils.Configure(); await utils.Configure();
utils.AddManualDownload( await utils.AddManualDownload(
new Dictionary<string, byte[]> {{"/baz/biz.pex", await testPex.ReadAllBytesAsync()}}); new Dictionary<string, byte[]> {{"/baz/biz.pex", await testPex.ReadAllBytesAsync()}});
await CompileAndInstall(profile); await CompileAndInstall(profile);
utils.VerifyInstalledGameFile(@"enbstuff\test.pex"); await utils.VerifyInstalledGameFile(@"enbstuff\test.pex");
} }
[Fact] [Fact]
@ -83,14 +83,14 @@ namespace Wabbajack.Test
{ {
var profile = utils.AddProfile(); var profile = utils.AddProfile();
var mod = utils.AddMod(); var mod = await utils.AddMod();
var testPex = utils.AddGameFile(@"enbstuff\test.pex", 10); var testPex = await utils.AddGameFile(@"enbstuff\test.pex", 10);
await utils.Configure(); await utils.Configure();
utils.MO2Folder.Combine(Consts.GameFolderFilesDir).CreateDirectory(); utils.MO2Folder.Combine(Consts.GameFolderFilesDir).CreateDirectory();
utils.AddManualDownload( await utils.AddManualDownload(
new Dictionary<string, byte[]> {{"/baz/biz.pex", await testPex.ReadAllBytesAsync()}}); new Dictionary<string, byte[]> {{"/baz/biz.pex", await testPex.ReadAllBytesAsync()}});
await CompileAndInstall(profile); await CompileAndInstall(profile);
@ -103,21 +103,21 @@ namespace Wabbajack.Test
{ {
var profile = utils.AddProfile(); var profile = utils.AddProfile();
var mod = utils.AddMod(); var mod = await utils.AddMod();
var testPex = utils.AddModFile(mod, @"Data\scripts\test.pex", 10); var testPex = await utils.AddModFile(mod, @"Data\scripts\test.pex", 10);
// Make a copy to make sure it gets picked up and moved around. // Make a copy to make sure it gets picked up and moved around.
testPex.CopyTo(testPex.WithExtension(new Extension(".copy"))); await testPex.CopyToAsync(testPex.WithExtension(new Extension(".copy")));
await utils.Configure(); await utils.Configure();
utils.AddManualDownload( await utils.AddManualDownload(
new Dictionary<string, byte[]> { { "/baz/biz.pex", await testPex.ReadAllBytesAsync() } }); new Dictionary<string, byte[]> { { "/baz/biz.pex", await testPex.ReadAllBytesAsync() } });
await CompileAndInstall(profile); await CompileAndInstall(profile);
utils.VerifyInstalledFile(mod, @"Data\scripts\test.pex"); await utils.VerifyInstalledFile(mod, @"Data\scripts\test.pex");
utils.VerifyInstalledFile(mod, @"Data\scripts\test.pex.copy"); await utils.VerifyInstalledFile(mod, @"Data\scripts\test.pex.copy");
} }
[Fact] [Fact]
@ -125,14 +125,14 @@ namespace Wabbajack.Test
{ {
var profile = utils.AddProfile(); var profile = utils.AddProfile();
var mod = utils.AddMod(); var mod = await utils.AddMod();
var unchanged = utils.AddModFile(mod, @"Data\scripts\unchanged.pex", 10); var unchanged = await utils.AddModFile(mod, @"Data\scripts\unchanged.pex", 10);
var deleted = utils.AddModFile(mod, @"Data\scripts\deleted.pex", 10); var deleted = await utils.AddModFile(mod, @"Data\scripts\deleted.pex", 10);
var modified = utils.AddModFile(mod, @"Data\scripts\modified.pex", 10); var modified = await utils.AddModFile(mod, @"Data\scripts\modified.pex", 10);
await utils.Configure(); await utils.Configure();
utils.AddManualDownload( await utils.AddManualDownload(
new Dictionary<string, byte[]> new Dictionary<string, byte[]>
{ {
{ "/baz/unchanged.pex", await unchanged.ReadAllBytesAsync() }, { "/baz/unchanged.pex", await unchanged.ReadAllBytesAsync() },
@ -142,9 +142,9 @@ namespace Wabbajack.Test
await CompileAndInstall(profile); await CompileAndInstall(profile);
utils.VerifyInstalledFile(mod, @"Data\scripts\unchanged.pex"); await utils.VerifyInstalledFile(mod, @"Data\scripts\unchanged.pex");
utils.VerifyInstalledFile(mod, @"Data\scripts\deleted.pex"); await utils.VerifyInstalledFile(mod, @"Data\scripts\deleted.pex");
utils.VerifyInstalledFile(mod, @"Data\scripts\modified.pex"); await utils.VerifyInstalledFile(mod, @"Data\scripts\modified.pex");
var unchangedPath = utils.PathOfInstalledFile(mod, @"Data\scripts\unchanged.pex"); var unchangedPath = utils.PathOfInstalledFile(mod, @"Data\scripts\unchanged.pex");
var deletedPath = utils.PathOfInstalledFile(mod, @"Data\scripts\deleted.pex"); var deletedPath = utils.PathOfInstalledFile(mod, @"Data\scripts\deleted.pex");
@ -170,9 +170,9 @@ namespace Wabbajack.Test
await CompileAndInstall(profile); await CompileAndInstall(profile);
utils.VerifyInstalledFile(mod, @"Data\scripts\unchanged.pex"); await utils.VerifyInstalledFile(mod, @"Data\scripts\unchanged.pex");
utils.VerifyInstalledFile(mod, @"Data\scripts\deleted.pex"); await utils.VerifyInstalledFile(mod, @"Data\scripts\deleted.pex");
utils.VerifyInstalledFile(mod, @"Data\scripts\modified.pex"); await utils.VerifyInstalledFile(mod, @"Data\scripts\modified.pex");
Assert.Equal(unchangedModified, unchangedPath.LastModified); Assert.Equal(unchangedModified, unchangedPath.LastModified);
Assert.NotEqual(modifiedModified, modifiedPath.LastModified); Assert.NotEqual(modifiedModified, modifiedPath.LastModified);
@ -184,7 +184,7 @@ namespace Wabbajack.Test
public async Task SetScreenSizeTest() public async Task SetScreenSizeTest()
{ {
var profile = utils.AddProfile(); var profile = utils.AddProfile();
var mod = utils.AddMod("dummy"); var mod = await utils.AddMod("dummy");
await utils.Configure(); await utils.Configure();
await utils.MO2Folder.Combine("profiles", profile, "somegameprefs.ini").WriteAllLinesAsync( await utils.MO2Folder.Combine("profiles", profile, "somegameprefs.ini").WriteAllLinesAsync(
@ -216,11 +216,11 @@ namespace Wabbajack.Test
public async Task UnmodifiedInlinedFilesArePulledFromArchives() public async Task UnmodifiedInlinedFilesArePulledFromArchives()
{ {
var profile = utils.AddProfile(); var profile = utils.AddProfile();
var mod = utils.AddMod(); var mod = await utils.AddMod();
var ini = utils.AddModFile(mod, @"foo.ini", 10); var ini = await utils.AddModFile(mod, @"foo.ini", 10);
await utils.Configure(); await utils.Configure();
utils.AddManualDownload( await utils.AddManualDownload(
new Dictionary<string, byte[]> { { "/baz/biz.pex", await ini.ReadAllBytesAsync() } }); new Dictionary<string, byte[]> { { "/baz/biz.pex", await ini.ReadAllBytesAsync() } });
var modlist = await CompileAndInstall(profile); var modlist = await CompileAndInstall(profile);
@ -234,9 +234,9 @@ namespace Wabbajack.Test
public async Task ModifiedIniFilesArePatchedAgainstFileWithSameName() public async Task ModifiedIniFilesArePatchedAgainstFileWithSameName()
{ {
var profile = utils.AddProfile(); var profile = utils.AddProfile();
var mod = utils.AddMod(); var mod = await utils.AddMod();
var ini = utils.AddModFile(mod, @"foo.ini", 10); var ini = await utils.AddModFile(mod, @"foo.ini", 10);
var meta = utils.AddModFile(mod, "meta.ini"); var meta = await utils.AddModFile(mod, "meta.ini");
await utils.Configure(); await utils.Configure();
@ -262,8 +262,8 @@ namespace Wabbajack.Test
public async Task CanPatchFilesSourcedFromBSAs() public async Task CanPatchFilesSourcedFromBSAs()
{ {
var profile = utils.AddProfile(); var profile = utils.AddProfile();
var mod = utils.AddMod(); var mod = await utils.AddMod();
var file = utils.AddModFile(mod, @"baz.bin", 10); var file = await utils.AddModFile(mod, @"baz.bin", 10);
await utils.Configure(); await utils.Configure();
@ -287,7 +287,7 @@ namespace Wabbajack.Test
new Dictionary<string, byte[]> { { "/stuff/files.bsa", await tempFile.Path.ReadAllBytesAsync() } }); new Dictionary<string, byte[]> { { "/stuff/files.bsa", await tempFile.Path.ReadAllBytesAsync() } });
await CompileAndInstall(profile); await CompileAndInstall(profile);
utils.VerifyInstalledFile(mod, @"baz.bin"); await utils.VerifyInstalledFile(mod, @"baz.bin");
} }
@ -295,8 +295,8 @@ namespace Wabbajack.Test
public async Task CanNoMatchIncludeFilesFromBSAs() public async Task CanNoMatchIncludeFilesFromBSAs()
{ {
var profile = utils.AddProfile(); var profile = utils.AddProfile();
var mod = utils.AddMod(); var mod = await utils.AddMod();
var file = utils.AddModFile(mod, @"baz.bsa", 10); var file = await utils.AddModFile(mod, @"baz.bsa", 10);
await file.Parent.Combine("meta.ini").WriteAllLinesAsync(new[] await file.Parent.Combine("meta.ini").WriteAllLinesAsync(new[]
{ {
@ -334,7 +334,7 @@ namespace Wabbajack.Test
new Dictionary<string, byte[]> { { "/stuff/matching_file_data.bin", tempFileData } }); new Dictionary<string, byte[]> { { "/stuff/matching_file_data.bin", tempFileData } });
await CompileAndInstall(profile); await CompileAndInstall(profile);
utils.VerifyInstalledFile(mod, @"baz.bsa"); await utils.VerifyInstalledFile(mod, @"baz.bsa");
} }
@ -342,8 +342,8 @@ namespace Wabbajack.Test
public async Task CanInstallFilesFromBSAAndBSA() public async Task CanInstallFilesFromBSAAndBSA()
{ {
var profile = utils.AddProfile(); var profile = utils.AddProfile();
var mod = utils.AddMod(); var mod = await utils.AddMod();
var file = utils.AddModFile(mod, @"baz.bin", 128); var file = await utils.AddModFile(mod, @"baz.bin", 128);
await utils.Configure(); await utils.Configure();
@ -362,14 +362,14 @@ namespace Wabbajack.Test
}, new MemoryStream(await file.ReadAllBytesAsync())); }, new MemoryStream(await file.ReadAllBytesAsync()));
await bsa.Build(tempFile.Path); await bsa.Build(tempFile.Path);
} }
tempFile.Path.CopyTo(file.Parent.Combine("bsa_data.bsa")); await tempFile.Path.CopyToAsync(file.Parent.Combine("bsa_data.bsa"));
var archive = utils.AddManualDownload( var archive = utils.AddManualDownload(
new Dictionary<string, byte[]> { { "/stuff/files.bsa", await tempFile.Path.ReadAllBytesAsync() } }); new Dictionary<string, byte[]> { { "/stuff/files.bsa", await tempFile.Path.ReadAllBytesAsync() } });
await CompileAndInstall(profile); await CompileAndInstall(profile);
utils.VerifyInstalledFile(mod, @"baz.bin"); await utils.VerifyInstalledFile(mod, @"baz.bin");
utils.VerifyInstalledFile(mod, @"bsa_data.bsa"); await utils.VerifyInstalledFile(mod, @"bsa_data.bsa");
} }
@ -377,8 +377,8 @@ namespace Wabbajack.Test
public async Task CanRecreateBSAsFromFilesSourcedInOtherBSAs() public async Task CanRecreateBSAsFromFilesSourcedInOtherBSAs()
{ {
var profile = utils.AddProfile(); var profile = utils.AddProfile();
var mod = utils.AddMod(); var mod = await utils.AddMod();
var file = utils.AddModFile(mod, @"baz.bsa", 10); var file = await utils.AddModFile(mod, @"baz.bsa", 10);
await utils.Configure(); await utils.Configure();
@ -414,7 +414,7 @@ namespace Wabbajack.Test
await CompileAndInstall(profile); await CompileAndInstall(profile);
utils.VerifyInstalledFile(mod, @"baz.bsa"); await utils.VerifyInstalledFile(mod, @"baz.bsa");
} }
@ -425,8 +425,8 @@ namespace Wabbajack.Test
Consts.TestMode = false; Consts.TestMode = false;
var profile = utils.AddProfile(); var profile = utils.AddProfile();
var mod = utils.AddMod(); var mod = await utils.AddMod();
var skyrimExe = utils.AddModFile(mod, @"Data\test.exe", 10); var skyrimExe = await utils.AddModFile(mod, @"Data\test.exe", 10);
var gameFolder = Consts.GameFolderFilesDir.RelativeTo(utils.MO2Folder); var gameFolder = Consts.GameFolderFilesDir.RelativeTo(utils.MO2Folder);
gameFolder.CreateDirectory(); gameFolder.CreateDirectory();
@ -459,18 +459,18 @@ namespace Wabbajack.Test
{ {
var profile = utils.AddProfile(); var profile = utils.AddProfile();
var mod = utils.AddMod(); var mod = await utils.AddMod();
var testPex = utils.AddModFile(mod, @"Data\scripts\test.pex", 10); var testPex = await utils.AddModFile(mod, @"Data\scripts\test.pex", 10);
await utils.Configure(); await utils.Configure();
await utils.AddModFile(mod, "meta.ini").WriteAllLinesAsync(new[] await (await utils.AddModFile(mod, "meta.ini")).WriteAllLinesAsync(new[]
{ {
"[General]", "notes= fsdaf WABBAJACK_NOMATCH_INCLUDE fadsfsad", "[General]", "notes= fsdaf WABBAJACK_NOMATCH_INCLUDE fadsfsad",
}); });
await CompileAndInstall(profile); await CompileAndInstall(profile);
utils.VerifyInstalledFile(mod, @"Data\scripts\test.pex"); await utils.VerifyInstalledFile(mod, @"Data\scripts\test.pex");
} }
@ -483,11 +483,11 @@ namespace Wabbajack.Test
{ {
var profile = utils.AddProfile(); var profile = utils.AddProfile();
var enabledMod = utils.AddMod(); var enabledMod = await utils.AddMod();
var enabledTestPex = utils.AddModFile(enabledMod, @"Data\scripts\enabledTestPex.pex", 10); var enabledTestPex = await utils.AddModFile(enabledMod, @"Data\scripts\enabledTestPex.pex", 10);
var disabledMod = utils.AddMod(); var disabledMod = await utils.AddMod();
var disabledTestPex = utils.AddModFile(disabledMod, @"Data\scripts\disabledTestPex.pex", 10); var disabledTestPex = await utils.AddModFile(disabledMod, @"Data\scripts\disabledTestPex.pex", 10);
await disabledMod.RelativeTo(utils.ModsFolder).Combine("meta.ini").WriteAllLinesAsync( await disabledMod.RelativeTo(utils.ModsFolder).Combine("meta.ini").WriteAllLinesAsync(
"[General]", "[General]",
@ -499,7 +499,7 @@ namespace Wabbajack.Test
(enabledMod, true) (enabledMod, true)
}); });
utils.AddManualDownload( await utils.AddManualDownload(
new Dictionary<string, byte[]> new Dictionary<string, byte[]>
{ {
{"/file1.pex", await enabledTestPex.ReadAllBytesAsync()}, {"/file1.pex", await enabledTestPex.ReadAllBytesAsync()},
@ -508,8 +508,8 @@ namespace Wabbajack.Test
await CompileAndInstall(profile); await CompileAndInstall(profile);
utils.VerifyInstalledFile(enabledMod, @"Data\scripts\enabledTestPex.pex"); await utils.VerifyInstalledFile(enabledMod, @"Data\scripts\enabledTestPex.pex");
utils.VerifyInstalledFile(disabledMod, @"Data\scripts\disabledTestPex.pex"); await utils.VerifyInstalledFile(disabledMod, @"Data\scripts\disabledTestPex.pex");
var modlistTxt = await utils.InstallFolder.Combine("profiles", profile, "modlist.txt").ReadAllLinesAsync(); var modlistTxt = await utils.InstallFolder.Combine("profiles", profile, "modlist.txt").ReadAllLinesAsync();
Assert.Equal(new string[] Assert.Equal(new string[]

View File

@ -57,7 +57,7 @@ namespace Wabbajack.Test
{ {
Profiles.Do(profile => Profiles.Do(profile =>
{ {
MO2Folder.Combine("profiles", profile, "modlist.txt").WriteAllLines( MO2Folder.Combine("profiles", profile, "modlist.txt").WriteAllLinesAsync(
Mods.Select(s => $"+{s}").ToArray()); Mods.Select(s => $"+{s}").ToArray());
}); });
} }
@ -65,7 +65,7 @@ namespace Wabbajack.Test
{ {
Profiles.Do(profile => Profiles.Do(profile =>
{ {
MO2Folder.Combine("profiles", profile, "modlist.txt").WriteAllLines( MO2Folder.Combine("profiles", profile, "modlist.txt").WriteAllLinesAsync(
enabledMods.Select(s => $"{(s.IsEnabled ? "+" : "-")}{s.ModName}").ToArray()); enabledMods.Select(s => $"{(s.IsEnabled ? "+" : "-")}{s.ModName}").ToArray());
}); });
} }
@ -79,17 +79,14 @@ namespace Wabbajack.Test
return profile_name; return profile_name;
} }
public string AddMod(string name = null) public async Task<string> AddMod(string name = null)
{ {
lock (this) string mod_name = name ?? RandomName();
{ var mod_folder = MO2Folder.Combine(Consts.MO2ModFolderName, (RelativePath)mod_name);
string mod_name = name ?? RandomName(); mod_folder.CreateDirectory();
var mod_folder = MO2Folder.Combine(Consts.MO2ModFolderName, (RelativePath)mod_name); await mod_folder.Combine("meta.ini").WriteAllTextAsync("[General]");
mod_folder.CreateDirectory(); Mods.Add(mod_name);
mod_folder.Combine("meta.ini").WriteAllText("[General]"); return mod_name;
Mods.Add(mod_name);
return mod_name;
}
} }
/// <summary> /// <summary>
@ -100,17 +97,15 @@ namespace Wabbajack.Test
/// <param name="path"></param> /// <param name="path"></param>
/// <param name="random_fill"></param> /// <param name="random_fill"></param>
/// <returns></returns> /// <returns></returns>
public AbsolutePath AddModFile(string mod_name, string path, int random_fill=128) public async Task<AbsolutePath> AddModFile(string mod_name, string path, int random_fill=128)
{ {
var full_path = ModsFolder.Combine(mod_name, path); var full_path = ModsFolder.Combine(mod_name, path);
full_path.Parent.CreateDirectory(); full_path.Parent.CreateDirectory();
GenerateRandomFileData(full_path, random_fill); await GenerateRandomFileData(full_path, random_fill);
return full_path; return full_path;
} }
public void GenerateRandomFileData(AbsolutePath full_path, int random_fill) public async Task GenerateRandomFileData(AbsolutePath full_path, int random_fill)
{ {
byte[] bytes = new byte[0]; byte[] bytes = new byte[0];
if (random_fill != 0) if (random_fill != 0)
@ -118,7 +113,7 @@ namespace Wabbajack.Test
bytes = new byte[random_fill]; bytes = new byte[random_fill];
RNG.NextBytes(bytes); RNG.NextBytes(bytes);
} }
full_path.WriteAllBytes(bytes); await full_path.WriteAllBytesAsync(bytes);
} }
public static byte[] RandomData(int? size = null, int maxSize = 1024) public static byte[] RandomData(int? size = null, int maxSize = 1024)
@ -162,20 +157,20 @@ namespace Wabbajack.Test
return data; return data;
} }
public string AddManualDownload(Dictionary<string, byte[]> contents) public async ValueTask<string> AddManualDownload(Dictionary<string, byte[]> contents)
{ {
var name = RandomName() + ".zip"; var name = RandomName() + ".zip";
using FileStream fs = DownloadsFolder.Combine(name).Create(); await using FileStream fs = await DownloadsFolder.Combine(name).Create();
using ZipArchive archive = new ZipArchive(fs, ZipArchiveMode.Create); using ZipArchive archive = new ZipArchive(fs, ZipArchiveMode.Create);
contents.Do(kv => contents.Do(kv =>
{ {
var entry = archive.CreateEntry(kv.Key); var entry = archive.CreateEntry(kv.Key);
using (var os = entry.Open()) using var os = entry.Open();
os.Write(kv.Value, 0, kv.Value.Length); os.Write(kv.Value, 0, kv.Value.Length);
}); });
DownloadsFolder.Combine(name + Consts.MetaFileExtension).WriteAllLines( await DownloadsFolder.Combine(name + Consts.MetaFileExtension).WriteAllLinesAsync(
"[General]", "[General]",
"manualURL=<TESTING>" "manualURL=<TESTING>"
); );
@ -227,7 +222,7 @@ namespace Wabbajack.Test
return InstallFolder.Combine((string)Consts.MO2ModFolderName, mod, file); return InstallFolder.Combine((string)Consts.MO2ModFolderName, mod, file);
} }
public void VerifyAllFiles(bool gameFileShouldNotExistInGameFolder = true) public async ValueTask VerifyAllFiles(bool gameFileShouldNotExistInGameFolder = true)
{ {
if (gameFileShouldNotExistInGameFolder) if (gameFileShouldNotExistInGameFolder)
{ {
@ -264,16 +259,16 @@ namespace Wabbajack.Test
if (!skipExtensions.Contains(srcFile.Extension)) if (!skipExtensions.Contains(srcFile.Extension))
{ {
Assert.Equal(srcFile.Size, destFile.Size); Assert.Equal(srcFile.Size, destFile.Size);
Assert.Equal(srcFile.FileHash(), destFile.FileHash()); Assert.Equal(await srcFile.FileHashAsync(), await destFile.FileHashAsync());
} }
} }
} }
public AbsolutePath AddGameFile(string path, int i) public async ValueTask<AbsolutePath> AddGameFile(string path, int i)
{ {
var fullPath = GameFolder.Combine(path); var fullPath = GameFolder.Combine(path);
fullPath.Parent.CreateDirectory(); fullPath.Parent.CreateDirectory();
GenerateRandomFileData(fullPath, i); await GenerateRandomFileData(fullPath, i);
return fullPath; return fullPath;
} }
} }

View File

@ -15,13 +15,13 @@ namespace Wabbajack.Test
public async Task CanCreatezEditPatches() public async Task CanCreatezEditPatches()
{ {
var profile = utils.AddProfile(); var profile = utils.AddProfile();
var moda = utils.AddMod(); var moda = await utils.AddMod();
var modb = utils.AddMod(); var modb = await utils.AddMod();
var moddest = utils.AddMod(); var moddest = await utils.AddMod();
var srca = utils.AddModFile(moda, @"srca.esp", 10); var srca = await utils.AddModFile(moda, @"srca.esp", 10);
var srcb = utils.AddModFile(moda, @"srcb.esp.mohidden", 10); var srcb = await utils.AddModFile(moda, @"srcb.esp.mohidden", 10);
var srcc = utils.AddModFile(modb, @"optional\srcc.esp", 10); var srcc = await utils.AddModFile(modb, @"optional\srcc.esp", 10);
var dest = utils.AddModFile(moddest, @"merged.esp", 20); var dest = await utils.AddModFile(moddest, @"merged.esp", 20);
var srcs = new List<string> {srca, srcb, srcc}; var srcs = new List<string> {srca, srcb, srcc};

View File

@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Reactive; using System.Reactive;
using System.Reactive.Subjects; using System.Reactive.Subjects;
using System.Threading.Tasks;
using Wabbajack.Common; using Wabbajack.Common;
using Wabbajack.Common.Serialization.Json; using Wabbajack.Common.Serialization.Json;
using Wabbajack.Lib; using Wabbajack.Lib;
@ -29,20 +30,19 @@ namespace Wabbajack
[JsonIgnore] [JsonIgnore]
public IObservable<Unit> SaveSignal => _saveSignal; public IObservable<Unit> SaveSignal => _saveSignal;
public static bool TryLoadTypicalSettings(out MainSettings settings) public static async ValueTask<(MainSettings settings, bool loaded)> TryLoadTypicalSettings()
{ {
if (!Consts.SettingsFile.Exists) if (!Consts.SettingsFile.Exists)
{ {
settings = default; return default;
return false;
} }
// Version check // Version check
try try
{ {
settings = Consts.SettingsFile.FromJson<MainSettings>(); var settings = Consts.SettingsFile.FromJson<MainSettings>();
if (settings.Version == Consts.SettingsVersion) if (settings.Version == Consts.SettingsVersion)
return true; return (settings, true);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -52,14 +52,13 @@ namespace Wabbajack
var backup = Consts.SettingsFile.AppendToName("-backup"); var backup = Consts.SettingsFile.AppendToName("-backup");
backup.Delete(); backup.Delete();
Consts.SettingsFile.CopyTo(backup); await Consts.SettingsFile.CopyToAsync(backup);
Consts.SettingsFile.Delete(); Consts.SettingsFile.Delete();
settings = default; return default;
return false;
} }
public static void SaveSettings(MainSettings settings) public static async ValueTask SaveSettings(MainSettings settings)
{ {
settings._saveSignal.OnNext(Unit.Default); settings._saveSignal.OnNext(Unit.Default);
@ -68,7 +67,7 @@ namespace Wabbajack
//settings._saveSignal.OnCompleted(); //settings._saveSignal.OnCompleted();
//await settings._saveSignal; //await settings._saveSignal;
settings.ToJson(Consts.SettingsFile); await settings.ToJsonAsync(Consts.SettingsFile);
} }
} }

View File

@ -144,11 +144,11 @@ namespace Wabbajack
.Unit() .Unit()
.StartWith(Unit.Default) .StartWith(Unit.Default)
.FlowSwitch(_parent.WhenAny(x => x.IsActive)) .FlowSwitch(_parent.WhenAny(x => x.IsActive))
.Select(_ => .SelectAsync(async _ =>
{ {
try try
{ {
return !metadata.NeedsDownload(Location); return !(await metadata.NeedsDownload(Location));
} }
catch (Exception) catch (Exception)
{ {
@ -185,7 +185,7 @@ namespace Wabbajack
var downloader = DownloadDispatcher.ResolveArchive(Metadata.Links.Download); var downloader = DownloadDispatcher.ResolveArchive(Metadata.Links.Download);
var result = await downloader.Download(new Archive(state: null!) { Name = Metadata.Title, Size = Metadata.DownloadMetadata?.Size ?? 0 }, Location); var result = await downloader.Download(new Archive(state: null!) { Name = Metadata.Title, Size = Metadata.DownloadMetadata?.Size ?? 0 }, Location);
// Want to rehash to current file, even if failed? // Want to rehash to current file, even if failed?
Location.FileHashCached(); await Location.FileHashCachedAsync();
tcs.SetResult(result); tcs.SetResult(result);
} }
catch (Exception ex) catch (Exception ex)

View File

@ -199,7 +199,7 @@ namespace Wabbajack
Settings.PosY = MainWindow.Top; Settings.PosY = MainWindow.Top;
Settings.Width = MainWindow.Width; Settings.Width = MainWindow.Width;
Settings.Height = MainWindow.Height; Settings.Height = MainWindow.Height;
MainSettings.SaveSettings(Settings); MainSettings.SaveSettings(Settings).AsTask().Wait();
Application.Current.Shutdown(); Application.Current.Shutdown();
} }
} }

View File

@ -45,19 +45,17 @@ namespace Wabbajack
ImageObservable = Observable.Return(Unit.Default) ImageObservable = Observable.Return(Unit.Default)
// Download and retrieve bytes on background thread // Download and retrieve bytes on background thread
.ObserveOn(RxApp.TaskpoolScheduler) .ObserveOn(RxApp.TaskpoolScheduler)
.Select(filePath => .SelectAsync(async filePath =>
{ {
try try
{ {
using var fs = ModListPath.OpenShared(); await using var fs = await ModListPath.OpenShared();
using var ar = new ZipArchive(fs, ZipArchiveMode.Read); using var ar = new ZipArchive(fs, ZipArchiveMode.Read);
var ms = new MemoryStream(); var ms = new MemoryStream();
var entry = ar.GetEntry("modlist-image.png"); var entry = ar.GetEntry("modlist-image.png");
if (entry == null) return default(MemoryStream); if (entry == null) return default(MemoryStream);
using (var e = entry.Open()) await using var e = entry.Open();
{ e.CopyTo(ms);
e.CopyTo(ms);
}
return ms; return ms;
} }
catch (Exception ex) catch (Exception ex)
@ -82,10 +80,7 @@ namespace Wabbajack
} }
}) })
// If ever would return null, show WJ logo instead // If ever would return null, show WJ logo instead
.Select(x => .Select(x => x ?? ResourceLinks.WabbajackLogoNoText.Value)
{
return x ?? ResourceLinks.WabbajackLogoNoText.Value;
})
.Replay(1) .Replay(1)
.RefCount(); .RefCount();
} }

View File

@ -45,8 +45,9 @@ namespace Wabbajack
Warmup(); Warmup();
var (settings, loadedSettings) = MainSettings.TryLoadTypicalSettings().AsTask().Result;
// Load settings // Load settings
if (CLIArguments.NoSettings || !MainSettings.TryLoadTypicalSettings(out var settings)) if (CLIArguments.NoSettings || !loadedSettings)
{ {
_settings = new MainSettings _settings = new MainSettings
{ {