mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
delete old server
This commit is contained in:
parent
ad844e8545
commit
f004595b5f
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
|
||||
</startup>
|
||||
</configuration>
|
@ -1,23 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using Wabbajack.Lib.Downloaders;
|
||||
|
||||
namespace Wabbajack.CacheServer.DTOs
|
||||
{
|
||||
public class DownloadState
|
||||
{
|
||||
[BsonId]
|
||||
public string Key { get; set; }
|
||||
public string Hash { get; set; }
|
||||
|
||||
public AbstractDownloadState State { get; set; }
|
||||
|
||||
public bool IsValid { get; set; }
|
||||
public DateTime LastValidationTime { get; set; } = DateTime.Now;
|
||||
public DateTime FirstValidationTime { get; set; } = DateTime.Now;
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.RightsManagement;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using Wabbajack.VirtualFileSystem;
|
||||
|
||||
namespace Wabbajack.CacheServer.DTOs
|
||||
{
|
||||
public class IndexedFile
|
||||
{
|
||||
[BsonId]
|
||||
public string Hash { get; set; }
|
||||
public string SHA256 { get; set; }
|
||||
public string SHA1 { get; set; }
|
||||
public string MD5 { get; set; }
|
||||
public string CRC { get; set; }
|
||||
public long Size { get; set; }
|
||||
public bool IsArchive { get; set; }
|
||||
public List<ChildFile> Children { get; set; } = new List<ChildFile>();
|
||||
}
|
||||
|
||||
public class ChildFile
|
||||
{
|
||||
public string Name;
|
||||
public string Extension;
|
||||
public string Hash;
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using Wabbajack.CacheServer.Jobs;
|
||||
|
||||
namespace Wabbajack.CacheServer.DTOs.JobQueue
|
||||
{
|
||||
public abstract class AJobPayload
|
||||
{
|
||||
public static List<Type> KnownSubTypes = new List<Type> {typeof(IndexJob)};
|
||||
public static Dictionary<Type, string> TypeToName { get; set; }
|
||||
public static Dictionary<string, Type> NameToType { get; set; }
|
||||
|
||||
|
||||
[BsonIgnore]
|
||||
public abstract string Description { get; }
|
||||
|
||||
public virtual bool UsesNexus { get; } = false;
|
||||
|
||||
public abstract Task<JobResult> Execute();
|
||||
|
||||
static AJobPayload()
|
||||
{
|
||||
NameToType = KnownSubTypes.ToDictionary(t => t.FullName.Substring(t.Namespace.Length + 1), t => t);
|
||||
TypeToName = NameToType.ToDictionary(k => k.Value, k => k.Key);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Wabbajack.CacheServer.DTOs.JobQueue
|
||||
{
|
||||
public class Job
|
||||
{
|
||||
public enum JobPriority : int
|
||||
{
|
||||
Low,
|
||||
Normal,
|
||||
High,
|
||||
}
|
||||
|
||||
[BsonId]
|
||||
public Guid Id { get; set; }
|
||||
public DateTime? Started { get; set; }
|
||||
public DateTime? Ended { get; set; }
|
||||
public DateTime Created { get; set; } = DateTime.Now;
|
||||
public JobPriority Priority { get; set; } = JobPriority.Normal;
|
||||
|
||||
public JobResult Result { get; set; }
|
||||
public bool RequiresNexus { get; set; } = true;
|
||||
public AJobPayload Payload { get; set; }
|
||||
|
||||
public static async Task<Guid> Enqueue(Job job)
|
||||
{
|
||||
await Server.Config.JobQueue.Connect().InsertOneAsync(job);
|
||||
return job.Id;
|
||||
}
|
||||
|
||||
public static async Task<Job> GetNext()
|
||||
{
|
||||
var filter = new BsonDocument
|
||||
{
|
||||
{"Started", BsonNull.Value}
|
||||
};
|
||||
var update = new BsonDocument
|
||||
{
|
||||
{"$set", new BsonDocument {{"Started", DateTime.Now}}}
|
||||
};
|
||||
var sort = new {Priority=-1, Created=1}.ToBsonDocument();
|
||||
var job = await Server.Config.JobQueue.Connect().FindOneAndUpdateAsync<Job>(filter, update, new FindOneAndUpdateOptions<Job>{Sort = sort});
|
||||
return job;
|
||||
}
|
||||
|
||||
public static async Task<Job> Finish(Job job, JobResult jobResult)
|
||||
{
|
||||
var filter = new BsonDocument
|
||||
{
|
||||
{"query", new BsonDocument {{"Id", job.Id}}},
|
||||
};
|
||||
var update = new BsonDocument
|
||||
{
|
||||
{"$set", new BsonDocument {{"Ended", DateTime.Now}, {"Result", jobResult.ToBsonDocument()}}}
|
||||
};
|
||||
var result = await Server.Config.JobQueue.Connect().FindOneAndUpdateAsync<Job>(filter, update);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
|
||||
namespace Wabbajack.CacheServer.DTOs.JobQueue
|
||||
{
|
||||
public class JobResult
|
||||
{
|
||||
public JobResultType ResultType { get; set; }
|
||||
[BsonIgnoreIfNull]
|
||||
public string Message { get; set; }
|
||||
|
||||
[BsonIgnoreIfNull]
|
||||
public string Stacktrace { get; set; }
|
||||
|
||||
public static JobResult Success()
|
||||
{
|
||||
return new JobResult { ResultType = JobResultType.Success };
|
||||
}
|
||||
|
||||
public static JobResult Error(Exception ex)
|
||||
{
|
||||
return new JobResult {ResultType = JobResultType.Error, Stacktrace = ex.ToString()};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public enum JobResultType
|
||||
{
|
||||
Success,
|
||||
Error
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
using System;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
|
||||
|
||||
namespace Wabbajack.CacheServer.DTOs
|
||||
{
|
||||
public class Metric
|
||||
{
|
||||
[BsonId]
|
||||
public ObjectId Id;
|
||||
public DateTime Timestamp;
|
||||
public string Action;
|
||||
public string Subject;
|
||||
public string MetricsKey;
|
||||
}
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using MongoDB.Driver;
|
||||
using MongoDB.Driver.Linq;
|
||||
using Wabbajack.Lib;
|
||||
using Wabbajack.Lib.ModListRegistry;
|
||||
|
||||
namespace Wabbajack.CacheServer.DTOs
|
||||
{
|
||||
public class ModListStatus
|
||||
{
|
||||
|
||||
[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 IMongoQueryable<ModListStatus> All
|
||||
{
|
||||
get
|
||||
{
|
||||
return Server.Config.ListValidation.Connect().AsQueryable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class DetailedStatus
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public DateTime Checked { get; set; } = 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; }
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
|
||||
namespace Wabbajack.CacheServer.DTOs
|
||||
{
|
||||
public class NexusCacheData<T>
|
||||
{
|
||||
[BsonId]
|
||||
public string Path { get; set; }
|
||||
public T Data { get; set; }
|
||||
public string Game { get; set; }
|
||||
public string ModId { get; set; }
|
||||
|
||||
public DateTime LastCheckedUTC { get; set; } = DateTime.UtcNow;
|
||||
|
||||
[BsonIgnoreIfNull]
|
||||
public string FileId { get; set; }
|
||||
|
||||
}
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
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.CacheServer.DTOs.JobQueue;
|
||||
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);
|
||||
BsonClassMap.RegisterClassMap<AbstractDownloadState>(cm => cm.SetIsRootClass(true));
|
||||
|
||||
dis = new TypeDiscriminator(typeof(AJobPayload), AJobPayload.NameToType, AJobPayload.TypeToName);
|
||||
BsonSerializer.RegisterDiscriminatorConvention(typeof(AJobPayload), dis);
|
||||
BsonClassMap.RegisterClassMap<AJobPayload>(cm => cm.SetIsRootClass(true));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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 = null;
|
||||
var bookmark = bsonReader.GetBookmark();
|
||||
bsonReader.ReadStartDocument();
|
||||
if (bsonReader.FindElement(ElementName))
|
||||
{
|
||||
var value = bsonReader.ReadString();
|
||||
if (typeMap.ContainsKey(value))
|
||||
type = typeMap[value];
|
||||
}
|
||||
|
||||
bsonReader.ReturnToBookmark(bookmark);
|
||||
if (type == null)
|
||||
throw new Exception($"Type mis-configuration can't find bson type for ${nominalType}");
|
||||
return type;
|
||||
}
|
||||
|
||||
public BsonValue GetDiscriminator(Type nominalType, Type actualType)
|
||||
{
|
||||
return revMap[actualType];
|
||||
}
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MongoDB.Driver;
|
||||
using MongoDB.Driver.Linq;
|
||||
|
||||
namespace Wabbajack.CacheServer
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
public static async Task<T> FindOneAsync<T>(this IMongoCollection<T> coll, Expression<Func<T, bool>> expr)
|
||||
{
|
||||
return (await coll.AsQueryable().Where(expr).Take(1).ToListAsync()).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
|
||||
<Costura />
|
||||
</Weavers>
|
@ -1,111 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
|
||||
<xs:element name="Weavers">
|
||||
<xs:complexType>
|
||||
<xs:all>
|
||||
<xs:element name="Costura" minOccurs="0" maxOccurs="1">
|
||||
<xs:complexType>
|
||||
<xs:all>
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeAssemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="IncludeAssemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged32Assemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with line breaks.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged64Assemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with line breaks.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="PreloadOrder" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The order of preloaded assemblies, delimited with line breaks.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:all>
|
||||
<xs:attribute name="CreateTemporaryAssemblies" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="IncludeDebugSymbols" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Controls if .pdbs for reference assemblies are also embedded.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="DisableCompression" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="DisableCleanup" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="LoadAtModuleInit" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="IgnoreSatelliteAssemblies" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="ExcludeAssemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="IncludeAssemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="Unmanaged32Assemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with |.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="Unmanaged64Assemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with |.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="PreloadOrder" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The order of preloaded assemblies, delimited with |.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:all>
|
||||
<xs:attribute name="VerifyAssembly" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="GenerateXsd" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:schema>
|
@ -1,24 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Nancy;
|
||||
|
||||
namespace Wabbajack.CacheServer
|
||||
{
|
||||
public class Heartbeat : NancyModule
|
||||
{
|
||||
private static DateTime startTime = DateTime.Now;
|
||||
|
||||
public Heartbeat() : base("/")
|
||||
{
|
||||
Get("/heartbeat", HandleHeartbeat);
|
||||
}
|
||||
|
||||
private object HandleHeartbeat(object arg)
|
||||
{
|
||||
return $"Service is live for: {DateTime.Now - startTime}";
|
||||
}
|
||||
}
|
||||
}
|
@ -1,144 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Security.Policy;
|
||||
using System.Threading.Tasks;
|
||||
using MongoDB.Driver;
|
||||
using MongoDB.Driver.Linq;
|
||||
using Nancy;
|
||||
using Nettle;
|
||||
using Wabbajack.CacheServer.DTOs.JobQueue;
|
||||
using Wabbajack.CacheServer.Jobs;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Lib;
|
||||
using Wabbajack.Lib.CompilationSteps;
|
||||
using Wabbajack.Lib.Downloaders;
|
||||
using Directory = Alphaleonis.Win32.Filesystem.Directory;
|
||||
using Path = Alphaleonis.Win32.Filesystem.Path;
|
||||
|
||||
namespace Wabbajack.CacheServer
|
||||
{
|
||||
public class JobQueueEndpoints : NancyModule
|
||||
{
|
||||
public JobQueueEndpoints() : base ("/jobs")
|
||||
{
|
||||
Get("/", HandleListJobs);
|
||||
Get("/enqueue_curated_for_indexing", HandleEnqueueAllCurated);
|
||||
Get("/enqueue_game_files_for_indexing", HandleEnqueueAllGameFiles);
|
||||
}
|
||||
|
||||
private readonly Func<object, string> HandleListJobsTemplate = NettleEngine.GetCompiler().Compile(@"
|
||||
<html><head/><body>
|
||||
|
||||
<h2>Jobs - {{$.jobs.Count}} Pending</h2>
|
||||
<h3>{{$.time}}</h3>
|
||||
<ol>
|
||||
{{each $.jobs}}
|
||||
<li>{{$.Description}}</li>
|
||||
{{/each}}
|
||||
</ol>
|
||||
|
||||
<script>
|
||||
setTimeout(function() { location.reload();}, 10000);
|
||||
</script>
|
||||
|
||||
</body></html>");
|
||||
|
||||
private async Task<Response> HandleListJobs(object arg)
|
||||
{
|
||||
var jobs = await Server.Config.JobQueue.Connect()
|
||||
.AsQueryable<Job>()
|
||||
.Where(j => j.Ended == null)
|
||||
.OrderByDescending(j => j.Priority)
|
||||
.ThenBy(j => j.Created)
|
||||
.ToListAsync();
|
||||
|
||||
var response = (Response)HandleListJobsTemplate(new {jobs, time = DateTime.Now});
|
||||
response.ContentType = "text/html";
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
private async Task<string> HandleEnqueueAllCurated(object arg)
|
||||
{
|
||||
var states = await Server.Config.ListValidation.Connect()
|
||||
.AsQueryable()
|
||||
.SelectMany(lst => lst.DetailedStatus.Archives)
|
||||
.Select(a => a.Archive)
|
||||
.ToListAsync();
|
||||
|
||||
var jobs = states.Select(state => new IndexJob {Archive = state})
|
||||
.Select(j => new Job {Payload = j, RequiresNexus = j.UsesNexus})
|
||||
.ToList();
|
||||
|
||||
if (jobs.Count > 0)
|
||||
await Server.Config.JobQueue.Connect().InsertManyAsync(jobs);
|
||||
|
||||
return $"Enqueued {states.Count} jobs";
|
||||
}
|
||||
|
||||
private async Task<string> HandleEnqueueAllGameFiles(object arg)
|
||||
{
|
||||
using (var queue = new WorkQueue(4))
|
||||
{
|
||||
var states = GameRegistry.Games.Values
|
||||
.Where(game => game.GameLocation() != null && game.MainExecutable != null)
|
||||
.SelectMany(game => Directory.EnumerateFiles(game.GameLocation(), "*", SearchOption.AllDirectories)
|
||||
.Select(file => new GameFileSourceDownloader.State
|
||||
{
|
||||
Game = game.Game,
|
||||
GameVersion = game.InstalledVersion,
|
||||
GameFile = file.RelativeTo(game.GameLocation()),
|
||||
}))
|
||||
.ToList();
|
||||
|
||||
await states.PMap(queue, state =>
|
||||
{
|
||||
state.Hash = Path.Combine(state.Game.MetaData().GameLocation(), state.GameFile).FileHash();
|
||||
});
|
||||
|
||||
var jobs = states.Select(state => new IndexJob {Archive = new Archive {Name = Path.GetFileName(state.GameFile), State = state}})
|
||||
.Select(j => new Job {Payload = j, RequiresNexus = j.UsesNexus})
|
||||
.ToList();
|
||||
|
||||
if (jobs.Count > 0)
|
||||
await Server.Config.JobQueue.Connect().InsertManyAsync(jobs);
|
||||
|
||||
return $"Enqueued {states.Count} Jobs";
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task StartJobQueue()
|
||||
{
|
||||
foreach (var task in Enumerable.Range(0, 4))
|
||||
{
|
||||
var tsk = StartJobQueueInner();
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task StartJobQueueInner()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
var job = await Job.GetNext();
|
||||
if (job == null)
|
||||
{
|
||||
await Task.Delay(5000);
|
||||
continue;
|
||||
}
|
||||
|
||||
var result = await job.Payload.Execute();
|
||||
await Job.Finish(job, result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Alphaleonis.Win32.Filesystem;
|
||||
using MongoDB.Driver;
|
||||
using MongoDB.Driver.Linq;
|
||||
using Wabbajack.CacheServer.DTOs;
|
||||
using Wabbajack.CacheServer.DTOs.JobQueue;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Lib;
|
||||
using Wabbajack.Lib.Downloaders;
|
||||
using Wabbajack.VirtualFileSystem;
|
||||
|
||||
namespace Wabbajack.CacheServer.Jobs
|
||||
{
|
||||
public class IndexJob : AJobPayload
|
||||
{
|
||||
public Archive Archive { get; set; }
|
||||
public override string Description { get; } = "Validate and index an archive";
|
||||
public override bool UsesNexus { get => Archive.State is NexusDownloader.State; }
|
||||
public override async Task<JobResult> Execute()
|
||||
{
|
||||
|
||||
var pk = new List<object>();
|
||||
pk.Add(AbstractDownloadState.TypeToName[Archive.State.GetType()]);
|
||||
pk.AddRange(Archive.State.PrimaryKey);
|
||||
var pk_str = string.Join("|",pk.Select(p => p.ToString()));
|
||||
|
||||
var found = await Server.Config.DownloadStates.Connect().AsQueryable().Where(f => f.Key == pk_str).Take(1).ToListAsync();
|
||||
if (found.Count > 0)
|
||||
return JobResult.Success();
|
||||
|
||||
string fileName = Archive.Name;
|
||||
string folder = Guid.NewGuid().ToString();
|
||||
Utils.Log($"Indexer is downloading {fileName}");
|
||||
var downloadDest = Path.Combine(Server.Config.Indexer.DownloadDir, folder, fileName);
|
||||
await Archive.State.Download(downloadDest);
|
||||
|
||||
using (var queue = new WorkQueue())
|
||||
{
|
||||
var vfs = new Context(queue, true);
|
||||
await vfs.AddRoot(Path.Combine(Server.Config.Indexer.DownloadDir, folder));
|
||||
var archive = vfs.Index.ByRootPath.First();
|
||||
var converted = ConvertArchive(new List<IndexedFile>(), archive.Value);
|
||||
try
|
||||
{
|
||||
await Server.Config.IndexedFiles.Connect().InsertManyAsync(converted, new InsertManyOptions {IsOrdered = false});
|
||||
}
|
||||
catch (MongoBulkWriteException)
|
||||
{
|
||||
}
|
||||
|
||||
await Server.Config.DownloadStates.Connect().InsertOneAsync(new DownloadState
|
||||
{
|
||||
Key = pk_str,
|
||||
Hash = archive.Value.Hash,
|
||||
State = Archive.State,
|
||||
IsValid = true
|
||||
});
|
||||
|
||||
var to_path = Path.Combine(Server.Config.Indexer.ArchiveDir,
|
||||
$"{Path.GetFileName(fileName)}_{archive.Value.Hash.FromBase64().ToHex()}_{Path.GetExtension(fileName)}");
|
||||
if (File.Exists(to_path))
|
||||
File.Delete(downloadDest);
|
||||
else
|
||||
File.Move(downloadDest, to_path);
|
||||
Utils.DeleteDirectory(Path.Combine(Server.Config.Indexer.DownloadDir, folder));
|
||||
}
|
||||
|
||||
return JobResult.Success();
|
||||
}
|
||||
|
||||
private List<IndexedFile> ConvertArchive(List<IndexedFile> files, VirtualFile file, bool isTop = true)
|
||||
{
|
||||
var name = isTop ? Path.GetFileName(file.Name) : file.Name;
|
||||
var ifile = new IndexedFile
|
||||
{
|
||||
Hash = file.Hash,
|
||||
SHA256 = file.ExtendedHashes.SHA256,
|
||||
SHA1 = file.ExtendedHashes.SHA1,
|
||||
MD5 = file.ExtendedHashes.MD5,
|
||||
CRC = file.ExtendedHashes.CRC,
|
||||
Size = file.Size,
|
||||
Children = file.Children != null ? file.Children.Select(
|
||||
f =>
|
||||
{
|
||||
ConvertArchive(files, f, false);
|
||||
|
||||
return new ChildFile
|
||||
{
|
||||
Hash = f.Hash,
|
||||
Name = f.Name.ToLowerInvariant(),
|
||||
Extension = Path.GetExtension(f.Name.ToLowerInvariant())
|
||||
};
|
||||
}).ToList() : new List<ChildFile>()
|
||||
};
|
||||
ifile.IsArchive = ifile.Children.Count > 0;
|
||||
files.Add(ifile);
|
||||
return files;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -1,252 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Alphaleonis.Win32.Filesystem;
|
||||
using MongoDB.Driver;
|
||||
using Nancy;
|
||||
using Wabbajack.CacheServer.DTOs;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Lib;
|
||||
using Wabbajack.Lib.Downloaders;
|
||||
using Wabbajack.Lib.ModListRegistry;
|
||||
using MongoDB.Driver.Linq;
|
||||
using Nettle;
|
||||
using Nettle.Functions;
|
||||
|
||||
namespace Wabbajack.CacheServer
|
||||
{
|
||||
public class ListValidationService : NancyModule
|
||||
{
|
||||
public ListValidationService() : base("/lists")
|
||||
{
|
||||
Get("/status", HandleGetLists);
|
||||
Get("/force_recheck", HandleForceRecheck);
|
||||
Get("/status/{Name}.json", HandleGetListJson);
|
||||
Get("/status/{Name}.html", HandleGetListHtml);
|
||||
Get("/status/{Name}/broken.rss", HandleGetRSSFeed);
|
||||
|
||||
}
|
||||
|
||||
private async Task<string> HandleForceRecheck(object arg)
|
||||
{
|
||||
await ValidateLists(false);
|
||||
return "done";
|
||||
}
|
||||
|
||||
private async Task<string> HandleGetLists(object arg)
|
||||
{
|
||||
var summaries = await ModListStatus.All.Select(m => m.Summary).ToListAsync();
|
||||
return summaries.ToJSON();
|
||||
}
|
||||
|
||||
public class ArchiveSummary
|
||||
{
|
||||
public string Name;
|
||||
public AbstractDownloadState State;
|
||||
}
|
||||
public class DetailedSummary
|
||||
{
|
||||
public string Name;
|
||||
public DateTime Checked;
|
||||
public List<ArchiveSummary> Failed;
|
||||
public List<ArchiveSummary> Passed;
|
||||
|
||||
}
|
||||
private async Task<string> HandleGetListJson(dynamic arg)
|
||||
{
|
||||
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 static readonly Func<object, string> HandleGetListTemplate = NettleEngine.GetCompiler().Compile(@"
|
||||
<html><body>
|
||||
<h2>{{lst.Name}} - {{lst.Checked}}</h2>
|
||||
<h3>Failed ({{failed.Count}}):</h3>
|
||||
<ul>
|
||||
{{each $.failed }}
|
||||
<li>{{$.Archive.Name}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
<h3>Passed ({{passed.Count}}):</h3>
|
||||
<ul>
|
||||
{{each $.passed }}
|
||||
<li>{{$.Archive.Name}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</body></html>
|
||||
");
|
||||
|
||||
private async Task<Response> HandleGetListHtml(dynamic arg)
|
||||
{
|
||||
|
||||
var lst = (await ModListStatus.ByName((string)arg.Name)).DetailedStatus;
|
||||
var response = (Response)HandleGetListTemplate(new
|
||||
{
|
||||
lst,
|
||||
failed = lst.Archives.Where(a => a.IsFailing).ToList(),
|
||||
passed = lst.Archives.Where(a => !a.IsFailing).ToList()
|
||||
});
|
||||
response.ContentType = "text/html";
|
||||
return response;
|
||||
}
|
||||
|
||||
private static readonly Func<object, string> HandleGetRSSFeedTemplate = NettleEngine.GetCompiler().Compile(@"
|
||||
<?xml version=""1.0""?>
|
||||
<rss version=""2.0"">
|
||||
<channel>
|
||||
<title>{{lst.Name}} - Broken Mods</title>
|
||||
<link>http://build.wabbajack.org/status/{{lst.Name}}.html</link>
|
||||
<description>These are mods that are broken and need updating</description>
|
||||
{{ each $.failed }}
|
||||
<item>
|
||||
<title>{{$.Archive.Name}}</title>
|
||||
<link>{{$.Archive.Name}}</link>
|
||||
</item>
|
||||
{{/each}}
|
||||
</channel>
|
||||
</rss>
|
||||
");
|
||||
|
||||
public async Task<Response> HandleGetRSSFeed(dynamic arg)
|
||||
{
|
||||
var metric = Metrics.Log("failed_rss", arg.Name);
|
||||
var lst = (await ModListStatus.ByName((string)arg.Name)).DetailedStatus;
|
||||
var response = (Response)HandleGetRSSFeedTemplate(new
|
||||
{
|
||||
lst,
|
||||
failed = lst.Archives.Where(a => a.IsFailing).ToList(),
|
||||
passed = lst.Archives.Where(a => !a.IsFailing).ToList()
|
||||
});
|
||||
response.ContentType = "application/rss+xml";
|
||||
await metric;
|
||||
return response;
|
||||
|
||||
}
|
||||
|
||||
public static void Start()
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
await ValidateLists();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utils.Log(ex.ToString());
|
||||
}
|
||||
|
||||
// Sleep for two hours
|
||||
await Task.Delay(1000 * 60 * 60 * 2);
|
||||
}
|
||||
}).FireAndForget();
|
||||
}
|
||||
public static async Task ValidateLists(bool skipIfNewer = true)
|
||||
{
|
||||
Utils.Log("Cleaning Nexus Cache");
|
||||
var client = new HttpClient();
|
||||
//await client.GetAsync("http://build.wabbajack.org/nexus_api_cache/update");
|
||||
|
||||
Utils.Log("Starting Modlist Validation");
|
||||
var modlists = await ModlistMetadata.LoadFromGithub();
|
||||
|
||||
using (var queue = new WorkQueue())
|
||||
{
|
||||
foreach (var list in modlists)
|
||||
{
|
||||
try
|
||||
{
|
||||
await ValidateList(list, queue, skipIfNewer);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utils.Log(ex.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Utils.Log($"Done validating {modlists.Count} lists");
|
||||
}
|
||||
|
||||
private static async Task ValidateList(ModlistMetadata list, WorkQueue queue, bool skipIfNewer = true)
|
||||
{
|
||||
var existing = await Server.Config.ListValidation.Connect().FindOneAsync(l => l.Id == list.Links.MachineURL);
|
||||
if (skipIfNewer && existing != null && DateTime.UtcNow - existing.DetailedStatus.Checked < TimeSpan.FromHours(2))
|
||||
return;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,140 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Alphaleonis.Win32.Filesystem;
|
||||
using MongoDB.Driver;
|
||||
using MongoDB.Driver.Linq;
|
||||
using Nancy;
|
||||
using Wabbajack.CacheServer.DTOs;
|
||||
using Wabbajack.Common;
|
||||
|
||||
namespace Wabbajack.CacheServer
|
||||
{
|
||||
/// <summary>
|
||||
/// Extremely
|
||||
/// </summary>
|
||||
public class Metrics : NancyModule
|
||||
{
|
||||
private static SemaphoreSlim _lockObject = new SemaphoreSlim(1);
|
||||
|
||||
public static async Task Log(DateTime timestamp, string action, string subject, string metricsKey = null)
|
||||
{
|
||||
var msg = new[] {string.Join("\t", new[]{timestamp.ToString(), metricsKey, action, subject})};
|
||||
Utils.Log(msg.First());
|
||||
var db = Server.Config.Metrics.Connect();
|
||||
await db.InsertOneAsync(new Metric {Timestamp = timestamp, Action = action, Subject = subject, MetricsKey = metricsKey});
|
||||
}
|
||||
|
||||
public static Task Log(string action, string subject)
|
||||
{
|
||||
return Log(DateTime.Now, action, subject);
|
||||
}
|
||||
|
||||
public Metrics() : base("/")
|
||||
{
|
||||
Get("/metrics/{Action}/{Value}", HandleMetrics);
|
||||
Get("/metrics/chart/", HandleChart);
|
||||
Get("/metrics/chart/{Action}/", 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)
|
||||
{
|
||||
var date = DateTime.UtcNow;
|
||||
await Log(date, arg.Action, arg.Value, Request.Headers[Consts.MetricsKeyHeader].FirstOrDefault());
|
||||
return date.ToString();
|
||||
}
|
||||
|
||||
private async Task<Response> HandleChart(dynamic arg)
|
||||
{
|
||||
/*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]});*/
|
||||
|
||||
var q = Server.Config.Metrics.Connect().AsQueryable();
|
||||
|
||||
// Remove guids / Default, which come from testing
|
||||
|
||||
if (arg?.Action != null)
|
||||
{
|
||||
var action = (string)arg.Action;
|
||||
q = q.Where(d => d.Action == action);
|
||||
}
|
||||
|
||||
|
||||
if (arg?.Value != null)
|
||||
{
|
||||
var value = (string)arg.Value;
|
||||
q = q.Where(d => d.Subject.StartsWith(value));
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.Append("<html><head><script src=\"https://cdn.jsdelivr.net/npm/chart.js@2.8.0\"></script></head>");
|
||||
sb.Append("<body><canvas id=\"myChart\"></canvas>");
|
||||
sb.Append("<script language='javascript'>");
|
||||
var script = @"var ctx = document.getElementById('myChart').getContext('2d');
|
||||
var chart = new Chart(ctx, {
|
||||
// The type of chart we want to create
|
||||
type: 'line',
|
||||
|
||||
// The data for our dataset
|
||||
data: {
|
||||
labels: [{{LABELS}}],
|
||||
datasets: [{
|
||||
label: '{{DATASET}}',
|
||||
backgroundColor: 'rgb(255, 99, 132)',
|
||||
borderColor: 'rgb(255, 99, 132)',
|
||||
data: [{{DATA}}]
|
||||
}]
|
||||
},
|
||||
|
||||
// Configuration options go here
|
||||
options: {}
|
||||
});";
|
||||
sb.Append(script.Replace("{{LABELS}}", string.Join(",", grouped_and_counted.Select(e => "'"+e.Day+"'")))
|
||||
.Replace("{{DATA}}", string.Join(",", grouped_and_counted.Select(e => e.Count.ToString())))
|
||||
.Replace("{{DATASET}}", (arg.Action ?? "*") + " - " + (arg.Value ?? "*")));
|
||||
|
||||
sb.Append("</script>");
|
||||
sb.Append("</body></html>");
|
||||
var response = (Response)sb.ToString();
|
||||
response.ContentType = "text/html";
|
||||
return response;
|
||||
}
|
||||
|
||||
public void Log(string l)
|
||||
{
|
||||
Utils.Log("Metrics: " + l);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,344 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MongoDB.Driver;
|
||||
using Nancy;
|
||||
using Newtonsoft.Json;
|
||||
using Wabbajack.CacheServer.DTOs;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Lib.Downloaders;
|
||||
using Wabbajack.Lib.NexusApi;
|
||||
|
||||
namespace Wabbajack.CacheServer
|
||||
{
|
||||
public class NexusCacheModule : NancyModule
|
||||
{
|
||||
|
||||
public NexusCacheModule() : base("/")
|
||||
{
|
||||
Get("/v1/games/{GameName}/mods/{ModID}/files/{FileID}.json", HandleFileID);
|
||||
Get("/v1/games/{GameName}/mods/{ModID}/files.json", HandleGetFiles);
|
||||
Get("/v1/games/{GameName}/mods/{ModID}.json", HandleModInfo);
|
||||
Get("/nexus_api_cache/{request}.json", HandleCacheCall);
|
||||
Get("/nexus_api_cache", ListCache);
|
||||
Get("/nexus_api_cache/update", UpdateCache);
|
||||
Get("/nexus_api_cache/ingest/{Folder}", HandleIngestCache);
|
||||
}
|
||||
|
||||
class UpdatedMod
|
||||
{
|
||||
public long mod_id;
|
||||
public long latest_file_update;
|
||||
public long latest_mod_activity;
|
||||
}
|
||||
|
||||
public async Task<object> UpdateCache(object arg)
|
||||
{
|
||||
var api = await NexusApiClient.Get(Request.Headers["apikey"].FirstOrDefault());
|
||||
|
||||
var gameTasks = GameRegistry.Games.Values
|
||||
.Where(game => game.NexusName != null)
|
||||
.Select(async game =>
|
||||
{
|
||||
return (game,
|
||||
mods: await api.Get<List<UpdatedMod>>(
|
||||
$"https://api.nexusmods.com/v1/games/{game.NexusName}/mods/updated.json?period=1m"));
|
||||
})
|
||||
.Select(async rTask =>
|
||||
{
|
||||
var (game, mods) = await rTask;
|
||||
return mods.Select(mod => new { game = game, mod = mod });
|
||||
}).ToList();
|
||||
|
||||
Utils.Log($"Getting update list for {gameTasks.Count} games");
|
||||
|
||||
var purge = (await Task.WhenAll(gameTasks))
|
||||
.SelectMany(i => i)
|
||||
.ToList();
|
||||
|
||||
Utils.Log($"Found {purge.Count} updated mods in the last month");
|
||||
using (var queue = new WorkQueue())
|
||||
{
|
||||
var collected = await purge.Select(d =>
|
||||
{
|
||||
var a = d.mod.latest_file_update.AsUnixTime();
|
||||
// Mod activity could hide files
|
||||
var b = d.mod.latest_mod_activity.AsUnixTime();
|
||||
|
||||
return new {Game = d.game.NexusName, Date = (a > b ? a : b), ModId = d.mod.mod_id.ToString()};
|
||||
}).PMap(queue, async t =>
|
||||
{
|
||||
var resultA = await Server.Config.NexusModInfos.Connect().DeleteManyAsync(f =>
|
||||
f.Game == t.Game && f.ModId == t.ModId && f.LastCheckedUTC <= t.Date);
|
||||
var resultB = await Server.Config.NexusModFiles.Connect().DeleteManyAsync(f =>
|
||||
f.Game == t.Game && f.ModId == t.ModId && f.LastCheckedUTC <= t.Date);
|
||||
var resultC = await Server.Config.NexusFileInfos.Connect().DeleteManyAsync(f =>
|
||||
f.Game == t.Game && f.ModId == t.ModId && f.LastCheckedUTC <= t.Date);
|
||||
|
||||
return resultA.DeletedCount + resultB.DeletedCount + resultC.DeletedCount;
|
||||
});
|
||||
|
||||
Utils.Log($"Purged {collected.Sum()} cache entries");
|
||||
}
|
||||
|
||||
return "Done";
|
||||
}
|
||||
|
||||
private string ListCache(object arg)
|
||||
{
|
||||
Utils.Log($"{DateTime.Now} - List Cache");
|
||||
return String.Join("",
|
||||
Directory.EnumerateFiles(NexusApiClient.LocalCacheDir)
|
||||
.Select(f => new FileInfo(f))
|
||||
.OrderByDescending(fi => fi.LastWriteTime)
|
||||
.Select(fi =>
|
||||
{
|
||||
var decoded = Encoding.UTF8.GetString(Path.GetFileNameWithoutExtension(fi.Name).FromHex());
|
||||
return $"{fi.LastWriteTime} \t {fi.Length.ToFileSizeString()} \t {decoded} \n";
|
||||
}));
|
||||
}
|
||||
|
||||
private async Task<Response> HandleModInfo(dynamic arg)
|
||||
{
|
||||
Utils.Log($"{DateTime.Now} - Mod Info - {arg.GameName}/{arg.ModID}/");
|
||||
string gameName = arg.GameName;
|
||||
string modId = arg.ModId;
|
||||
var result = await Server.Config.NexusModInfos.Connect()
|
||||
.FindOneAsync(info => info.Game == gameName && info.ModId == modId);
|
||||
|
||||
string method = "CACHED";
|
||||
if (result == null)
|
||||
{
|
||||
var api = await NexusApiClient.Get(Request.Headers["apikey"].FirstOrDefault());
|
||||
var path = $"/v1/games/{gameName}/mods/{modId}.json";
|
||||
var body = await api.Get<ModInfo>(path);
|
||||
result = new NexusCacheData<ModInfo>
|
||||
{
|
||||
Data = body,
|
||||
Path = path,
|
||||
Game = gameName,
|
||||
ModId = modId
|
||||
};
|
||||
try
|
||||
{
|
||||
await Server.Config.NexusModInfos.Connect().InsertOneAsync(result);
|
||||
}
|
||||
catch (MongoWriteException)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
method = "NOT_CACHED";
|
||||
}
|
||||
|
||||
Response response = result.Data.ToJSON();
|
||||
response.Headers.Add("WABBAJACK_CACHE_FROM", method);
|
||||
response.ContentType = "application/json";
|
||||
return response;
|
||||
}
|
||||
|
||||
private async Task<Response> HandleFileID(dynamic arg)
|
||||
{
|
||||
Utils.Log($"{DateTime.Now} - File Info - {arg.GameName}/{arg.ModID}/{arg.FileID}");
|
||||
string gameName = arg.GameName;
|
||||
string modId = arg.ModId;
|
||||
string fileId = arg.FileId;
|
||||
var result = await Server.Config.NexusFileInfos.Connect()
|
||||
.FindOneAsync(info => info.Game == gameName && info.ModId == modId && info.FileId == fileId);
|
||||
|
||||
string method = "CACHED";
|
||||
if (result == null)
|
||||
{
|
||||
var api = await NexusApiClient.Get(Request.Headers["apikey"].FirstOrDefault());
|
||||
var path = $"/v1/games/{gameName}/mods/{modId}/files/{fileId}.json";
|
||||
var body = await api.Get<NexusFileInfo>(path);
|
||||
result = new NexusCacheData<NexusFileInfo>
|
||||
{
|
||||
Data = body,
|
||||
Path = path,
|
||||
Game = gameName,
|
||||
ModId = modId,
|
||||
FileId = fileId
|
||||
};
|
||||
try
|
||||
{
|
||||
await Server.Config.NexusFileInfos.Connect().InsertOneAsync(result);
|
||||
}
|
||||
catch (MongoWriteException)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
method = "NOT_CACHED";
|
||||
}
|
||||
|
||||
Response response = result.Data.ToJSON();
|
||||
response.Headers.Add("WABBAJACK_CACHE_FROM", method);
|
||||
response.ContentType = "application/json";
|
||||
return response;
|
||||
}
|
||||
|
||||
private async Task<Response> HandleGetFiles(dynamic arg)
|
||||
{
|
||||
Utils.Log($"{DateTime.Now} - Mod Files - {arg.GameName} {arg.ModID}");
|
||||
string gameName = arg.GameName;
|
||||
string modId = arg.ModId;
|
||||
var result = await Server.Config.NexusModFiles.Connect()
|
||||
.FindOneAsync(info => info.Game == gameName && info.ModId == modId);
|
||||
|
||||
string method = "CACHED";
|
||||
if (result == null)
|
||||
{
|
||||
var api = await NexusApiClient.Get(Request.Headers["apikey"].FirstOrDefault());
|
||||
var path = $"/v1/games/{gameName}/mods/{modId}/files.json";
|
||||
var body = await api.Get<NexusApiClient.GetModFilesResponse>(path);
|
||||
result = new NexusCacheData<NexusApiClient.GetModFilesResponse>
|
||||
{
|
||||
Data = body,
|
||||
Path = path,
|
||||
Game = gameName,
|
||||
ModId = modId
|
||||
};
|
||||
try
|
||||
{
|
||||
await Server.Config.NexusModFiles.Connect().InsertOneAsync(result);
|
||||
}
|
||||
catch (MongoWriteException)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
method = "NOT_CACHED";
|
||||
}
|
||||
|
||||
Response response = result.Data.ToJSON();
|
||||
response.Headers.Add("WABBAJACK_CACHE_FROM", method);
|
||||
response.ContentType = "application/json";
|
||||
return response;
|
||||
}
|
||||
|
||||
private async Task<string> HandleCacheCall(dynamic arg)
|
||||
{
|
||||
try
|
||||
{
|
||||
string param = (string)arg.request;
|
||||
var url = new Uri(Encoding.UTF8.GetString(param.FromHex()));
|
||||
|
||||
var client = new HttpClient();
|
||||
var builder = new UriBuilder(url) {Host = "localhost", Port = Request.Url.Port ?? 8080, Scheme = "http"};
|
||||
client.DefaultRequestHeaders.Add("apikey", Request.Headers["apikey"]);
|
||||
return await client.GetStringAsync(builder.Uri.ToString());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utils.Log(ex.ToString());
|
||||
return "ERROR";
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<string> HandleIngestCache(dynamic arg)
|
||||
{
|
||||
int count = 0;
|
||||
int failed = 0;
|
||||
|
||||
using (var queue = new WorkQueue())
|
||||
{
|
||||
await Directory.EnumerateFiles(Path.Combine(Server.Config.Settings.TempDir, (string)arg.Folder)).PMap(queue,
|
||||
async file =>
|
||||
{
|
||||
Utils.Log($"Ingesting {file}");
|
||||
if (!file.EndsWith(".json")) return;
|
||||
|
||||
var fileInfo = new FileInfo(file);
|
||||
count++;
|
||||
|
||||
var url = new Url(
|
||||
Encoding.UTF8.GetString(Path.GetFileNameWithoutExtension(file).FromHex()));
|
||||
var split = url.Path.Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries);
|
||||
try
|
||||
{
|
||||
switch (split.Length)
|
||||
{
|
||||
case 5 when split[3] == "mods":
|
||||
{
|
||||
var body = file.FromJSON<ModInfo>();
|
||||
|
||||
var payload = new NexusCacheData<ModInfo>();
|
||||
payload.Data = body;
|
||||
payload.Game = split[2];
|
||||
payload.Path = url.Path;
|
||||
payload.ModId = body.mod_id;
|
||||
payload.LastCheckedUTC = fileInfo.LastWriteTimeUtc;
|
||||
|
||||
try
|
||||
{
|
||||
await Server.Config.NexusModInfos.Connect().InsertOneAsync(payload);
|
||||
}
|
||||
catch (MongoWriteException ex)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 6 when split[5] == "files.json":
|
||||
{
|
||||
var body = file.FromJSON<NexusApiClient.GetModFilesResponse>();
|
||||
var payload = new NexusCacheData<NexusApiClient.GetModFilesResponse>();
|
||||
payload.Path = url.Path;
|
||||
payload.Data = body;
|
||||
payload.Game = split[2];
|
||||
payload.ModId = split[4];
|
||||
payload.LastCheckedUTC = fileInfo.LastWriteTimeUtc;
|
||||
|
||||
try
|
||||
{
|
||||
await Server.Config.NexusModFiles.Connect().InsertOneAsync(payload);
|
||||
}
|
||||
catch (MongoWriteException ex)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 7 when split[5] == "files":
|
||||
{
|
||||
var body = file.FromJSON<NexusFileInfo>();
|
||||
var payload = new NexusCacheData<NexusFileInfo>();
|
||||
payload.Data = body;
|
||||
payload.Path = url.Path;
|
||||
payload.Game = split[2];
|
||||
payload.FileId = Path.GetFileNameWithoutExtension(split[6]);
|
||||
payload.ModId = split[4];
|
||||
payload.LastCheckedUTC = fileInfo.LastWriteTimeUtc;
|
||||
|
||||
try
|
||||
{
|
||||
await Server.Config.NexusFileInfos.Connect().InsertOneAsync(payload);
|
||||
}
|
||||
catch (MongoWriteException ex)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
failed++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return $"Inserted {count} caches, {failed} failed";
|
||||
}
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Nancy.Hosting.Self;
|
||||
using Wabbajack.Common;
|
||||
|
||||
namespace Wabbajack.CacheServer
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Utils.LogMessages.Subscribe(Console.WriteLine);
|
||||
using (var server = new Server("http://localhost:8080"))
|
||||
{
|
||||
Consts.WabbajackCacheHostname = "localhost";
|
||||
Consts.WabbajackCachePort = 8080;
|
||||
server.Start();
|
||||
|
||||
ListValidationService.Start();
|
||||
var tsk = JobQueueEndpoints.StartJobQueue();
|
||||
|
||||
Console.ReadLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Wabbajack.CacheServer")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Wabbajack.CacheServer")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2019")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("bdc9a094-d235-47cd-83ca-44199b60ab20")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
@ -1,3 +0,0 @@
|
||||
# Wabbajack.CacheServer
|
||||
|
||||
CacheServer for caching mod information to reduce the amount of API calls a user has to account for when using Wabbajack to compiler/install a ModList.
|
@ -1,79 +0,0 @@
|
||||
using System;
|
||||
using Alphaleonis.Win32.Filesystem;
|
||||
using Nancy;
|
||||
using Nancy.Bootstrapper;
|
||||
using Nancy.Configuration;
|
||||
using Nancy.Hosting.Self;
|
||||
using Nancy.TinyIoc;
|
||||
using Wabbajack.CacheServer.DTOs;
|
||||
using Wabbajack.CacheServer.ServerConfig;
|
||||
using Wabbajack.Common;
|
||||
|
||||
namespace Wabbajack.CacheServer
|
||||
{
|
||||
public class Server : IDisposable
|
||||
{
|
||||
private NancyHost _server;
|
||||
private HostConfiguration _config;
|
||||
public static BuildServerConfig Config;
|
||||
|
||||
static Server()
|
||||
{
|
||||
SerializerSettings.Init();
|
||||
}
|
||||
|
||||
|
||||
public Server(string address)
|
||||
{
|
||||
Address = address;
|
||||
_config = new HostConfiguration {MaximumConnectionCount = 200, RewriteLocalhost = true};
|
||||
//_config.UrlReservations.CreateAutomatically = true;
|
||||
_server = new NancyHost(_config, new Uri(address));
|
||||
|
||||
Config = File.ReadAllText("config.yaml").FromYaml<BuildServerConfig>();
|
||||
}
|
||||
|
||||
public string Address { get; }
|
||||
|
||||
public void Start()
|
||||
{
|
||||
_server.Start();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_server?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public class CachingBootstrapper : DefaultNancyBootstrapper
|
||||
{
|
||||
protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines)
|
||||
{
|
||||
pipelines.AfterRequest.AddItemToEndOfPipeline(ctx =>
|
||||
{
|
||||
ctx.Response.WithHeader("Access-Control-Allow-Origin", "*")
|
||||
.WithHeader("Access-Control-Allow-Methods", "POST, GET")
|
||||
.WithHeader("Access-Control-Allow-Headers", "Accept, Origin, Content-type")
|
||||
.WithHeader("Cache-Control","no-store");
|
||||
});
|
||||
}
|
||||
|
||||
public override void Configure(INancyEnvironment environment)
|
||||
{
|
||||
environment.Tracing(
|
||||
enabled: true,
|
||||
displayErrorTraces: true);
|
||||
}
|
||||
|
||||
protected override void ConfigureApplicationContainer(TinyIoCContainer container)
|
||||
{
|
||||
container.Register<Heartbeat>();
|
||||
container.Register<JobQueueEndpoints>();
|
||||
container.Register<ListValidationService>();
|
||||
container.Register<Metrics>();
|
||||
container.Register<NexusCacheModule>();
|
||||
container.Register<TestingEndpoints>();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MongoDB.Driver.Core.Configuration;
|
||||
using Wabbajack.CacheServer.DTOs;
|
||||
using Wabbajack.CacheServer.DTOs.JobQueue;
|
||||
using Wabbajack.Lib.NexusApi;
|
||||
|
||||
namespace Wabbajack.CacheServer.ServerConfig
|
||||
{
|
||||
public class BuildServerConfig
|
||||
{
|
||||
public MongoConfig<Metric> Metrics { get; set; }
|
||||
public MongoConfig<ModListStatus> ListValidation { get; set; }
|
||||
|
||||
public MongoConfig<Job> JobQueue { get; set; }
|
||||
|
||||
public MongoConfig<IndexedFile> IndexedFiles { get; set; }
|
||||
public MongoConfig<DownloadState> DownloadStates { get; set; }
|
||||
|
||||
public MongoConfig<NexusCacheData<ModInfo>> NexusModInfos { get; set; }
|
||||
public MongoConfig<NexusCacheData<NexusApiClient.GetModFilesResponse>> NexusModFiles { get; set; }
|
||||
public MongoConfig<NexusCacheData<NexusFileInfo>> NexusFileInfos { get; set; }
|
||||
|
||||
public IndexerConfig Indexer { get; set; }
|
||||
|
||||
public Settings Settings { get; set; }
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Wabbajack.CacheServer.ServerConfig
|
||||
{
|
||||
public class IndexerConfig
|
||||
{
|
||||
public string DownloadDir { get; set; }
|
||||
public string TempDir { get; set; }
|
||||
|
||||
public string ArchiveDir { get; set; }
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Wabbajack.CacheServer.ServerConfig
|
||||
{
|
||||
public class Settings
|
||||
{
|
||||
public string TempDir { get; set; }
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Nancy;
|
||||
using Nancy.Responses;
|
||||
|
||||
namespace Wabbajack.CacheServer
|
||||
{
|
||||
/// <summary>
|
||||
/// These endpoints are used by the testing service to verify that manual and direct
|
||||
/// downloading works as expected.
|
||||
/// </summary>
|
||||
public class TestingEndpoints : NancyModule
|
||||
{
|
||||
public TestingEndpoints() : base("/")
|
||||
{
|
||||
Get("/WABBAJACK_TEST_FILE.txt", _ => "Cheese for Everyone!");
|
||||
Get("/WABBAJACK_TEST_FILE.zip", _ =>
|
||||
{
|
||||
var response = new StreamResponse(() => new MemoryStream(Encoding.UTF8.GetBytes("Cheese for Everyone!")), "application/zip");
|
||||
return response.AsAttachment("WABBAJACK_TEST_FILE.zip");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,169 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{BDC9A094-D235-47CD-83CA-44199B60AB20}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>Wabbajack.CacheServer</RootNamespace>
|
||||
<AssemblyName>Wabbajack.CacheServer</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<Deterministic>true</Deterministic>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<NoWarn>CS1998</NoWarn>
|
||||
<WarningsAsErrors>CS4014</WarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<NoWarn>CS1998</NoWarn>
|
||||
<WarningsAsErrors>CS4014</WarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<NoWarn>CS1998</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<WarningsAsErrors>CS4014</WarningsAsErrors>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>CS1998</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<WarningsAsErrors>CS4014</WarningsAsErrors>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Windows" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="WindowsBase" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="DTOs\DownloadState.cs" />
|
||||
<Compile Include="DTOs\IndexedFile.cs" />
|
||||
<Compile Include="DTOs\JobQueue\AJobPayload.cs" />
|
||||
<Compile Include="DTOs\NexusCacheData.cs" />
|
||||
<Compile Include="Jobs\IndexJob.cs" />
|
||||
<Compile Include="DTOs\JobQueue\Job.cs" />
|
||||
<Compile Include="DTOs\JobQueue\JobResult.cs" />
|
||||
<Compile Include="DTOs\Metric.cs" />
|
||||
<Compile Include="DTOs\ModListStatus.cs" />
|
||||
<Compile Include="DTOs\MongoDoc.cs" />
|
||||
<Compile Include="DTOs\SerializerSettings.cs" />
|
||||
<Compile Include="Extensions.cs" />
|
||||
<Compile Include="JobQueueEndpoints.cs" />
|
||||
<Compile Include="ListValidationService.cs" />
|
||||
<Compile Include="Metrics.cs" />
|
||||
<Compile Include="NexusCacheModule.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Server.cs" />
|
||||
<Compile Include="Heartbeat.cs" />
|
||||
<Compile Include="ServerConfig\BuildServerConfig.cs" />
|
||||
<Compile Include="ServerConfig\IndexerConfig.cs" />
|
||||
<Compile Include="ServerConfig\MongoConfig.cs" />
|
||||
<Compile Include="TestingEndpoints.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="config.yaml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Wabbajack.Common\Wabbajack.Common.csproj">
|
||||
<Project>{B3F3FB6E-B9EB-4F49-9875-D78578BC7AE5}</Project>
|
||||
<Name>Wabbajack.Common</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Wabbajack.Lib\Wabbajack.Lib.csproj">
|
||||
<Project>{0a820830-a298-497d-85e0-e9a89efef5fe}</Project>
|
||||
<Name>Wabbajack.Lib</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Wabbajack.VirtualFileSystem\Wabbajack.VirtualFileSystem.csproj">
|
||||
<Project>{5d6a2eaf-6604-4c51-8ae2-a746b4bc5e3e}</Project>
|
||||
<Name>Wabbajack.VirtualFileSystem</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MongoDB.Driver">
|
||||
<Version>2.10.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Nancy.Hosting.Self">
|
||||
<Version>2.0.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Nettle">
|
||||
<Version>1.3.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Newtonsoft.Json">
|
||||
<Version>12.0.3</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="ReactiveUI">
|
||||
<Version>11.1.6</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.Reactive">
|
||||
<Version>4.3.2</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
@ -1,39 +0,0 @@
|
||||
---
|
||||
Metrics:
|
||||
Host: internal.test.mongodb
|
||||
Database: wabbajack
|
||||
Collection: metrics
|
||||
ListValidation:
|
||||
Host: internal.test.mongodb
|
||||
Database: wabbajack
|
||||
Collection: mod_lists
|
||||
JobQueue:
|
||||
Host: internal.test.mongodb
|
||||
Database: wabbajack
|
||||
Collection: job_queue
|
||||
IndexedFiles:
|
||||
Host: internal.test.mongodb
|
||||
Database: wabbajack
|
||||
Collection: indexed_files
|
||||
NexusModInfos:
|
||||
Host: internal.test.mongodb
|
||||
Database: wabbajack
|
||||
Collection: nexus_mod_infos
|
||||
NexusModFiles:
|
||||
Host: internal.test.mongodb
|
||||
Database: wabbajack
|
||||
Collection: nexus_mod_files
|
||||
NexusFileInfos:
|
||||
Host: internal.test.mongodb
|
||||
Database: wabbajack
|
||||
Collection: nexus_file_infos
|
||||
DownloadStates:
|
||||
Host: internal.test.mongodb
|
||||
Database: wabbajack
|
||||
Collection: download_states
|
||||
Indexer:
|
||||
DownloadDir: c:\tmp\downloads
|
||||
TempDir: c:\tmp\tmp
|
||||
ArchiveDir: c:\archives
|
||||
Settings:
|
||||
TempDir: c:\tmp\tmp
|
Loading…
Reference in New Issue
Block a user