mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Merge pull request #153 from wabbajack-tools/manual-download-guidence
Manual Download Guidence
This commit is contained in:
commit
4d68a0c5cb
@ -103,17 +103,25 @@ namespace Wabbajack.Common
|
|||||||
return sha.Hash.ToBase64();
|
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();
|
try
|
||||||
hash.HashSizeInBits = 64;
|
|
||||||
hash.Seed = 0x42;
|
|
||||||
using (var fs = File.OpenRead(file))
|
|
||||||
{
|
{
|
||||||
var config = new xxHashConfig();
|
var hash = new xxHashConfig();
|
||||||
config.HashSizeInBits = 64;
|
hash.HashSizeInBits = 64;
|
||||||
var value = xxHashFactory.Instance.Create(config).ComputeHash(fs);
|
hash.Seed = 0x42;
|
||||||
return value.AsBase64String();
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,8 +18,8 @@ namespace Wabbajack.Lib.Downloaders
|
|||||||
new ModDBDownloader(),
|
new ModDBDownloader(),
|
||||||
new NexusDownloader(),
|
new NexusDownloader(),
|
||||||
new MediaFireDownloader(),
|
new MediaFireDownloader(),
|
||||||
|
new HTTPDownloader(),
|
||||||
new ManualDownloader(),
|
new ManualDownloader(),
|
||||||
new HTTPDownloader()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly Dictionary<Type, IDownloader> IndexedDownloaders;
|
private static readonly Dictionary<Type, IDownloader> IndexedDownloaders;
|
||||||
|
@ -1,15 +1,67 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reactive.Linq;
|
||||||
|
using System.Reactive.Subjects;
|
||||||
|
using System.Reactive.Threading.Tasks;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Syroot.Windows.IO;
|
||||||
using Wabbajack.Common;
|
using Wabbajack.Common;
|
||||||
using Wabbajack.Lib.Validation;
|
using Wabbajack.Lib.Validation;
|
||||||
|
using File = System.IO.File;
|
||||||
|
|
||||||
namespace Wabbajack.Lib.Downloaders
|
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)
|
public AbstractDownloadState GetDownloaderState(dynamic archive_ini)
|
||||||
{
|
{
|
||||||
var url = archive_ini?.General?.manualURL;
|
var url = archive_ini?.General?.manualURL;
|
||||||
@ -30,7 +82,33 @@ namespace Wabbajack.Lib.Downloaders
|
|||||||
|
|
||||||
public override void Download(Archive a, string destination)
|
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()
|
public override bool Verify()
|
||||||
|
@ -229,19 +229,6 @@ namespace Wabbajack.Lib
|
|||||||
Info("Done! You may now exit the application!");
|
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>
|
/// <summary>
|
||||||
/// We don't want to make the installer index all the archives, that's just a waste of time, so instead
|
/// 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.
|
/// 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");
|
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)
|
foreach (var dispatcher in dispatchers)
|
||||||
dispatcher.Prepare();
|
dispatcher.Prepare();
|
||||||
|
|
||||||
DownloadMissingArchives(missing);
|
DownloadMissingArchives(missing);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DownloadMissingArchives(List<Archive> missing, bool download = true)
|
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}");
|
Info($"Downloading {archive.Name}");
|
||||||
var output_path = Path.Combine(DownloadFolder, archive.Name);
|
var output_path = Path.Combine(DownloadFolder, archive.Name);
|
||||||
|
@ -54,6 +54,9 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="PresentationCore" />
|
<Reference Include="PresentationCore" />
|
||||||
<Reference Include="PresentationFramework" />
|
<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" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
<Reference Include="System.Design" />
|
<Reference Include="System.Design" />
|
||||||
@ -186,6 +189,9 @@
|
|||||||
<PackageReference Include="SharpCompress">
|
<PackageReference Include="SharpCompress">
|
||||||
<Version>0.23.0</Version>
|
<Version>0.23.0</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
<PackageReference Include="Syroot.Windows.IO.KnownFolders">
|
||||||
|
<Version>1.2.1</Version>
|
||||||
|
</PackageReference>
|
||||||
<PackageReference Include="System.Reactive">
|
<PackageReference Include="System.Reactive">
|
||||||
<Version>4.2.0</Version>
|
<Version>4.2.0</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
@ -147,6 +147,29 @@ namespace Wabbajack.Test
|
|||||||
Assert.AreEqual(File.ReadAllText(filename), "Cheese for Everyone!");
|
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]
|
[TestMethod]
|
||||||
public void MediaFireDownload()
|
public void MediaFireDownload()
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user