diff --git a/Wabbajack.CacheServer/DTOs/Metric.cs b/Wabbajack.CacheServer/DTOs/Metric.cs new file mode 100644 index 00000000..e3c671d3 --- /dev/null +++ b/Wabbajack.CacheServer/DTOs/Metric.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using CouchDB.Driver.Types; + +namespace Wabbajack.CacheServer.DTOs +{ + public class Metric + { + public DateTime Timestamp; + public string Action; + public string Subject; + } +} diff --git a/Wabbajack.CacheServer/DTOs/ModListStatus.cs b/Wabbajack.CacheServer/DTOs/ModListStatus.cs new file mode 100644 index 00000000..5c64599d --- /dev/null +++ b/Wabbajack.CacheServer/DTOs/ModListStatus.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Media.Animation; +using CouchDB.Driver.Extensions; +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Driver; +using Wabbajack.Lib; +using Wabbajack.Lib.ModListRegistry; + +namespace Wabbajack.CacheServer.DTOs +{ + public class ModListStatus + { + static ModListStatus() + { + SerializerSettings.Init(); + } + + [BsonId] + public string Id { get; set; } + public ModlistSummary Summary { get; set; } + + public ModlistMetadata Metadata { get; set; } + public DetailedStatus DetailedStatus { get; set; } + + public static async Task Update(ModListStatus status) + { + var id = status.Metadata.Links.MachineURL; + await Server.Config.ListValidation.Connect().FindOneAndReplaceAsync(s => s.Id == id, status, new FindOneAndReplaceOptions {IsUpsert = true}); + } + + public static IQueryable AllSummaries + { + get + { + return null; + } + } + + public static async Task ByName(string name) + { + var result = await Server.Config.ListValidation.Connect() + .AsQueryable() + .Where(doc => doc.Metadata.Links.MachineURL == name || doc.Metadata.Title == name) + .ToListAsync(); + return result.First(); + } + + public static IQueryable All + { + get + { + return Server.Config.ListValidation.Connect().AsQueryable(); + } + } + } + + public class DetailedStatus + { + public string Name; + public DateTime Checked = DateTime.Now; + public List Archives { get; set; } + public DownloadMetadata DownloadMetaData { get; set; } + public bool HasFailures { get; set; } + public string MachineName { get; set; } + } + + public class DetailedStatusItem + { + public bool IsFailing { get; set; } + public Archive Archive { get; set; } + } +} diff --git a/Wabbajack.CacheServer/DTOs/MongoDoc.cs b/Wabbajack.CacheServer/DTOs/MongoDoc.cs new file mode 100644 index 00000000..0d91b231 --- /dev/null +++ b/Wabbajack.CacheServer/DTOs/MongoDoc.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MongoDB.Bson; + +namespace Wabbajack.CacheServer.DTOs +{ + public class MongoDoc + { + public ObjectId _id { get; set; } = ObjectId.Empty; + } +} diff --git a/Wabbajack.CacheServer/DTOs/SerializerSettings.cs b/Wabbajack.CacheServer/DTOs/SerializerSettings.cs new file mode 100644 index 00000000..2a922397 --- /dev/null +++ b/Wabbajack.CacheServer/DTOs/SerializerSettings.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MongoDB.Bson; +using MongoDB.Bson.IO; +using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.Conventions; +using Wabbajack.Lib.Downloaders; + +namespace Wabbajack.CacheServer.DTOs +{ + public static class SerializerSettings + { + public static void Init() + { + var dis = new TypeDiscriminator(typeof(AbstractDownloadState), AbstractDownloadState.NameToType, + AbstractDownloadState.TypeToName); + BsonSerializer.RegisterDiscriminatorConvention(typeof(AbstractDownloadState), dis); + } + } + + + public class TypeDiscriminator : IDiscriminatorConvention + { + private readonly Type defaultType; + private readonly Dictionary typeMap; + private Dictionary revMap; + + public TypeDiscriminator(Type defaultType, + Dictionary typeMap, Dictionary revMap) + { + this.defaultType = defaultType; + this.typeMap = typeMap; + this.revMap = revMap; + } + + + /// + /// Element Name + /// + public string ElementName => "_wjType"; + + public Type GetActualType(IBsonReader bsonReader, Type nominalType) + { + Type type = defaultType; + var bookmark = bsonReader.GetBookmark(); + bsonReader.ReadStartDocument(); + if (bsonReader.FindElement(ElementName)) + { + var value = bsonReader.ReadString(); + if (typeMap.ContainsKey(value)) + type = typeMap[value]; + } + + bsonReader.ReturnToBookmark(bookmark); + return type; + } + + public BsonValue GetDiscriminator(Type nominalType, Type actualType) + { + return revMap[actualType]; + } + } +} diff --git a/Wabbajack.CacheServer/ListValidationService.cs b/Wabbajack.CacheServer/ListValidationService.cs index bc27b784..fd21fea0 100644 --- a/Wabbajack.CacheServer/ListValidationService.cs +++ b/Wabbajack.CacheServer/ListValidationService.cs @@ -8,8 +8,10 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; +using CouchDB.Driver.Extensions; using Nancy; using Nancy.Responses; +using Wabbajack.CacheServer.DTOs; using Wabbajack.Common; using Wabbajack.Lib; using Wabbajack.Lib.Downloaders; @@ -19,18 +21,6 @@ namespace Wabbajack.CacheServer { public class ListValidationService : NancyModule { - public class ModListStatus - { - public string Name; - public DateTime Checked = DateTime.Now; - public List<(Archive archive, bool)> Archives { get; set; } - public DownloadMetadata DownloadMetaData { get; set; } - public bool HasFailures { get; set; } - public string MachineName { get; set; } - } - - public static Dictionary ModLists { get; set; } - public ListValidationService() : base("/lists") { Get("/status", HandleGetLists); @@ -38,15 +28,9 @@ namespace Wabbajack.CacheServer Get("/status/{Name}.html", HandleGetListHtml); } - private object HandleGetLists(object arg) + private async Task HandleGetLists(object arg) { - var summaries = ModLists.Values.Select(m => new ModlistSummary - { - Name = m.Name, - Checked = m.Checked, - Failed = m.Archives.Count(a => a.Item2), - Passed = m.Archives.Count(a => !a.Item2), - }).ToList(); + var summaries = await ModListStatus.All.Select(m => m.Summary).ToListAsync(); return summaries.ToJSON(); } @@ -63,44 +47,36 @@ namespace Wabbajack.CacheServer public List Passed; } - private object HandleGetListJson(dynamic arg) + private async Task HandleGetListJson(dynamic arg) { - var lst = ModLists[(string)arg.Name]; - var summary = new DetailedSummary - { - Name = lst.Name, - Checked = lst.Checked, - Failed = lst.Archives.Where(a => a.Item2) - .Select(a => new ArchiveSummary {Name = a.archive.Name, State = a.archive.State}).ToList(), - Passed = lst.Archives.Where(a => !a.Item2) - .Select(a => new ArchiveSummary { Name = a.archive.Name, State = a.archive.State }).ToList(), - }; - return summary.ToJSON(); + var metric = Metrics.Log("list_validation.get_list_json", (string)arg.Name); + var lst = (await ModListStatus.ByName((string)arg.Name)).DetailedStatus; + return lst.ToJSON(); } - private object HandleGetListHtml(dynamic arg) + private async Task HandleGetListHtml(dynamic arg) { - var lst = ModLists[(string)arg.Name]; + var lst = (await ModListStatus.ByName((string)arg.Name)).DetailedStatus; var sb = new StringBuilder(); sb.Append(""); sb.Append($"

{lst.Name} - {lst.Checked}

"); - var failed_list = lst.Archives.Where(a => a.Item2).ToList(); + var failed_list = lst.Archives.Where(a => a.IsFailing).ToList(); sb.Append($"

Failed ({failed_list.Count}):

"); sb.Append("
    "); foreach (var archive in failed_list) { - sb.Append($"
  • {archive.archive.Name}
  • "); + sb.Append($"
  • {archive.Archive.Name}
  • "); } sb.Append("
"); - var pased_list = lst.Archives.Where(a => !a.Item2).ToList(); + var pased_list = lst.Archives.Where(a => !a.IsFailing).ToList(); sb.Append($"

Passed ({pased_list.Count}):

"); sb.Append("
    "); - foreach (var archive in pased_list.OrderBy(f => f.archive.Name)) + foreach (var archive in pased_list.OrderBy(f => f.Archive.Name)) { - sb.Append($"
  • {archive.archive.Name}
  • "); + sb.Append($"
  • {archive.Archive.Name}
  • "); } sb.Append("
"); @@ -134,75 +110,96 @@ namespace Wabbajack.CacheServer { Utils.Log("Cleaning Nexus Cache"); var client = new HttpClient(); - await client.GetAsync("http://build.wabbajack.org/nexus_api_cache/update"); + //await client.GetAsync("http://build.wabbajack.org/nexus_api_cache/update"); Utils.Log("Starting Modlist Validation"); var modlists = await ModlistMetadata.LoadFromGithub(); - var statuses = new Dictionary(); - using (var queue = new WorkQueue()) { foreach (var list in modlists) { - var modlist_path = Path.Combine(Consts.ModListDownloadFolder, list.Links.MachineURL + ExtensionManager.Extension); - - if (list.NeedsDownload(modlist_path)) + try { - if (File.Exists(modlist_path)) - File.Delete(modlist_path); - - var state = DownloadDispatcher.ResolveArchive(list.Links.Download); - Utils.Log($"Downloading {list.Links.MachineURL} - {list.Title}"); - await state.Download(modlist_path); + await ValidateList(list, queue); } - else + catch (Exception ex) { - Utils.Log($"No changes detected from downloaded modlist"); } - - - Utils.Log($"Loading {modlist_path}"); - - var installer = AInstaller.LoadFromFile(modlist_path); - - Utils.Log($"{installer.Archives.Count} archives to validate"); - - DownloadDispatcher.PrepareAll(installer.Archives.Select(a => a.State)); - - var validated = (await installer.Archives - .PMap(queue, async archive => - { - Utils.Log($"Validating: {archive.Name}"); - bool is_failed; - try - { - is_failed = !(await archive.State.Verify()); - } - catch (Exception) - { - is_failed = false; - } - - return (archive, is_failed); - })) - .ToList(); - - - var status = new ModListStatus - { - Name = list.Title, - Archives = validated.OrderBy(v => v.archive.Name).ToList(), - DownloadMetaData = list.DownloadMetadata, - HasFailures = validated.Any(v => v.is_failed) - }; - - statuses.Add(status.Name, status); - } + } } - Utils.Log($"Done validating {statuses.Count} lists"); - ModLists = statuses; + Utils.Log($"Done validating {modlists.Count} lists"); + } + + private static async Task ValidateList(ModlistMetadata list, WorkQueue queue) + { + var modlist_path = Path.Combine(Consts.ModListDownloadFolder, list.Links.MachineURL + ExtensionManager.Extension); + + if (list.NeedsDownload(modlist_path)) + { + if (File.Exists(modlist_path)) + File.Delete(modlist_path); + + var state = DownloadDispatcher.ResolveArchive(list.Links.Download); + Utils.Log($"Downloading {list.Links.MachineURL} - {list.Title}"); + await state.Download(modlist_path); + } + else + { + Utils.Log($"No changes detected from downloaded modlist"); + } + + + Utils.Log($"Loading {modlist_path}"); + + var installer = AInstaller.LoadFromFile(modlist_path); + + Utils.Log($"{installer.Archives.Count} archives to validate"); + + DownloadDispatcher.PrepareAll(installer.Archives.Select(a => a.State)); + + var validated = (await installer.Archives + .PMap(queue, async archive => + { + Utils.Log($"Validating: {archive.Name}"); + bool is_failed; + try + { + is_failed = !(await archive.State.Verify()); + } + catch (Exception) + { + is_failed = false; + } + + return new DetailedStatusItem {IsFailing = is_failed, Archive = archive}; + })) + .ToList(); + + + var status = new DetailedStatus + { + Name = list.Title, + Archives = validated.OrderBy(v => v.Archive.Name).ToList(), + DownloadMetaData = list.DownloadMetadata, + HasFailures = validated.Any(v => v.IsFailing) + }; + + var dto = new ModListStatus + { + Id = list.Links.MachineURL, + Summary = new ModlistSummary + { + Name = status.Name, + Checked = status.Checked, + Failed = status.Archives.Count(a => a.IsFailing), + Passed = status.Archives.Count(a => !a.IsFailing), + }, + DetailedStatus = status, + Metadata = list + }; + await ModListStatus.Update(dto); } } } diff --git a/Wabbajack.CacheServer/Metrics.cs b/Wabbajack.CacheServer/Metrics.cs index 140681d0..72490852 100644 --- a/Wabbajack.CacheServer/Metrics.cs +++ b/Wabbajack.CacheServer/Metrics.cs @@ -6,8 +6,10 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; +using CouchDB.Driver.Extensions; +using MongoDB.Driver; using Nancy; -using ReactiveUI; +using Wabbajack.CacheServer.DTOs; using Wabbajack.Common; namespace Wabbajack.CacheServer @@ -19,19 +21,17 @@ namespace Wabbajack.CacheServer { private static SemaphoreSlim _lockObject = new SemaphoreSlim(1); - public static async Task Log(params object[] args) + public static async Task Log(DateTime timestamp, string action, string subject) { - var msg = new[] {string.Join("\t", args.Select(a => a.ToString()))}; + var msg = new[] {string.Join("\t", new[]{timestamp.ToString(), action, subject})}; Utils.Log(msg.First()); - await _lockObject.WaitAsync(); - try - { - File.AppendAllLines("stats.tsv", msg); - } - finally - { - _lockObject.Release(); - } + var db = Server.Config.Metrics.Connect(); + await db.InsertOneAsync(new Metric {Timestamp = timestamp, Action = action, Subject = subject}); + } + + public static Task Log(string action, string subject) + { + return Log(DateTime.Now, action, subject); } public Metrics() : base("/") @@ -40,6 +40,26 @@ namespace Wabbajack.CacheServer Get("/metrics/chart/", HandleChart); Get("/metrics/chart/{Action}/", HandleChart); Get("/metrics/chart/{Action}/{Value}/", HandleChart); + Get("/metrics/ingest/{filename}", HandleBulkIngest); + } + + private async Task HandleBulkIngest(dynamic arg) + { + Log("Bulk Loading " + arg.filename.ToString()); + + var lines = File.ReadAllLines(Path.Combine(@"c:\tmp", (string)arg.filename)); + + var db = Server.Config.Metrics.Connect(); + + var data = lines.Select(line => line.Split('\t')) + .Where(line => line.Length == 3) + .Select(line => new Metric{ Timestamp = DateTime.Parse(line[0]), Action = line[1], Subject = line[2] }) + .ToList(); + + foreach (var metric in data) + await db.InsertOneAsync(metric); + + return $"Processed {lines.Length} records"; } private async Task HandleMetrics(dynamic arg) @@ -49,36 +69,33 @@ namespace Wabbajack.CacheServer return date.ToString(); } - private static async Task GetData() - { - await _lockObject.WaitAsync(); - try - { - return File.ReadAllLines("stats.tsv"); - } - finally - { - _lockObject.Release(); - } - } - private async Task HandleChart(dynamic arg) { - var data = (await GetData()).Select(line => line.Split('\t')) + /*var data = (await GetData()).Select(line => line.Split('\t')) .Where(line => line.Length == 3) - .Select(line => new {date = DateTime.Parse(line[0]), Action = line[1], Value = line[2]}); + .Select(line => new {date = DateTime.Parse(line[0]), Action = line[1], Value = line[2]});*/ + + var q = (IQueryable)Server.Config.Metrics.Connect().AsQueryable(); // Remove guids / Default, which come from testing - data = data.Where(d => !Guid.TryParse(d.Value ?? "", out _) && (d.Value ?? "") != "Default"); if (arg?.Action != null) - data = data.Where(d => d.Action == arg.Action); + { + var action = (string)arg.Action; + q = q.Where(d => d.Action == action); + } if (arg?.Value != null) - data = data.Where(d => d.Value.StartsWith(arg.Value)); + { + var value = (string)arg.Value; + q = q.Where(d => d.Subject.StartsWith(value)); + } - var grouped_and_counted = data.GroupBy(d => d.date.ToString("yyyy-MM-dd")) + var data = (await q.Take(Int32.MaxValue).ToListAsync()).AsEnumerable(); + data = data.Where(d => !Guid.TryParse(d.Subject ?? "", out Guid v) && (d.Subject ?? "") != "Default"); + + var grouped_and_counted = data.GroupBy(d => d.Timestamp.ToString("yyyy-MM-dd")) .OrderBy(d => d.Key) .Select(d => new {Day = d.Key, Count = d.Count()}) .ToList(); @@ -116,5 +133,10 @@ namespace Wabbajack.CacheServer response.ContentType = "text/html"; return response; } + + public void Log(string l) + { + Utils.Log("Metrics: " + l); + } } } diff --git a/Wabbajack.CacheServer/Server.cs b/Wabbajack.CacheServer/Server.cs index 76d7867c..22456cfb 100644 --- a/Wabbajack.CacheServer/Server.cs +++ b/Wabbajack.CacheServer/Server.cs @@ -6,12 +6,15 @@ using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; +using Alphaleonis.Win32.Filesystem; using Nancy; using Nancy.Bootstrapper; using Nancy.Configuration; using Nancy.Diagnostics; using Nancy.Hosting.Self; using Nancy.TinyIoc; +using Wabbajack.CacheServer.ServerConfig; +using Wabbajack.Common; namespace Wabbajack.CacheServer { @@ -19,6 +22,7 @@ namespace Wabbajack.CacheServer { private NancyHost _server; private HostConfiguration _config; + public static BuildServerConfig Config; public Server(string address) { @@ -26,8 +30,8 @@ namespace Wabbajack.CacheServer _config = new HostConfiguration {MaximumConnectionCount = 24, RewriteLocalhost = true}; //_config.UrlReservations.CreateAutomatically = true; _server = new NancyHost(_config, new Uri(address)); - - + + Config = File.ReadAllText("config.yaml").FromYaml(); } public string Address { get; } diff --git a/Wabbajack.CacheServer/ServerConfig/BuildServerConfig.cs b/Wabbajack.CacheServer/ServerConfig/BuildServerConfig.cs new file mode 100644 index 00000000..f26d7b0d --- /dev/null +++ b/Wabbajack.CacheServer/ServerConfig/BuildServerConfig.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wabbajack.CacheServer.DTOs; + +namespace Wabbajack.CacheServer.ServerConfig +{ + public class BuildServerConfig + { + public MongoConfig Metrics { get; set; } + public MongoConfig ListValidation { get; set; } + } +} diff --git a/Wabbajack.CacheServer/ServerConfig/MongoConfig.cs b/Wabbajack.CacheServer/ServerConfig/MongoConfig.cs new file mode 100644 index 00000000..519b2684 --- /dev/null +++ b/Wabbajack.CacheServer/ServerConfig/MongoConfig.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MongoDB.Driver; +using Wabbajack.CacheServer.DTOs; + +namespace Wabbajack.CacheServer.ServerConfig +{ + public class MongoConfig + { + public string Host { get; set; } + public string Database { get; set; } + public string Collection { get; set; } + public string Username { get; set; } + public string Password { get; set; } + + private IMongoDatabase Client + { + get + { + if (Username != null && Password != null) + return new MongoClient($"mongodb://{Username}:{Password}@{Host}").GetDatabase(Database); + return new MongoClient($"mongodb://{Host}").GetDatabase(Database); + } + } + + public IMongoCollection Connect() + { + return Client.GetCollection(Collection); + } + } +} diff --git a/Wabbajack.CacheServer/Wabbajack.CacheServer.csproj b/Wabbajack.CacheServer/Wabbajack.CacheServer.csproj index 6121cea9..c9a879b1 100644 --- a/Wabbajack.CacheServer/Wabbajack.CacheServer.csproj +++ b/Wabbajack.CacheServer/Wabbajack.CacheServer.csproj @@ -73,6 +73,10 @@ + + + + @@ -80,10 +84,15 @@ + + + + PreserveNewest + @@ -96,6 +105,12 @@ + + 1.1.5 + + + 2.10.0 + 2.0.0 @@ -109,5 +124,6 @@ 4.3.2 + \ No newline at end of file diff --git a/Wabbajack.CacheServer/config.yaml b/Wabbajack.CacheServer/config.yaml new file mode 100644 index 00000000..a04acc07 --- /dev/null +++ b/Wabbajack.CacheServer/config.yaml @@ -0,0 +1,12 @@ +--- +Metrics: + Host: internal.test.mongodb + Database: wabbajack + Collection: metrics +ListValidation: + Host: internal.test.mongodb + Database: wabbajack + Collection: mod_lists + + + diff --git a/Wabbajack.Lib/ACompiler.cs b/Wabbajack.Lib/ACompiler.cs index 6e44278e..994b6f31 100644 --- a/Wabbajack.Lib/ACompiler.cs +++ b/Wabbajack.Lib/ACompiler.cs @@ -95,7 +95,7 @@ namespace Wabbajack.Lib ModList.Readme = $"readme{readme.Extension}"; } - ModList.ReadmeIsWebsite = ReadmeIsWebsite; + //ModList.ReadmeIsWebsite = ReadmeIsWebsite; ModList.ToCERAS(Path.Combine(ModListOutputFolder, "modlist"), CerasConfig.Config); diff --git a/Wabbajack.Lib/CerasConfig.cs b/Wabbajack.Lib/CerasConfig.cs index 3997c8bf..05d16e4c 100644 --- a/Wabbajack.Lib/CerasConfig.cs +++ b/Wabbajack.Lib/CerasConfig.cs @@ -32,7 +32,7 @@ namespace Wabbajack.Lib }, }; - Config.VersionTolerance.Mode = VersionToleranceMode.Standard; + //Config.VersionTolerance.Mode = VersionToleranceMode.Standard; } } } diff --git a/Wabbajack.Lib/Data.cs b/Wabbajack.Lib/Data.cs index fd87897e..e4a4d43d 100644 --- a/Wabbajack.Lib/Data.cs +++ b/Wabbajack.Lib/Data.cs @@ -119,7 +119,7 @@ namespace Wabbajack.Lib /// /// Whether readme is a website /// - public bool ReadmeIsWebsite; + //public bool ReadmeIsWebsite; } public class Directive diff --git a/Wabbajack.Lib/Downloaders/AbstractDownloadState.cs b/Wabbajack.Lib/Downloaders/AbstractDownloadState.cs index 2feca218..16db7cde 100644 --- a/Wabbajack.Lib/Downloaders/AbstractDownloadState.cs +++ b/Wabbajack.Lib/Downloaders/AbstractDownloadState.cs @@ -1,5 +1,9 @@ -using System.Threading.Tasks; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; +using MongoDB.Bson.Serialization.Attributes; using Wabbajack.Lib.Validation; namespace Wabbajack.Lib.Downloaders @@ -7,8 +11,37 @@ namespace Wabbajack.Lib.Downloaders /// /// Base for all abstract downloaders /// + [BsonDiscriminator(RootClass = true)] + [BsonKnownTypes(typeof(HTTPDownloader.State), typeof(GameFileSourceDownloader.State), typeof(GoogleDriveDownloader.State), + typeof(LoversLabDownloader.State), typeof(ManualDownloader.State), typeof(MediaFireDownloader.State), typeof(MegaDownloader.State), + typeof(ModDBDownloader.State), typeof(NexusDownloader.State), typeof(SteamWorkshopDownloader.State))] public abstract class AbstractDownloadState { + + public static List KnownSubTypes = new List() + { + typeof(HTTPDownloader.State), + typeof(GameFileSourceDownloader.State), + typeof(GoogleDriveDownloader.State), + typeof(LoversLabDownloader.State), + typeof(ManualDownloader.State), + typeof(MediaFireDownloader.State), + typeof(MegaDownloader.State), + typeof(ModDBDownloader.State), + typeof(NexusDownloader.State), + typeof(SteamWorkshopDownloader.State) + }; + public static Dictionary NameToType { get; set; } + public static Dictionary TypeToName { get; set; } + + static AbstractDownloadState() + { + NameToType = KnownSubTypes.ToDictionary(t => t.FullName.Substring(t.Namespace.Length + 1), t => t); + TypeToName = NameToType.ToDictionary(k => k.Value, k => k.Key); + } + + + /// /// Returns true if this file is allowed to be downloaded via whitelist /// diff --git a/Wabbajack.Lib/MO2Compiler.cs b/Wabbajack.Lib/MO2Compiler.cs index 0688d105..5234f302 100644 --- a/Wabbajack.Lib/MO2Compiler.cs +++ b/Wabbajack.Lib/MO2Compiler.cs @@ -320,7 +320,7 @@ namespace Wabbajack.Lib Utils.Log( $"Removing {remove.Count} archives from the compilation state, this is probably not an issue but reference this if you have compilation failures"); - remove.Do(r => Utils.Log($"Resolution failed for: {r.File}")); + remove.Do(r => Utils.Log($"Resolution failed for: {r.File.FullPath}")); IndexedArchives.RemoveAll(a => remove.Contains(a)); } diff --git a/Wabbajack.Lib/Wabbajack.Lib.csproj b/Wabbajack.Lib/Wabbajack.Lib.csproj index 0d50ba48..93233f4c 100644 --- a/Wabbajack.Lib/Wabbajack.Lib.csproj +++ b/Wabbajack.Lib/Wabbajack.Lib.csproj @@ -57,6 +57,9 @@ MinimumRecommendedRules.ruleset + + ..\..\..\Users\tbald\.nuget\packages\mongodb.bson\2.10.0\lib\net452\MongoDB.Bson.dll + @@ -206,6 +209,9 @@ 6.0.0 + + 2.10.0 + 12.0.3 diff --git a/Wabbajack/View Models/ModListVM.cs b/Wabbajack/View Models/ModListVM.cs index 184d3d6b..264771d6 100644 --- a/Wabbajack/View Models/ModListVM.cs +++ b/Wabbajack/View Models/ModListVM.cs @@ -87,7 +87,7 @@ namespace Wabbajack public void OpenReadmeWindow() { if (string.IsNullOrEmpty(Readme)) return; - if (SourceModList.ReadmeIsWebsite) + if (false) //SourceModList.ReadmeIsWebsite) { Process.Start(Readme); }