diff --git a/Wabbajack.Lib/Consts.cs b/Wabbajack.Lib/Consts.cs new file mode 100644 index 00000000..8832eaac --- /dev/null +++ b/Wabbajack.Lib/Consts.cs @@ -0,0 +1,6 @@ +namespace Wabbajack.Lib; + +public static class Consts +{ + public static string AppName = "Wabbajack"; +} \ No newline at end of file diff --git a/Wabbajack.Lib/Data.cs b/Wabbajack.Lib/Data.cs deleted file mode 100644 index c2355deb..00000000 --- a/Wabbajack.Lib/Data.cs +++ /dev/null @@ -1,318 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Compression.BSA; -using Newtonsoft.Json; -using Wabbajack.Common; -using Wabbajack.Common.Serialization.Json; -using Wabbajack.ImageHashing; -using Wabbajack.Lib.Downloaders; -using Wabbajack.VirtualFileSystem; - -namespace Wabbajack.Lib -{ - public class RawSourceFile - { - public readonly RelativePath Path; - - public RawSourceFile(VirtualFile file, RelativePath path) - { - File = file; - Path = path; - } - - public AbsolutePath AbsolutePath - { - get - { - if (!File.IsNative) - throw new InvalidDataException("Can't get the absolute path of a non-native file"); - return File.FullPath.Base; - } - } - - public VirtualFile File { get; } - - public Hash Hash => File.Hash; - - public T EvolveTo() where T : Directive, new() - { - var v = new T {To = Path, Hash = File.Hash, Size = File.Size}; - return v; - } - } - - [JsonName("ModList")] - public class ModList - { - /// - /// Archives required by this modlist - /// - public List Archives = new List(); - - /// - /// Author of the ModList - /// - public string Author = string.Empty; - - /// - /// Description of the ModList - /// - public string Description = string.Empty; - - /// - /// Install directives - /// - public List Directives = new List(); - - /// - /// The game variant to which this game applies - /// - public Game GameType; - - /// - /// Hash of the banner-image - /// - public RelativePath Image; - - /// - /// The Mod Manager used to create the modlist - /// - public ModManager ModManager; - - /// - /// Name of the ModList - /// - public string Name = string.Empty; - - /// - /// URL to the readme - /// - public string Readme = string.Empty; - - /// - /// The build version of Wabbajack used when compiling the Modlist - /// - public Version? WabbajackVersion; - - /// - /// Website of the ModList - /// - public Uri? Website; - - /// - /// Current Version of the Modlist - /// - public Version Version = new Version(1, 0, 0, 0); - - /// - /// Whether the Modlist is NSFW or not - /// - public bool IsNSFW; - - /// - /// The size of all the archives once they're downloaded - /// - [JsonIgnore] - public long DownloadSize => Archives.Sum(a => a.Size); - - /// - /// The size of all the files once they are installed (excluding downloaded archives) - /// - [JsonIgnore] - public long InstallSize => Directives.Sum(s => s.Size); - - public ModList Clone() - { - using var ms = new MemoryStream(); - this.ToJson(ms); - ms.Position = 0; - return ms.FromJson(); - } - } - - public abstract class Directive - { - public Hash Hash { get; set; } - public long Size { get; set; } - - /// - /// location the file will be copied to, relative to the install path. - /// - public RelativePath To { get; set; } - } - - public class IgnoredDirectly : Directive - { - public string Reason = string.Empty; - } - - public class NoMatch : IgnoredDirectly - { - } - - [JsonName("InlineFile")] - public class InlineFile : Directive - { - /// - /// Data that will be written as-is to the destination location; - /// - public RelativePath SourceDataID { get; set; } - - [JsonIgnore] - public VirtualFile? SourceDataFile { get; set; } - } - - [JsonName("ArchiveMeta")] - public class ArchiveMeta : Directive - { - public RelativePath SourceDataID { get; set; } - } - - public enum PropertyType { Banner, Readme } - - /// - /// File meant to be extracted before the installation - /// - [JsonName("PropertyFile")] - public class PropertyFile : InlineFile - { - public PropertyType Type; - } - - [JsonName("CleanedESM")] - public class CleanedESM : InlineFile - { - public Hash SourceESMHash; - } - - /// - /// A file that has the game and MO2 folders remapped on installation - /// - [JsonName("RemappedInlineFile")] - public class RemappedInlineFile : InlineFile - { - } - - [JsonName("SteamMeta")] - public class SteamMeta : ArchiveMeta - { - public int ItemID { get; set; } - } - - [JsonName("FromArchive")] - public class FromArchive : Directive - { - private string? _fullPath; - - public HashRelativePath ArchiveHashPath { get; set; } - - [JsonIgnore] - public VirtualFile? FromFile { get; set; } - - [JsonIgnore] - public string FullPath => _fullPath ??= string.Join("|", ArchiveHashPath); - } - - [JsonName("CreateBSA")] - public class CreateBSA : Directive - { - public RelativePath TempID { get; set; } - public ArchiveStateObject State { get; } - public List FileStates { get; set; } = new List(); - - public CreateBSA(ArchiveStateObject state, IEnumerable? items = null) - { - State = state; - if (items != null) - { - FileStates.AddRange(items); - } - } - } - - [JsonName("PatchedFromArchive")] - public class PatchedFromArchive : FromArchive - { - public Hash FromHash { get; set; } - - /// - /// The file to apply to the source file to patch it - /// - public RelativePath PatchID { get; set; } - - - /// - /// During compilation this holds several possible files that could be used as a patch source. At the end - /// of compilation we'll go through all of these and find the smallest patch file. - /// - [JsonIgnore] - public VirtualFile[] Choices { get; set; } = { }; - } - - [JsonName("TransformedTexture")] - public class TransformedTexture : FromArchive - { - /// - /// The file to apply to the source file to patch it - /// - public ImageState ImageState { get; set; } = new(); - } - - [JsonName("SourcePatch")] - public class SourcePatch - { - public Hash Hash { get; set; } - public RelativePath RelativePath { get; set; } - } - - [JsonName("MergedPatch")] - public class MergedPatch : Directive - { - public RelativePath PatchID { get; set; } - public List Sources { get; set; } = new List(); - } - - [JsonName("Archive")] - public class Archive - { - /// - /// xxHash64 of the archive - /// - public Hash Hash { get; set; } - - /// - /// Meta INI for the downloaded archive - /// - public string? Meta { get; set; } - - /// - /// Human friendly name of this archive - /// - public string Name { get; set; } = string.Empty; - - public long Size { get; set; } - - public AbstractDownloadState State { get; } - - public Archive(AbstractDownloadState state) - { - State = state; - } - } - - public class IndexedArchive - { - public dynamic? IniData; - public string Meta = string.Empty; - public string Name = string.Empty; - public VirtualFile File { get; } - public AbstractDownloadState? State { get; set; } - - public IndexedArchive(VirtualFile file) - { - File = file; - } - } -} diff --git a/Wabbajack.Lib/LauncherUpdater.cs b/Wabbajack.Lib/LauncherUpdater.cs index d3552281..90f476f7 100644 --- a/Wabbajack.Lib/LauncherUpdater.cs +++ b/Wabbajack.Lib/LauncherUpdater.cs @@ -1,18 +1,51 @@ using System; using System.Diagnostics; using System.Linq; +using System.Net.Http; +using System.Net.Http.Json; +using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.VisualBasic.CompilerServices; using Newtonsoft.Json; -using Wabbajack.Common; -using Wabbajack.Lib.Http; +using Wabbajack.Downloaders; +using Wabbajack.DTOs; +using Wabbajack.DTOs.DownloadStates; +using Wabbajack.DTOs.JsonConverters; +using Wabbajack.Networking.Http; +using Wabbajack.Networking.Http.Interfaces; +using Wabbajack.Networking.WabbajackClientApi; +using Wabbajack.Paths; +using Wabbajack.Paths.IO; +using Wabbajack.RateLimiter; namespace Wabbajack.Lib { public class LauncherUpdater { + private readonly ILogger _logger; + private readonly HttpClient _client; + private readonly Client _wjclient; + private readonly DTOSerializer _dtos; + + private readonly DownloadDispatcher _downloader; + + private static Uri GITHUB_REPO_RELEASES = new("https://api.github.com/repos/wabbajack-tools/wabbajack/releases"); + + public LauncherUpdater(ILogger logger, HttpClient client, Client wjclient, DTOSerializer dtos, + DownloadDispatcher downloader) + { + _logger = logger; + _client = client; + _wjclient = wjclient; + _dtos = dtos; + _downloader = downloader; + } + + public static Lazy CommonFolder = new (() => { - var entryPoint = AbsolutePath.EntryPoint; + var entryPoint = KnownFolders.EntryPoint; // If we're not in a folder that looks like a version, abort if (!Version.TryParse(entryPoint.FileName.ToString(), out var version)) @@ -21,24 +54,26 @@ namespace Wabbajack.Lib } // If we're not in a folder that has Wabbajack.exe in the parent folder, abort - if (!entryPoint.Parent.Combine(Consts.AppName).WithExtension(new Extension(".exe")).IsFile) + if (!entryPoint.Parent.Combine(Consts.AppName).WithExtension(new Extension(".exe")).FileExists()) { return entryPoint; } return entryPoint.Parent; }); - - public static async Task Run() + + + + public async Task Run() { - if (CommonFolder.Value == AbsolutePath.EntryPoint) + if (CommonFolder.Value == KnownFolders.EntryPoint) { - Utils.Log("Outside of standard install folder, not updating"); + _logger.LogInformation("Outside of standard install folder, not updating"); return; } - var version = Version.Parse(AbsolutePath.EntryPoint.FileName.ToString()); + var version = Version.Parse(KnownFolders.EntryPoint.FileName.ToString()); var oldVersions = CommonFolder.Value .EnumerateDirectories() @@ -52,8 +87,8 @@ namespace Wabbajack.Lib foreach (var (_, path) in oldVersions) { - Utils.Log($"Deleting old Wabbajack version at: {path}"); - await path.DeleteDirectory(); + _logger.LogInformation("Deleting old Wabbajack version at: {Path}", path); + path.DeleteDirectory(); } var release = (await GetReleases()) @@ -68,41 +103,51 @@ namespace Wabbajack.Lib }) .FirstOrDefault(); - var launcherFolder = AbsolutePath.EntryPoint.Parent; + var launcherFolder = KnownFolders.EntryPoint.Parent; var exePath = launcherFolder.Combine("Wabbajack.exe"); var launcherVersion = FileVersionInfo.GetVersionInfo(exePath.ToString()); if (release != default && release.version > Version.Parse(launcherVersion.FileVersion!)) { - Utils.Log($"Updating Launcher from {launcherVersion.FileVersion} to {release.version}"); + _logger.LogInformation("Updating Launcher from {OldVersion} to {NewVersion}", launcherVersion.FileVersion, release.version); var tempPath = launcherFolder.Combine("Wabbajack.exe.temp"); - var client = new Client(); - client.UseChromeUserAgent(); - await client.DownloadAsync(release.asset.BrowserDownloadUrl!, tempPath); - if (tempPath.Size != release.asset.Size) + await _downloader.Download(new Archive { - Utils.Log( - $"Downloaded launcher did not match expected size: {tempPath.Size} expected {release.asset.Size}"); + State = new Http {Url = release.asset.BrowserDownloadUrl!}, + Name = release.asset.Name, + Size = release.asset.Size + }, tempPath, CancellationToken.None); + + if (tempPath.Size() != release.asset.Size) + { + _logger.LogInformation( + "Downloaded launcher did not match expected size: {DownloadedSize} expected {ExpectedSize}", tempPath.Size(), release.asset.Size); return; } - if (exePath.Exists) - await exePath.DeleteAsync(); - await tempPath.MoveToAsync(exePath); + if (exePath.FileExists()) + exePath.Delete(); + await tempPath.MoveToAsync(exePath, true, CancellationToken.None); - Utils.Log("Finished updating wabbajack"); - await Metrics.Send("updated_launcher", $"{launcherVersion.FileVersion} -> {release.version}"); + _logger.LogInformation("Finished updating wabbajack"); + await _wjclient.SendMetric("updated_launcher", $"{launcherVersion.FileVersion} -> {release.version}"); } } - private static async Task GetReleases() + private async Task GetReleases() { - Utils.Log("Getting new Wabbajack version list"); - var client = new Client(); - client.UseChromeUserAgent(); - return await client.GetJsonAsync(Consts.GITHUB_REPO_RELEASES.ToString()); + _logger.LogInformation("Getting new Wabbajack version list"); + var msg = MakeMessage(GITHUB_REPO_RELEASES); + return await _client.GetJsonFromSendAsync(msg, _dtos.Options); + } + + private HttpRequestMessage MakeMessage(Uri uri) + { + var msg = new HttpRequestMessage(HttpMethod.Get, uri); + msg.UseChromeUserAgent(); + return msg; } diff --git a/Wabbajack.Lib/Manifest.cs b/Wabbajack.Lib/Manifest.cs deleted file mode 100644 index 3ef99e8b..00000000 --- a/Wabbajack.Lib/Manifest.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Wabbajack.Common; -using Wabbajack.Common.Serialization.Json; - -namespace Wabbajack.Lib -{ - [JsonName("Manifest")] - public class Manifest - { - public readonly string Name; - public readonly Version Version; - public readonly string Author; - public readonly string Description; - - public readonly Game GameType; - // Enum toString for better parsing in other software - public string GameName; - - public readonly ModManager ModManager; - // Enum toString for better parsing in other software - public string ModManagerName; - - public readonly long DownloadSize; - public readonly long InstallSize; - - public bool IsNSFW; - - public readonly List Archives; - public readonly List InlinedFiles; - - public Manifest(ModList modlist) - { - Name = modlist.Name; - Version = modlist.Version; - Author = modlist.Author; - Description = modlist.Description; - - GameType = modlist.GameType; - GameName = GameType.ToString(); - - ModManager = modlist.ModManager; - ModManagerName = ModManager.ToString(); - - DownloadSize = modlist.DownloadSize; - InstallSize = modlist.InstallSize; - - IsNSFW = modlist.IsNSFW; - - // meta is being omitted due to it being useless and not very space friendly - Archives = modlist.Archives.Select(a => new Archive(a.State) - { - Hash = a.Hash, - Name = a.Name, - Size = a.Size, - }).ToList(); - - InlinedFiles = modlist.Directives.OfType().ToList(); - } - } -} diff --git a/Wabbajack.Lib/Tasks/MakeNewMO2Project.cs b/Wabbajack.Lib/Tasks/MakeNewMO2Project.cs deleted file mode 100644 index 9a2cc7f4..00000000 --- a/Wabbajack.Lib/Tasks/MakeNewMO2Project.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Threading.Tasks; -using Wabbajack.Common; - -namespace Wabbajack.Lib.Tasks -{ - public class MakeNewMO2Project - { - public static async Task Execute(AbsolutePath folder, Game game) - { - - } - } -} diff --git a/Wabbajack.Lib/Tasks/MigrateGameFolder.cs b/Wabbajack.Lib/Tasks/MigrateGameFolder.cs deleted file mode 100644 index 06feb725..00000000 --- a/Wabbajack.Lib/Tasks/MigrateGameFolder.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System.Threading.Tasks; -using Wabbajack.Common; - -namespace Wabbajack.Lib.Tasks -{ - public class MigrateGameFolder - { - public static async Task Execute(AbsolutePath mo2Folder) - { - var iniPath = mo2Folder.Combine(Consts.ModOrganizer2Ini); - if (!iniPath.Exists) - { - Utils.Log($"Game folder conversion failed, {Consts.ModOrganizer2Ini} does not exist in {mo2Folder}"); - return false; - } - - var newGamePath = mo2Folder.Combine(Consts.GameFolderFilesDir); - newGamePath.CreateDirectory(); - var gameIni = iniPath.LoadIniFile(); - - if (!GameRegistry.TryGetByFuzzyName((string)gameIni.General.gameName, out var gameMeta)) - { - Utils.Log($"Could not locate game for {gameIni.General.gameName}"); - return false; - } - - - var orginGamePath = gameMeta.GameLocation(); - foreach (var file in gameMeta.GameLocation().EnumerateFiles()) - { - var relPath = file.RelativeTo(orginGamePath); - var newFile = relPath.RelativeTo(newGamePath); - if (newFile.Exists) - { - Utils.Log($"Skipping {relPath} it already exists in the target path"); - continue; - } - - Utils.Log($"Copying/Linking {relPath}"); - await file.HardLinkIfOversize(newFile); - } - - Utils.Log("Remapping INI"); - var iniString = await iniPath.ReadAllTextAsync(); - iniString = iniString.Replace((string)orginGamePath, (string)newGamePath); - iniString = iniString.Replace(((string)orginGamePath).Replace(@"\", @"\\"), ((string)newGamePath).Replace(@"\", @"\\")); - iniString = iniString.Replace(((string)orginGamePath).Replace(@"\", @"/"), ((string)newGamePath).Replace(@"\", @"/")); - await iniPath.WriteAllTextAsync(iniString); - - return true; - } - } -} diff --git a/Wabbajack.Lib/Validation/DTOs.cs b/Wabbajack.Lib/Validation/DTOs.cs deleted file mode 100644 index 00be5104..00000000 --- a/Wabbajack.Lib/Validation/DTOs.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Collections.Generic; - -namespace Wabbajack.Lib.Validation -{ - public class Permissions - { - public bool? CanExtractBSAs { get; set; } - public bool? CanModifyESPs { get; set; } - public bool? CanModifyAssets { get; set; } - public bool? CanUseInOtherGames { get; set; } - } - - //public class Author - //{ - // public Permissions Permissions { get; set; } - // public Dictionary Games; - //} - - //public class Game - //{ - // public Permissions Permissions; - // public Dictionary Mods; - //} - - //public class Mod - //{ - // public Permissions Permissions; - // public Dictionary Files; - //} - - //public class File - //{ - // public Permissions Permissions; - //} - - public class ServerWhitelist - { - public List GoogleIDs = new List(); - public List AllowedPrefixes = new List(); - } -} diff --git a/Wabbajack.Lib/Validation/ValidateModlist.cs b/Wabbajack.Lib/Validation/ValidateModlist.cs deleted file mode 100644 index 360f2389..00000000 --- a/Wabbajack.Lib/Validation/ValidateModlist.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Net.Http; -using System.Threading.Tasks; -using Wabbajack.Common; -using Wabbajack.Lib.Downloaders; -using Path = Alphaleonis.Win32.Filesystem.Path; - -namespace Wabbajack.Lib.Validation -{ - /// - /// Core class for rights management. Given a Wabbajack ModList this class will return a list of all the - /// known rights violations of the ModList - /// - public class ValidateModlist - { - public ServerWhitelist ServerWhitelist { get; private set; } = new ServerWhitelist(); - public void LoadServerWhitelist(string s) - { - ServerWhitelist = s.FromYaml(); - } - - public async Task LoadListsFromGithub() - { - var client = new Wabbajack.Lib.Http.Client(); - - Utils.Log("Loading server whitelist"); - using (var response = await client.GetAsync(Consts.ServerWhitelistURL)) - using (var result = await response.Content.ReadAsStreamAsync()) - { - ServerWhitelist = result.FromYaml(); - Utils.Log($"Loaded permissions for {ServerWhitelist.AllowedPrefixes?.Count ?? 0} servers and {ServerWhitelist.GoogleIDs?.Count ?? 0} Google Drive files"); - } - - } - - public static async Task RunValidation(ModList modlist) - { - var validator = new ValidateModlist(); - - await validator.LoadListsFromGithub(); - - Utils.Log("Running validation checks"); - var errors = await validator.Validate(modlist); - errors.Do(e => Utils.Log(e)); - if (errors.Count() > 0) - { - throw new Exception($"{errors.Count()} validation errors found, cannot continue."); - } - else - { - Utils.Log("No validation failures"); - } - } - - public async Task> Validate(ModList modlist) - { - ConcurrentStack ValidationErrors = new(); - modlist.Archives - .Where(m => !m.State.IsWhitelisted(ServerWhitelist)) - .Do(m => - { - ValidationErrors.Push($"{m.Name} is not a whitelisted download"); - }); - - return ValidationErrors.ToList(); - } - } -} diff --git a/Wabbajack.Lib/VirusScanner.cs b/Wabbajack.Lib/VirusScanner.cs deleted file mode 100644 index 459f260b..00000000 --- a/Wabbajack.Lib/VirusScanner.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Org.BouncyCastle.Bcpg; -using Wabbajack.Common; -using Wabbajack.Common.FileSignatures; - -namespace Wabbajack.Lib -{ - /// - /// Wrapper around Windows Defender's commandline tool - /// - public class VirusScanner - { - public enum Result : int - { - NotMalware = 0, - Malware = 2 - } - - private static AbsolutePath ScannerPath() - { - return ((AbsolutePath)@"C:\ProgramData\Microsoft\Windows Defender\Platform") - .EnumerateDirectories(recursive:false) - .OrderByDescending(f => f.FileName) - .First() - .EnumerateFiles(recursive:true) - .First(f => f.FileName == (RelativePath)"MpCmdRun.exe"); - } - - public static async Task<(Hash, Result)> ScanStream(Stream stream) - { - var ms = new MemoryStream(); - await stream.CopyToAsync(ms); - ms.Position = 0; - - var hash = await ms.xxHashAsync(); - ms.Position = 0; - - await using var file = new TempFile(); - try - { - await file.Path.WriteAllAsync(ms); - } - catch (IOException ex) - { - // Was caught before we could fully scan the file due to real-time virus scans - if (ex.Message.ToLowerInvariant().Contains("malware")) - { - return (hash, Result.Malware); - } - } - - var process = new ProcessHelper - { - Path = ScannerPath(), - Arguments = new object[] {"-Scan", "-ScanType", "3", "-DisableRemediation", "-File", file.Path}, - }; - - return (hash, (Result)await process.Start()); - } - - private static SignatureChecker ExecutableChecker = new SignatureChecker(Definitions.FileType.DLL, - Definitions.FileType.EXE, - Definitions.FileType.PIF, - Definitions.FileType.QXD, - Definitions.FileType.QTX, - Definitions.FileType.DRV, - Definitions.FileType.SYS, - Definitions.FileType.COM); - - public static async Task ShouldScan(AbsolutePath path) - { - return await ExecutableChecker.MatchesAsync(path) != null; - } - } -} diff --git a/Wabbajack.Lib/Wabbajack.Lib.csproj b/Wabbajack.Lib/Wabbajack.Lib.csproj index 83fc3ab6..5433596b 100644 --- a/Wabbajack.Lib/Wabbajack.Lib.csproj +++ b/Wabbajack.Lib/Wabbajack.Lib.csproj @@ -74,6 +74,8 @@ + + diff --git a/Wabbajack.Lib/WebAutomation/CefSharpWrapper.cs b/Wabbajack.Lib/WebAutomation/CefSharpWrapper.cs index 1782e14f..55384a39 100644 --- a/Wabbajack.Lib/WebAutomation/CefSharpWrapper.cs +++ b/Wabbajack.Lib/WebAutomation/CefSharpWrapper.cs @@ -1,16 +1,12 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Text; using System.Threading; using System.Threading.Tasks; using CefSharp; -using Wabbajack.Common; -using Wabbajack.Common.Exceptions; +using Microsoft.Extensions.Logging; +using Microsoft.VisualBasic.CompilerServices; using Wabbajack.Lib.LibCefHelpers; +using Wabbajack.Networking.Http; +using Wabbajack.Paths; namespace Wabbajack.Lib.WebAutomation { @@ -18,8 +14,9 @@ namespace Wabbajack.Lib.WebAutomation { private readonly IWebBrowser _browser; public Action? DownloadHandler { get; set; } - public CefSharpWrapper(IWebBrowser browser) + public CefSharpWrapper(ILogger logger, IWebBrowser browser) { + _logger = logger; _browser = browser; _browser.DownloadHandler = new DownloadHandler(this); @@ -59,6 +56,7 @@ namespace Wabbajack.Lib.WebAutomation ("We could not locate the item you are trying to view.", 404), }; private static readonly Random RetryRandom = new Random(); + private readonly ILogger _logger; public async Task NavigateToAndDownload(Uri uri, AbsolutePath dest, bool quickMode = false, CancellationToken? token = null) { @@ -86,7 +84,7 @@ namespace Wabbajack.Lib.WebAutomation { retryCount += 1; var retry = RetryRandom.Next(retryCount * 5000, retryCount * 5000 * 2); - Utils.Log($"Got server load error from {uri} retying in {retry}ms [{err}]"); + _logger.LogWarning("Got server load error from {Uri} retying in {Retry}ms [{Error}]", uri, retry, err); await Task.Delay(TimeSpan.FromMilliseconds(retry)); goto RETRY; } @@ -98,7 +96,7 @@ namespace Wabbajack.Lib.WebAutomation throw new HttpException(httpCode,$"Web driver failed: {err}"); } - Utils.Log($"Loaded page {uri} starting download..."); + _logger.LogInformation("Loaded page {Uri} starting download", uri); return await handler.TaskResult; } finally { diff --git a/Wabbajack.Lib/WebAutomation/WebAutomation.cs b/Wabbajack.Lib/WebAutomation/WebAutomation.cs index 029093a4..ca31f705 100644 --- a/Wabbajack.Lib/WebAutomation/WebAutomation.cs +++ b/Wabbajack.Lib/WebAutomation/WebAutomation.cs @@ -6,6 +6,7 @@ using System.Windows; using CefSharp; using CefSharp.OffScreen; using HtmlAgilityPack; +using Microsoft.Extensions.Logging; using Wabbajack.Common; using Wabbajack.Lib.LibCefHelpers; using Wabbajack.Paths; @@ -18,16 +19,16 @@ namespace Wabbajack.Lib.WebAutomation private readonly IWebBrowser _browser; private readonly CefSharpWrapper _driver; - public Driver() + public Driver(ILogger logger) { _browser = new ChromiumWebBrowser(); - _driver = new CefSharpWrapper(_browser); + _driver = new CefSharpWrapper(logger, _browser); } - public static async Task Create() + public static async Task Create(ILogger logger) { Helpers.Init(); - var driver = new Driver(); + var driver = new Driver(logger); await driver._driver.WaitForInitialized(); return driver; } diff --git a/Wabbajack.Networking.Http/Extensions.cs b/Wabbajack.Networking.Http/Extensions.cs new file mode 100644 index 00000000..08e9e029 --- /dev/null +++ b/Wabbajack.Networking.Http/Extensions.cs @@ -0,0 +1,29 @@ +using System.Net.Http; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; + +namespace Wabbajack.Networking.Http; + +public static class Extensions +{ + public static HttpRequestMessage UseChromeUserAgent(this HttpRequestMessage msg) + { + msg.Headers.UserAgent.Clear(); + msg.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"); + return msg; + } + + public static async Task GetJsonFromSendAsync(this HttpClient client, HttpRequestMessage msg, + JsonSerializerOptions opts, CancellationToken? token = null) + { + token ??= CancellationToken.None; + using var result = await client.SendAsync(msg, token.Value); + if (!result.IsSuccessStatusCode) + { + throw new HttpException(result); + } + return (await JsonSerializer.DeserializeAsync(await result.Content.ReadAsStreamAsync(token.Value)))!; + } + +} \ No newline at end of file