Implement mod list maintainer

This commit is contained in:
Timothy Baldridge 2021-12-27 08:37:20 -07:00
parent 9a13413472
commit bf5d092f43
4 changed files with 102 additions and 9 deletions

View File

@ -13,6 +13,7 @@ using System.Windows.Input;
using System.Windows.Media.Imaging;
using Alphaleonis.Win32.Filesystem;
using DynamicData;
using Microsoft.Extensions.Logging;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using Wabbajack.Common;
@ -23,7 +24,9 @@ using Wabbajack.Lib.Downloaders;
using Wabbajack.Lib.Extensions;
using Wabbajack.Lib.ModListRegistry;
using Wabbajack.Paths;
using Wabbajack.Paths.IO;
using Wabbajack.RateLimiter;
using Wabbajack.Services.OSIntegrated.Services;
namespace Wabbajack
{
@ -84,12 +87,17 @@ namespace Wabbajack
public bool LoadingImage => _LoadingImage.Value;
private Subject<bool> IsLoadingIdle;
private readonly ILogger<ModListMetadataVM> _logger;
private readonly ModListDownloadMaintainer _maintainer;
public ModListMetadataVM(ModListGalleryVM parent, ModlistMetadata metadata)
public ModListMetadataVM(ILogger<ModListMetadataVM> logger, ModListGalleryVM parent, ModlistMetadata metadata,
ModListDownloadMaintainer maintainer)
{
_logger = logger;
_parent = parent;
_maintainer = maintainer;
Metadata = metadata;
Location = LauncherUpdater.CommonFolder.Value.Combine("downloaded_mod_lists", Metadata.Links.MachineURL + (string)Consts.ModListExtension);
Location = LauncherUpdater.CommonFolder.Value.Combine("downloaded_mod_lists", Metadata.Links.MachineURL).WithExtension(Ext.Wabbajack);
ModListTagList = new List<ModListTag>();
Metadata.tags.ForEach(tag =>
@ -103,7 +111,7 @@ namespace Wabbajack
VersionText = "Modlist version : " + Metadata.Version;
IsBroken = metadata.ValidationSummary.HasFailures || metadata.ForceDown;
//https://www.wabbajack.org/#/modlists/info?machineURL=eldersouls
OpenWebsiteCommand = ReactiveCommand.Create(() => Utils.OpenWebsite(new Uri($"https://www.wabbajack.org/#/modlists/info?machineURL={Metadata.Links.MachineURL}")));
OpenWebsiteCommand = ReactiveCommand.Create(() => UIUtils.OpenWebsite(new Uri($"https://www.wabbajack.org/#/modlists/info?machineURL={Metadata.Links.MachineURL}")));
IsLoadingIdle = new Subject<bool>();
@ -152,7 +160,7 @@ namespace Wabbajack
return false;
}
// Return an updated check on exists
return Location.Exists;
return Location.FileExists();
}
return exists;
})
@ -175,7 +183,7 @@ namespace Wabbajack
}
catch (Exception ex)
{
Utils.Error(ex);
_logger.LogError(ex, "While opening modlist README");
}
});
})
@ -190,7 +198,7 @@ namespace Wabbajack
{
try
{
return !IsDownloading && !(await metadata.NeedsDownload(Location));
return !IsDownloading && !(await maintainer.HaveModList(metadata));
}
catch (Exception)
{
@ -200,7 +208,7 @@ namespace Wabbajack
.ToGuiProperty(this, nameof(Exists));
var imageObs = Observable.Return(Metadata.Links.ImageUri)
.DownloadBitmapImage((ex) => Utils.Log($"Error downloading modlist image {Metadata.Title}"));
.DownloadBitmapImage((ex) => _logger.LogError("Error downloading modlist image {Title}", Metadata.Title));
_Image = imageObs
.ToGuiProperty(this, nameof(Image));
@ -227,8 +235,8 @@ namespace Wabbajack
try
{
IsDownloading = true;
Utils.Log($"Starting Download of {Metadata.Links.MachineURL}");
var downloader = DownloadDispatcher.ResolveArchive(Metadata.Links.Download);
_logger.LogInformation("Starting Download of {MachineUrl}", Metadata.Links.MachineURL);
var downloader = await DownloadDispatcher.ResolveArchive(Metadata.Links.Download);
var result = await downloader.Download(
new Archive(state: null!)
{

View File

@ -27,10 +27,14 @@ public class Job<T> : IJob, IDisposable
{
await Resource.Report(this, processedSize, token);
Current += processedSize;
OnUpdate?.Invoke(this, (Percent.FactoryPutInRange(Current, Size ?? 1), Current));
}
public void ReportNoWait(int processedSize)
{
Resource.ReportNoWait(this, processedSize);
OnUpdate?.Invoke(this, (Percent.FactoryPutInRange(Current, Size ?? 1), Current));
}
public event EventHandler<(Percent Progress, long Processed)> OnUpdate;
}

View File

@ -19,6 +19,7 @@ using Wabbajack.Networking.WabbajackClientApi;
using Wabbajack.Paths;
using Wabbajack.Paths.IO;
using Wabbajack.RateLimiter;
using Wabbajack.Services.OSIntegrated.Services;
using Wabbajack.Services.OSIntegrated.TokenProviders;
using Wabbajack.VFS;
@ -99,6 +100,8 @@ public static class ServiceExtensions
service.AddScoped<Context>();
service.AddSingleton<FileExtractor.FileExtractor>();
service.AddSingleton<ModListDownloadMaintainer>();
// Networking
service.AddSingleton<HttpClient>();
service.AddAllSingleton<IHttpDownloader, SingleThreadedDownloader>();

View File

@ -0,0 +1,78 @@
using System;
using System.Reactive.Subjects;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Wabbajack.Common;
using Wabbajack.Downloaders;
using Wabbajack.DTOs;
using Wabbajack.Paths;
using Wabbajack.Paths.IO;
using Wabbajack.RateLimiter;
using Wabbajack.VFS;
namespace Wabbajack.Services.OSIntegrated.Services;
public class ModListDownloadMaintainer
{
private readonly ILogger<ModListDownloadMaintainer> _logger;
private readonly Configuration _configuration;
private readonly DownloadDispatcher _dispatcher;
private readonly FileHashCache _hashCache;
private readonly IResource<DownloadDispatcher> _rateLimiter;
public ModListDownloadMaintainer(ILogger<ModListDownloadMaintainer> logger, Configuration configuration,
DownloadDispatcher dispatcher, FileHashCache hashCache, IResource<DownloadDispatcher> rateLimiter)
{
_logger = logger;
_configuration = configuration;
_dispatcher = dispatcher;
_hashCache = hashCache;
_rateLimiter = rateLimiter;
}
public AbsolutePath ModListPath(ModlistMetadata metadata)
{
return _configuration.ModListsDownloadLocation.Combine(metadata.Links.MachineURL).WithExtension(Ext.Wabbajack);
}
public async Task<bool> HaveModList(ModlistMetadata metadata, CancellationToken? token = null)
{
token ??= CancellationToken.None;
var path = ModListPath(metadata);
if (!path.FileExists()) return false;
return await _hashCache.FileHashCachedAsync(path, token.Value) == metadata.DownloadMetadata!.Hash;
}
public (IObservable<Percent> Progress, Task Task) DownloadModlist(ModlistMetadata metadata, CancellationToken? token = null)
{
var path = ModListPath(metadata);
token ??= CancellationToken.None;
var progress = new Subject<Percent>();
progress.OnNext(Percent.Zero);
var tsk = Task.Run(async () =>
{
var job = await _rateLimiter.Begin($"Downloading {metadata.Title}", metadata.DownloadMetadata!.Size, token.Value);
job.OnUpdate += (_, pr) =>
{
progress.OnNext(pr.Progress);
};
var hash = await _dispatcher.Download(new Archive()
{
State = _dispatcher.Parse(new Uri(metadata.Links.Download))!,
Size = metadata.DownloadMetadata.Size,
Hash = metadata.DownloadMetadata.Hash
}, path, job, token.Value);
_hashCache.FileHashWriteCache(path, hash);
});
return (progress, tsk);
}
}