Merge pull request #153 from wabbajack-tools/manual-download-guidence

Manual Download Guidence
This commit is contained in:
Timothy Baldridge 2019-11-06 21:42:43 -07:00 committed by GitHub
commit 4d68a0c5cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 140 additions and 28 deletions

View File

@ -103,17 +103,25 @@ namespace Wabbajack.Common
return sha.Hash.ToBase64();
}
public static string FileHash(this string file)
public static string FileHash(this string file, bool nullOnIOError = false)
{
var hash = new xxHashConfig();
hash.HashSizeInBits = 64;
hash.Seed = 0x42;
using (var fs = File.OpenRead(file))
try
{
var config = new xxHashConfig();
config.HashSizeInBits = 64;
var value = xxHashFactory.Instance.Create(config).ComputeHash(fs);
return value.AsBase64String();
var hash = new xxHashConfig();
hash.HashSizeInBits = 64;
hash.Seed = 0x42;
using (var fs = File.OpenRead(file))
{
var config = new xxHashConfig();
config.HashSizeInBits = 64;
var value = xxHashFactory.Instance.Create(config).ComputeHash(fs);
return value.AsBase64String();
}
}
catch (IOException ex)
{
if (nullOnIOError) return null;
throw ex;
}
}

View File

@ -18,8 +18,8 @@ namespace Wabbajack.Lib.Downloaders
new ModDBDownloader(),
new NexusDownloader(),
new MediaFireDownloader(),
new HTTPDownloader(),
new ManualDownloader(),
new HTTPDownloader()
};
private static readonly Dictionary<Type, IDownloader> IndexedDownloaders;

View File

@ -1,15 +1,67 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Reactive.Threading.Tasks;
using System.Text;
using System.Threading.Tasks;
using Syroot.Windows.IO;
using Wabbajack.Common;
using Wabbajack.Lib.Validation;
using File = System.IO.File;
namespace Wabbajack.Lib.Downloaders
{
class ManualDownloader : IDownloader
public class ManualDownloader : IDownloader
{
private FileSystemWatcher _watcher;
private Subject<FileEvent> _fileEvents = new Subject<FileEvent>();
private KnownFolder _downloadfolder;
class FileEvent
{
public string FullPath { get; set; }
public string Name { get; set; }
public long Size { get; set; }
}
public ManualDownloader()
{
_downloadfolder = new KnownFolder(KnownFolderType.DownloadsLocalized);
_watcher = new FileSystemWatcher(_downloadfolder.Path);
_watcher.Created += _watcher_Created;
_watcher.Changed += _watcher_Changed;
}
private void _watcher_Changed(object sender, FileSystemEventArgs e)
{
PublishEvent(e);
}
private void _watcher_Created(object sender, FileSystemEventArgs e)
{
PublishEvent(e);
}
private void PublishEvent(FileSystemEventArgs e)
{
try
{
_fileEvents.OnNext(new FileEvent
{
Size = new FileInfo(e.FullPath).Length,
Name = e.Name,
FullPath = e.FullPath
});
}
catch (IOException)
{
}
}
public AbstractDownloadState GetDownloaderState(dynamic archive_ini)
{
var url = archive_ini?.General?.manualURL;
@ -30,7 +82,33 @@ namespace Wabbajack.Lib.Downloaders
public override void Download(Archive a, string destination)
{
Utils.Log($"You must manually visit {Url} and download {a.Name} file by hand.");
var downloader = (ManualDownloader)GetDownloader();
var abs_path = Path.Combine(downloader._downloadfolder.Path, a.Name);
lock (downloader)
{
try
{
Utils.Log($"You must manually visit {Url} and download {a.Name} file by hand.");
Utils.Log($"Waiting for {a.Name}");
downloader._watcher.EnableRaisingEvents = true;
var watcher = downloader._fileEvents
.Where(f => f.Size == a.Size)
.Where(f => f.FullPath.FileHash(true) == a.Hash)
.Buffer(new TimeSpan(0, 5, 0), 1)
.Select(x => x.FirstOrDefault())
.FirstOrDefaultAsync();
Process.Start(Url);
abs_path = watcher.Wait()?.FullPath;
if (!File.Exists(abs_path))
throw new InvalidDataException($"File not found after manual download operation");
File.Move(abs_path, destination);
}
finally
{
downloader._watcher.EnableRaisingEvents = false;
}
}
}
public override bool Verify()

View File

@ -229,19 +229,6 @@ namespace Wabbajack.Lib
Info("Done! You may now exit the application!");
}
private bool LocateGameFolder()
{
var fs = UIUtils.ShowFolderSelectionDialog("Please locate your game installation path");
if (fs != null)
{
GameFolder = fs;
return true;
}
return false;
}
/// <summary>
/// We don't want to make the installer index all the archives, that's just a waste of time, so instead
/// we'll pass just enough information to VFS to let it know about the files we have.
@ -457,17 +444,27 @@ namespace Wabbajack.Lib
Info("Getting Nexus API Key, if a browser appears, please accept");
var dispatchers = ModList.Archives.Select(m => m.State.GetDownloader()).Distinct();
var dispatchers = missing.Select(m => m.State.GetDownloader()).Distinct();
foreach (var dispatcher in dispatchers)
dispatcher.Prepare();
DownloadMissingArchives(missing);
}
private void DownloadMissingArchives(List<Archive> missing, bool download = true)
{
missing.PMap(archive =>
if (download)
{
foreach (var a in missing.Where(a => a.State.GetType() == typeof(ManualDownloader.State)))
{
var output_path = Path.Combine(DownloadFolder, a.Name);
a.State.Download(a, output_path);
}
}
missing.Where(a => a.State.GetType() != typeof(ManualDownloader.State))
.PMap(archive =>
{
Info($"Downloading {archive.Name}");
var output_path = Path.Combine(DownloadFolder, archive.Name);

View File

@ -54,6 +54,9 @@
<ItemGroup>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="Syroot.KnownFolders">
<HintPath>..\..\..\Users\tbald\.nuget\packages\syroot.windows.io.knownfolders\1.2.1\lib\net452\Syroot.KnownFolders.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Design" />
@ -186,6 +189,9 @@
<PackageReference Include="SharpCompress">
<Version>0.23.0</Version>
</PackageReference>
<PackageReference Include="Syroot.Windows.IO.KnownFolders">
<Version>1.2.1</Version>
</PackageReference>
<PackageReference Include="System.Reactive">
<Version>4.2.0</Version>
</PackageReference>

View File

@ -147,6 +147,29 @@ namespace Wabbajack.Test
Assert.AreEqual(File.ReadAllText(filename), "Cheese for Everyone!");
}
[TestMethod]
public void ManualDownload()
{
var ini = @"[General]
manualURL=http://build.wabbajack.org/WABBAJACK_TEST_FILE.zip";
var state = (AbstractDownloadState)DownloadDispatcher.ResolveArchive(ini.LoadIniString());
Assert.IsNotNull(state);
var converted = state.ViaJSON();
Assert.IsTrue(converted.Verify());
var filename = Guid.NewGuid().ToString();
Assert.IsTrue(converted.IsWhitelisted(new ServerWhitelist { AllowedPrefixes = new List<string> { "http://build.wabbajack.org/" } }));
converted.Download(new Archive { Name = "WABBAJACK_TEST_FILE.zip", Size = 20, Hash = "eSIyd+KOG3s="}, filename);
Assert.AreEqual("eSIyd+KOG3s=", Utils.FileHash(filename));
Assert.AreEqual(File.ReadAllText(filename), "Cheese for Everyone!");
}
[TestMethod]
public void MediaFireDownload()
{