Metrics and status are now in MongoDB

This commit is contained in:
Timothy Baldridge 2019-12-29 15:57:01 -07:00
parent f9cdbbc6a1
commit 5a0e19f4b1
18 changed files with 444 additions and 133 deletions

View File

@ -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;
}
}

View File

@ -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<ModListStatus>(s => s.Id == id, status, new FindOneAndReplaceOptions<ModListStatus> {IsUpsert = true});
}
public static IQueryable<ModListStatus> AllSummaries
{
get
{
return null;
}
}
public static async Task<ModListStatus> 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<ModListStatus> All
{
get
{
return Server.Config.ListValidation.Connect().AsQueryable();
}
}
}
public class DetailedStatus
{
public string Name;
public DateTime Checked = DateTime.Now;
public List<DetailedStatusItem> 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; }
}
}

View File

@ -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;
}
}

View File

@ -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<string, Type> typeMap;
private Dictionary<Type, string> revMap;
public TypeDiscriminator(Type defaultType,
Dictionary<string, Type> typeMap, Dictionary<Type, string> revMap)
{
this.defaultType = defaultType;
this.typeMap = typeMap;
this.revMap = revMap;
}
/// <summary>
/// Element Name
/// </summary>
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];
}
}
}

View File

@ -8,8 +8,10 @@ using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Alphaleonis.Win32.Filesystem; using Alphaleonis.Win32.Filesystem;
using CouchDB.Driver.Extensions;
using Nancy; using Nancy;
using Nancy.Responses; using Nancy.Responses;
using Wabbajack.CacheServer.DTOs;
using Wabbajack.Common; using Wabbajack.Common;
using Wabbajack.Lib; using Wabbajack.Lib;
using Wabbajack.Lib.Downloaders; using Wabbajack.Lib.Downloaders;
@ -19,18 +21,6 @@ namespace Wabbajack.CacheServer
{ {
public class ListValidationService : NancyModule 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<string, ModListStatus> ModLists { get; set; }
public ListValidationService() : base("/lists") public ListValidationService() : base("/lists")
{ {
Get("/status", HandleGetLists); Get("/status", HandleGetLists);
@ -38,15 +28,9 @@ namespace Wabbajack.CacheServer
Get("/status/{Name}.html", HandleGetListHtml); Get("/status/{Name}.html", HandleGetListHtml);
} }
private object HandleGetLists(object arg) private async Task<string> HandleGetLists(object arg)
{ {
var summaries = ModLists.Values.Select(m => new ModlistSummary var summaries = await ModListStatus.All.Select(m => m.Summary).ToListAsync();
{
Name = m.Name,
Checked = m.Checked,
Failed = m.Archives.Count(a => a.Item2),
Passed = m.Archives.Count(a => !a.Item2),
}).ToList();
return summaries.ToJSON(); return summaries.ToJSON();
} }
@ -63,44 +47,36 @@ namespace Wabbajack.CacheServer
public List<ArchiveSummary> Passed; public List<ArchiveSummary> Passed;
} }
private object HandleGetListJson(dynamic arg) private async Task<string> HandleGetListJson(dynamic arg)
{ {
var lst = ModLists[(string)arg.Name]; var metric = Metrics.Log("list_validation.get_list_json", (string)arg.Name);
var summary = new DetailedSummary var lst = (await ModListStatus.ByName((string)arg.Name)).DetailedStatus;
{ return lst.ToJSON();
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();
} }
private object HandleGetListHtml(dynamic arg) private async Task<Response> HandleGetListHtml(dynamic arg)
{ {
var lst = ModLists[(string)arg.Name]; var lst = (await ModListStatus.ByName((string)arg.Name)).DetailedStatus;
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.Append("<html><body>"); sb.Append("<html><body>");
sb.Append($"<h2>{lst.Name} - {lst.Checked}</h2>"); sb.Append($"<h2>{lst.Name} - {lst.Checked}</h2>");
var failed_list = lst.Archives.Where(a => a.Item2).ToList(); var failed_list = lst.Archives.Where(a => a.IsFailing).ToList();
sb.Append($"<h3>Failed ({failed_list.Count}):</h3>"); sb.Append($"<h3>Failed ({failed_list.Count}):</h3>");
sb.Append("<ul>"); sb.Append("<ul>");
foreach (var archive in failed_list) foreach (var archive in failed_list)
{ {
sb.Append($"<li>{archive.archive.Name}</li>"); sb.Append($"<li>{archive.Archive.Name}</li>");
} }
sb.Append("</ul>"); sb.Append("</ul>");
var pased_list = lst.Archives.Where(a => !a.Item2).ToList(); var pased_list = lst.Archives.Where(a => !a.IsFailing).ToList();
sb.Append($"<h3>Passed ({pased_list.Count}):</h3>"); sb.Append($"<h3>Passed ({pased_list.Count}):</h3>");
sb.Append("<ul>"); sb.Append("<ul>");
foreach (var archive in pased_list.OrderBy(f => f.archive.Name)) foreach (var archive in pased_list.OrderBy(f => f.Archive.Name))
{ {
sb.Append($"<li>{archive.archive.Name}</li>"); sb.Append($"<li>{archive.Archive.Name}</li>");
} }
sb.Append("</ul>"); sb.Append("</ul>");
@ -134,16 +110,29 @@ namespace Wabbajack.CacheServer
{ {
Utils.Log("Cleaning Nexus Cache"); Utils.Log("Cleaning Nexus Cache");
var client = new HttpClient(); 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"); Utils.Log("Starting Modlist Validation");
var modlists = await ModlistMetadata.LoadFromGithub(); var modlists = await ModlistMetadata.LoadFromGithub();
var statuses = new Dictionary<string, ModListStatus>();
using (var queue = new WorkQueue()) using (var queue = new WorkQueue())
{ {
foreach (var list in modlists) foreach (var list in modlists)
{
try
{
await ValidateList(list, queue);
}
catch (Exception ex)
{
}
}
}
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); var modlist_path = Path.Combine(Consts.ModListDownloadFolder, list.Links.MachineURL + ExtensionManager.Extension);
@ -184,25 +173,33 @@ namespace Wabbajack.CacheServer
is_failed = false; is_failed = false;
} }
return (archive, is_failed); return new DetailedStatusItem {IsFailing = is_failed, Archive = archive};
})) }))
.ToList(); .ToList();
var status = new ModListStatus var status = new DetailedStatus
{ {
Name = list.Title, Name = list.Title,
Archives = validated.OrderBy(v => v.archive.Name).ToList(), Archives = validated.OrderBy(v => v.Archive.Name).ToList(),
DownloadMetaData = list.DownloadMetadata, DownloadMetaData = list.DownloadMetadata,
HasFailures = validated.Any(v => v.is_failed) HasFailures = validated.Any(v => v.IsFailing)
}; };
statuses.Add(status.Name, status); var dto = new ModListStatus
} {
} Id = list.Links.MachineURL,
Summary = new ModlistSummary
Utils.Log($"Done validating {statuses.Count} lists"); {
ModLists = statuses; 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);
} }
} }
} }

View File

@ -6,8 +6,10 @@ using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Alphaleonis.Win32.Filesystem; using Alphaleonis.Win32.Filesystem;
using CouchDB.Driver.Extensions;
using MongoDB.Driver;
using Nancy; using Nancy;
using ReactiveUI; using Wabbajack.CacheServer.DTOs;
using Wabbajack.Common; using Wabbajack.Common;
namespace Wabbajack.CacheServer namespace Wabbajack.CacheServer
@ -19,19 +21,17 @@ namespace Wabbajack.CacheServer
{ {
private static SemaphoreSlim _lockObject = new SemaphoreSlim(1); 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()); Utils.Log(msg.First());
await _lockObject.WaitAsync(); var db = Server.Config.Metrics.Connect();
try await db.InsertOneAsync(new Metric {Timestamp = timestamp, Action = action, Subject = subject});
{
File.AppendAllLines("stats.tsv", msg);
} }
finally
public static Task Log(string action, string subject)
{ {
_lockObject.Release(); return Log(DateTime.Now, action, subject);
}
} }
public Metrics() : base("/") public Metrics() : base("/")
@ -40,6 +40,26 @@ namespace Wabbajack.CacheServer
Get("/metrics/chart/", HandleChart); Get("/metrics/chart/", HandleChart);
Get("/metrics/chart/{Action}/", HandleChart); Get("/metrics/chart/{Action}/", HandleChart);
Get("/metrics/chart/{Action}/{Value}/", HandleChart); Get("/metrics/chart/{Action}/{Value}/", HandleChart);
Get("/metrics/ingest/{filename}", HandleBulkIngest);
}
private async Task<string> 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<string> HandleMetrics(dynamic arg) private async Task<string> HandleMetrics(dynamic arg)
@ -49,36 +69,33 @@ namespace Wabbajack.CacheServer
return date.ToString(); return date.ToString();
} }
private static async Task<string[]> GetData()
{
await _lockObject.WaitAsync();
try
{
return File.ReadAllLines("stats.tsv");
}
finally
{
_lockObject.Release();
}
}
private async Task<Response> HandleChart(dynamic arg) private async Task<Response> 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) .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<Metric>)Server.Config.Metrics.Connect().AsQueryable();
// Remove guids / Default, which come from testing // Remove guids / Default, which come from testing
data = data.Where(d => !Guid.TryParse(d.Value ?? "", out _) && (d.Value ?? "") != "Default");
if (arg?.Action != null) 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) 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) .OrderBy(d => d.Key)
.Select(d => new {Day = d.Key, Count = d.Count()}) .Select(d => new {Day = d.Key, Count = d.Count()})
.ToList(); .ToList();
@ -116,5 +133,10 @@ namespace Wabbajack.CacheServer
response.ContentType = "text/html"; response.ContentType = "text/html";
return response; return response;
} }
public void Log(string l)
{
Utils.Log("Metrics: " + l);
}
} }
} }

View File

@ -6,12 +6,15 @@ using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Alphaleonis.Win32.Filesystem;
using Nancy; using Nancy;
using Nancy.Bootstrapper; using Nancy.Bootstrapper;
using Nancy.Configuration; using Nancy.Configuration;
using Nancy.Diagnostics; using Nancy.Diagnostics;
using Nancy.Hosting.Self; using Nancy.Hosting.Self;
using Nancy.TinyIoc; using Nancy.TinyIoc;
using Wabbajack.CacheServer.ServerConfig;
using Wabbajack.Common;
namespace Wabbajack.CacheServer namespace Wabbajack.CacheServer
{ {
@ -19,6 +22,7 @@ namespace Wabbajack.CacheServer
{ {
private NancyHost _server; private NancyHost _server;
private HostConfiguration _config; private HostConfiguration _config;
public static BuildServerConfig Config;
public Server(string address) public Server(string address)
{ {
@ -27,7 +31,7 @@ namespace Wabbajack.CacheServer
//_config.UrlReservations.CreateAutomatically = true; //_config.UrlReservations.CreateAutomatically = true;
_server = new NancyHost(_config, new Uri(address)); _server = new NancyHost(_config, new Uri(address));
Config = File.ReadAllText("config.yaml").FromYaml<BuildServerConfig>();
} }
public string Address { get; } public string Address { get; }

View File

@ -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<Metric> Metrics { get; set; }
public MongoConfig<ModListStatus> ListValidation { get; set; }
}
}

View File

@ -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<T>
{
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<T> Connect()
{
return Client.GetCollection<T>(Collection);
}
}
}

View File

@ -73,6 +73,10 @@
<Reference Include="WindowsBase" /> <Reference Include="WindowsBase" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="DTOs\Metric.cs" />
<Compile Include="DTOs\ModListStatus.cs" />
<Compile Include="DTOs\MongoDoc.cs" />
<Compile Include="DTOs\SerializerSettings.cs" />
<Compile Include="ListValidationService.cs" /> <Compile Include="ListValidationService.cs" />
<Compile Include="Metrics.cs" /> <Compile Include="Metrics.cs" />
<Compile Include="NexusCacheModule.cs" /> <Compile Include="NexusCacheModule.cs" />
@ -80,10 +84,15 @@
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Server.cs" /> <Compile Include="Server.cs" />
<Compile Include="Heartbeat.cs" /> <Compile Include="Heartbeat.cs" />
<Compile Include="ServerConfig\BuildServerConfig.cs" />
<Compile Include="ServerConfig\MongoConfig.cs" />
<Compile Include="TestingEndpoints.cs" /> <Compile Include="TestingEndpoints.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="App.config" /> <None Include="App.config" />
<None Include="config.yaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Wabbajack.Common\Wabbajack.Common.csproj"> <ProjectReference Include="..\Wabbajack.Common\Wabbajack.Common.csproj">
@ -96,6 +105,12 @@
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="CouchDB.NET">
<Version>1.1.5</Version>
</PackageReference>
<PackageReference Include="MongoDB.Driver">
<Version>2.10.0</Version>
</PackageReference>
<PackageReference Include="Nancy.Hosting.Self"> <PackageReference Include="Nancy.Hosting.Self">
<Version>2.0.0</Version> <Version>2.0.0</Version>
</PackageReference> </PackageReference>
@ -109,5 +124,6 @@
<Version>4.3.2</Version> <Version>4.3.2</Version>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project> </Project>

View File

@ -0,0 +1,12 @@
---
Metrics:
Host: internal.test.mongodb
Database: wabbajack
Collection: metrics
ListValidation:
Host: internal.test.mongodb
Database: wabbajack
Collection: mod_lists

View File

@ -95,7 +95,7 @@ namespace Wabbajack.Lib
ModList.Readme = $"readme{readme.Extension}"; ModList.Readme = $"readme{readme.Extension}";
} }
ModList.ReadmeIsWebsite = ReadmeIsWebsite; //ModList.ReadmeIsWebsite = ReadmeIsWebsite;
ModList.ToCERAS(Path.Combine(ModListOutputFolder, "modlist"), CerasConfig.Config); ModList.ToCERAS(Path.Combine(ModListOutputFolder, "modlist"), CerasConfig.Config);

View File

@ -32,7 +32,7 @@ namespace Wabbajack.Lib
}, },
}; };
Config.VersionTolerance.Mode = VersionToleranceMode.Standard; //Config.VersionTolerance.Mode = VersionToleranceMode.Standard;
} }
} }
} }

View File

@ -119,7 +119,7 @@ namespace Wabbajack.Lib
/// <summary> /// <summary>
/// Whether readme is a website /// Whether readme is a website
/// </summary> /// </summary>
public bool ReadmeIsWebsite; //public bool ReadmeIsWebsite;
} }
public class Directive public class Directive

View File

@ -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 Alphaleonis.Win32.Filesystem;
using MongoDB.Bson.Serialization.Attributes;
using Wabbajack.Lib.Validation; using Wabbajack.Lib.Validation;
namespace Wabbajack.Lib.Downloaders namespace Wabbajack.Lib.Downloaders
@ -7,8 +11,37 @@ namespace Wabbajack.Lib.Downloaders
/// <summary> /// <summary>
/// Base for all abstract downloaders /// Base for all abstract downloaders
/// </summary> /// </summary>
[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 abstract class AbstractDownloadState
{ {
public static List<Type> KnownSubTypes = new List<Type>()
{
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<string, Type> NameToType { get; set; }
public static Dictionary<Type, string> 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);
}
/// <summary> /// <summary>
/// Returns true if this file is allowed to be downloaded via whitelist /// Returns true if this file is allowed to be downloaded via whitelist
/// </summary> /// </summary>

View File

@ -320,7 +320,7 @@ namespace Wabbajack.Lib
Utils.Log( Utils.Log(
$"Removing {remove.Count} archives from the compilation state, this is probably not an issue but reference this if you have compilation failures"); $"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)); IndexedArchives.RemoveAll(a => remove.Contains(a));
} }

View File

@ -57,6 +57,9 @@
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="MongoDB.Bson">
<HintPath>..\..\..\Users\tbald\.nuget\packages\mongodb.bson\2.10.0\lib\net452\MongoDB.Bson.dll</HintPath>
</Reference>
<Reference Include="PresentationCore" /> <Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" /> <Reference Include="PresentationFramework" />
<Reference Include="System" /> <Reference Include="System" />
@ -206,6 +209,9 @@
<PackageReference Include="Microsoft.Toolkit.Wpf.UI.Controls.WebView"> <PackageReference Include="Microsoft.Toolkit.Wpf.UI.Controls.WebView">
<Version>6.0.0</Version> <Version>6.0.0</Version>
</PackageReference> </PackageReference>
<PackageReference Include="MongoDB.Bson">
<Version>2.10.0</Version>
</PackageReference>
<PackageReference Include="Newtonsoft.Json"> <PackageReference Include="Newtonsoft.Json">
<Version>12.0.3</Version> <Version>12.0.3</Version>
</PackageReference> </PackageReference>

View File

@ -87,7 +87,7 @@ namespace Wabbajack
public void OpenReadmeWindow() public void OpenReadmeWindow()
{ {
if (string.IsNullOrEmpty(Readme)) return; if (string.IsNullOrEmpty(Readme)) return;
if (SourceModList.ReadmeIsWebsite) if (false) //SourceModList.ReadmeIsWebsite)
{ {
Process.Start(Readme); Process.Start(Readme);
} }