wabbajack/Wabbajack.Lib/Downloaders/ManualDownloader.cs
Timothy Baldridge db3b441d19 #### Version - 2.3.6.1 - 12/31/2020
* When IPS4 (e.g. LL) sites based on CEF fail to validate, they no longer hang the app
* If a IPS4 CEF site throws a 503, or 400 error, retry
* Clean out the cookies during IPS4 CEF downloads so that they don't cause 400 errors
* Limit the number of connections to IPS4 sites to 20 per minute (one per 6 seconds)
* If a site *does* timeout, throw a log of the CEF state into `CEFStates` for easier debugging by the WJ team
* Wrote a new CLI utility to stress test the Verification routines.
* Ignore files that have `\Edit Scripts\Export\` in their path
2020-12-30 23:44:58 -07:00

123 lines
3.6 KiB
C#

using System.IO;
using System.Linq;
using System.Reactive.Subjects;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Wabbajack.Common;
using Wabbajack.Common.IO;
using Wabbajack.Common.Serialization.Json;
using Wabbajack.Lib.Validation;
namespace Wabbajack.Lib.Downloaders
{
public class ManualDownloader : IDownloader
{
private FileSystemWatcher _watcher;
private Subject<FileEvent> _fileEvents = new Subject<FileEvent>();
private KnownFolder _downloadfolder;
public readonly AsyncLock Lock = new AsyncLock();
class FileEvent
{
public string FullPath { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public long Size { get; set; }
}
public ManualDownloader()
{
_downloadfolder = new KnownFolder(KnownFolderType.Downloads);
_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 async Task<AbstractDownloadState?> GetDownloaderState(dynamic archiveINI, bool quickMode)
{
var url = archiveINI?.General?.manualURL;
return url != null ? new State(url) : null;
}
public async Task Prepare()
{
}
[JsonName("ManualDownloader")]
public class State : AbstractDownloadState
{
public string Url { get; }
[JsonIgnore]
public override object[] PrimaryKey => new object[] { Url };
public State(string url)
{
Url = url;
}
public override bool IsWhitelisted(ServerWhitelist whitelist)
{
return Url == "<TESTING>" || whitelist.AllowedPrefixes.Any(p => Url.StartsWith(p));
}
public override async Task<bool> Download(Archive a, AbsolutePath destination)
{
var (uri, client) = await Utils.Log(await ManuallyDownloadFile.Create(this)).Task;
var state = new HTTPDownloader.State(uri.ToString()) { Client = client };
return await state.Download(a, destination);
}
public override async Task<bool> Verify(Archive a, CancellationToken? token)
{
return true;
}
public override IDownloader GetDownloader()
{
return DownloadDispatcher.GetInstance<ManualDownloader>();
}
public override string GetManifestURL(Archive a)
{
return Url;
}
public override string[] GetMetaIni()
{
return new []
{
"[General]",
$"manualURL={Url}",
};
}
}
}
}