Metrics bug fixes

This commit is contained in:
Timothy Baldridge 2020-01-09 19:06:11 -07:00
parent ad5c8b83e6
commit 94b01a0454
12 changed files with 111 additions and 94 deletions

View File

@ -4,10 +4,11 @@ using Wabbajack.BuildServer.Models;
namespace Wabbajack.BuildServer.Controllers namespace Wabbajack.BuildServer.Controllers
{ {
[ApiController]
public abstract class AControllerBase<T> : ControllerBase public abstract class AControllerBase<T> : ControllerBase
{ {
protected readonly ILogger<T> Logger;
protected readonly DBContext Db; protected readonly DBContext Db;
protected readonly ILogger<T> Logger;
protected AControllerBase(ILogger<T> logger, DBContext db) protected AControllerBase(ILogger<T> logger, DBContext db)
{ {

View File

@ -1,12 +1,8 @@
using System.Collections.Generic; using System.Threading.Tasks;
using System.Reflection.Metadata;
using System.Threading.Tasks;
using GraphQL; using GraphQL;
using GraphQL.Language.AST;
using GraphQL.Types; using GraphQL.Types;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using Wabbajack.BuildServer.GraphQL; using Wabbajack.BuildServer.GraphQL;
using Wabbajack.BuildServer.Models; using Wabbajack.BuildServer.Models;
@ -24,12 +20,8 @@ namespace Wabbajack.BuildServer.Controllers
public async Task<IActionResult> Post([FromBody] GraphQLQuery query) public async Task<IActionResult> Post([FromBody] GraphQLQuery query)
{ {
var inputs = query.Variables.ToInputs(); var inputs = query.Variables.ToInputs();
var schema = new Schema var schema = new Schema {Query = new Query(Db), Mutation = new Mutation(Db)};
{
Query = new Query(Db),
Mutation = new Mutation(Db)
};
var result = await new DocumentExecuter().ExecuteAsync(_ => var result = await new DocumentExecuter().ExecuteAsync(_ =>
{ {
_.Schema = schema; _.Schema = schema;
@ -37,14 +29,13 @@ namespace Wabbajack.BuildServer.Controllers
_.OperationName = query.OperationName; _.OperationName = query.OperationName;
_.Inputs = inputs; _.Inputs = inputs;
}); });
if(result.Errors?.Count > 0) if (result.Errors?.Count > 0)
{ {
return BadRequest(); return BadRequest();
} }
return Ok(result); return Ok(result);
} }
} }
} }

View File

@ -0,0 +1,31 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Wabbajack.BuildServer.Models;
using Wabbajack.Common;
namespace Wabbajack.BuildServer.Controllers
{
[Route("/heartbeat")]
public class Heartbeat : AControllerBase<Heartbeat>
{
static Heartbeat()
{
_startTime = DateTime.Now;
}
private static DateTime _startTime;
public Heartbeat(ILogger<Heartbeat> logger, DBContext db) : base(logger, db)
{
}
[HttpGet]
public async Task<TimeSpan> GetHeartbeat()
{
return DateTime.Now - _startTime;
}
}
}

View File

@ -22,7 +22,7 @@ namespace Wabbajack.BuildServer.Controllers
[Route("{xxHashAsBase64}")] [Route("{xxHashAsBase64}")]
public async Task<IndexedVirtualFile> GetFile(string xxHashAsBase64) public async Task<IndexedVirtualFile> GetFile(string xxHashAsBase64)
{ {
var id = xxHashAsBase64;//.FromHex().ToBase64(); var id = xxHashAsBase64.FromHex().ToBase64();
var query = new[] var query = new[]
{ {
new BsonDocument("$match", new BsonDocument("$match",
@ -47,16 +47,18 @@ namespace Wabbajack.BuildServer.Controllers
if (t == null) if (t == null)
return null; return null;
Dictionary<string, TreeResult> indexed_children= new Dictionary<string, TreeResult>(); Dictionary<string, TreeResult> indexed_children = new Dictionary<string, TreeResult>();
if (t.IsArchive) if (t.IsArchive)
indexed_children = t.ChildFiles.ToDictionary(t => t.Hash); indexed_children = t.ChildFiles.ToDictionary(t => t.Hash);
var file = new IndexedVirtualFile var file = new IndexedVirtualFile
{ {
Name = Name, Name = Name,
Size = t.Size, Size = t.Size,
Hash = t.Hash, Hash = t.Hash,
Children = t.IsArchive ? t.Children.Select(child => Convert(indexed_children[child.Hash], child.Name)).ToList() : new List<IndexedVirtualFile>() Children = t.IsArchive
? t.Children.Select(child => Convert(indexed_children[child.Hash], child.Name)).ToList()
: new List<IndexedVirtualFile>()
}; };
return file; return file;
} }
@ -68,7 +70,5 @@ namespace Wabbajack.BuildServer.Controllers
{ {
public List<TreeResult> ChildFiles { get; set; } public List<TreeResult> ChildFiles { get; set; }
} }
} }
} }

View File

@ -26,6 +26,5 @@ namespace Wabbajack.BuildServer.Controllers
.OrderByDescending(j => j.Priority) .OrderByDescending(j => j.Priority)
.ToListAsync(); .ToListAsync();
} }
} }
} }

View File

@ -11,13 +11,12 @@ namespace Wabbajack.BuildServer.Controllers
{ {
[ApiController] [ApiController]
[Route("/lists")] [Route("/lists")]
public class ListValidation : AControllerBase<ListValidation> public class ListValidation : AControllerBase<ListValidation>
{ {
public ListValidation(ILogger<ListValidation> logger, DBContext db) : base(logger, db) public ListValidation(ILogger<ListValidation> logger, DBContext db) : base(logger, db)
{ {
} }
[HttpGet] [HttpGet]
[Route("status.json")] [Route("status.json")]
public async Task<IList<ModlistSummary>> HandleGetLists() public async Task<IList<ModlistSummary>> HandleGetLists()

View File

@ -1,35 +0,0 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Wabbajack.BuildServer.Models;
using Wabbajack.Common;
namespace Wabbajack.BuildServer.Controllers
{
[Route("/metrics")]
public class Metrics : AControllerBase<Metrics>
{
[HttpGet]
[Route("{Action}/Value")]
public async Task<string> NewMetric(string Action, string Value)
{
var date = DateTime.UtcNow;
await Log(date, Action, Value, Request.Headers[Consts.MetricsKeyHeader].FirstOrDefault());
return date.ToString();
}
public Metrics(ILogger<Metrics> logger, DBContext db) : base(logger, db)
{
}
internal 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());
await Db.Metrics.InsertOneAsync(new Metric {Timestamp = timestamp, Action = action, Subject = subject, MetricsKey = metricsKey});
}
}
}

View File

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using Wabbajack.BuildServer.Models;
using Wabbajack.Common;
using Wabbajack.Lib.ModListRegistry;
namespace Wabbajack.BuildServer.Controllers
{
[ApiController]
[Route("/metrics")]
public class MetricsController : AControllerBase<MetricsController>
{
public MetricsController(ILogger<MetricsController> logger, DBContext db) : base(logger, db)
{
}
[HttpGet]
[Route("{Subject}/{Value}")]
public async Task<Result> LogMetricAsync(string Subject, string Value)
{
var date = DateTime.UtcNow;
await Log(date, Subject, Value, Request.Headers[Consts.MetricsKeyHeader].FirstOrDefault());
return new Result { Timestamp = date};
}
private async Task Log(DateTime timestamp, string action, string subject, string metricsKey = null)
{
Logger.Log(LogLevel.Information, $"Log - {timestamp} {action} {subject} {metricsKey}");
await Db.Metrics.InsertOneAsync(new Metric
{
Timestamp = timestamp, Action = action, Subject = subject, MetricsKey = metricsKey
});
}
public class Result
{
public DateTime Timestamp { get; set; }
}
}
}

View File

@ -13,14 +13,13 @@ namespace Wabbajack.BuildServer.Controllers
[Route("/v1/games/")] [Route("/v1/games/")]
public class NexusCache : AControllerBase<NexusCache> public class NexusCache : AControllerBase<NexusCache>
{ {
public NexusCache(ILogger<NexusCache> logger, DBContext db) : base(logger, db) public NexusCache(ILogger<NexusCache> logger, DBContext db) : base(logger, db)
{ {
} }
/// <summary> /// <summary>
/// Looks up the mod details for a given Gamename/ModId pair. If the entry is not found in the cache it will /// Looks up the mod details for a given Gamename/ModId pair. If the entry is not found in the cache it will
/// be requested from the server (using the caller's Nexus API key if provided). /// be requested from the server (using the caller's Nexus API key if provided).
/// </summary> /// </summary>
/// <param name="db"></param> /// <param name="db"></param>
/// <param name="GameName">The Nexus game name</param> /// <param name="GameName">The Nexus game name</param>
@ -38,13 +37,7 @@ namespace Wabbajack.BuildServer.Controllers
var api = await NexusApiClient.Get(Request.Headers["apikey"].FirstOrDefault()); var api = await NexusApiClient.Get(Request.Headers["apikey"].FirstOrDefault());
var path = $"/v1/games/{GameName}/mods/{ModId}.json"; var path = $"/v1/games/{GameName}/mods/{ModId}.json";
var body = await api.Get<ModInfo>(path); var body = await api.Get<ModInfo>(path);
result = new NexusCacheData<ModInfo> result = new NexusCacheData<ModInfo> {Data = body, Path = path, Game = GameName, ModId = ModId};
{
Data = body,
Path = path,
Game = GameName,
ModId = ModId
};
try try
{ {
await Db.NexusModInfos.InsertOneAsync(result); await Db.NexusModInfos.InsertOneAsync(result);
@ -74,10 +67,7 @@ namespace Wabbajack.BuildServer.Controllers
var body = await api.Get<NexusApiClient.GetModFilesResponse>(path); var body = await api.Get<NexusApiClient.GetModFilesResponse>(path);
result = new NexusCacheData<NexusApiClient.GetModFilesResponse> result = new NexusCacheData<NexusApiClient.GetModFilesResponse>
{ {
Data = body, Data = body, Path = path, Game = GameName, ModId = ModId
Path = path,
Game = GameName,
ModId = ModId
}; };
try try
{ {
@ -85,7 +75,6 @@ namespace Wabbajack.BuildServer.Controllers
} }
catch (MongoWriteException) catch (MongoWriteException)
{ {
} }
method = "NOT_CACHED"; method = "NOT_CACHED";
@ -96,10 +85,11 @@ namespace Wabbajack.BuildServer.Controllers
} }
[HttpGet] [HttpGet]
[Route("{GameName}/mods/{ModId}/files/{FileId}.json")] [Route("{GameName}/mods/{ModId}/files/{FileId}.json")]
public async Task<object> GetFileInfo(string GameName, string ModId, string FileId) public async Task<object> GetFileInfo(string GameName, string ModId, string FileId)
{ {
var result = await Db.NexusFileInfos.FindOneAsync(info => info.Game == GameName && info.ModId == ModId && info.FileId == FileId); var result = await Db.NexusFileInfos.FindOneAsync(info =>
info.Game == GameName && info.ModId == ModId && info.FileId == FileId);
string method = "CACHED"; string method = "CACHED";
if (result == null) if (result == null)
@ -109,9 +99,9 @@ namespace Wabbajack.BuildServer.Controllers
var body = await api.Get<NexusFileInfo>(path); var body = await api.Get<NexusFileInfo>(path);
result = new NexusCacheData<NexusFileInfo> result = new NexusCacheData<NexusFileInfo>
{ {
Data = body, Data = body,
Path = path, Path = path,
Game = GameName, Game = GameName,
ModId = ModId, ModId = ModId,
FileId = FileId FileId = FileId
}; };
@ -121,7 +111,6 @@ namespace Wabbajack.BuildServer.Controllers
} }
catch (MongoWriteException) catch (MongoWriteException)
{ {
} }
method = "NOT_CACHED"; method = "NOT_CACHED";
@ -130,7 +119,5 @@ namespace Wabbajack.BuildServer.Controllers
Response.Headers.Add("x-cache-method", method); Response.Headers.Add("x-cache-method", method);
return result.Data; return result.Data;
} }
} }
} }

View File

@ -15,12 +15,12 @@ namespace Wabbajack.BuildServer
{ {
CreateHostBuilder(args).Build().Run(); CreateHostBuilder(args).Build().Run();
} }
public static IHostBuilder CreateHostBuilder(string[] args) => public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args) Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => .ConfigureWebHostDefaults(webBuilder =>
{ {
webBuilder.UseUrls("http://*:5000", "https://*:5001"); webBuilder.UseUrls("http://*:5000");
webBuilder.UseStartup<Startup>(); webBuilder.UseStartup<Startup>();
}); });
} }

View File

@ -22,6 +22,7 @@ using Swashbuckle.AspNetCore.Swagger;
using Wabbajack.BuildServer.Controllers; using Wabbajack.BuildServer.Controllers;
using Wabbajack.BuildServer.Models; using Wabbajack.BuildServer.Models;
using Microsoft.AspNetCore.Mvc.NewtonsoftJson; using Microsoft.AspNetCore.Mvc.NewtonsoftJson;
using Wabbajack.BuildServer.Controllers;
using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.FileProviders;
using Directory = System.IO.Directory; using Directory = System.IO.Directory;
@ -44,15 +45,15 @@ namespace Wabbajack.BuildServer
{ {
c.SwaggerDoc("v1", new OpenApiInfo {Title = "Wabbajack Build API", Version = "v1"}); c.SwaggerDoc("v1", new OpenApiInfo {Title = "Wabbajack Build API", Version = "v1"});
}); });
services.AddSingleton<DBContext>(); services.AddSingleton<DBContext>();
services.AddSingleton<JobManager>(); services.AddSingleton<JobManager>();
services.AddSingleton<AppSettings>(); services.AddSingleton<AppSettings>();
services.AddControllers(o => services.AddMvc();
services.AddControllers()
.AddNewtonsoftJson(o =>
{ {
}).AddNewtonsoftJson(o =>
{
o.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; o.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
}); });

View File

@ -2,11 +2,8 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>netcoreapp3.1</TargetFramework>
<OutputType>Exe</OutputType>
<UserSecretsId>aspnet-Wabbajack.BuildServer-6E798B30-DB04-4436-BE65-F043AF37B314</UserSecretsId> <UserSecretsId>aspnet-Wabbajack.BuildServer-6E798B30-DB04-4436-BE65-F043AF37B314</UserSecretsId>
<WebProject_DirectoryAccessLevelKey>0</WebProject_DirectoryAccessLevelKey> <WebProject_DirectoryAccessLevelKey>0</WebProject_DirectoryAccessLevelKey>
<PublishTrimmed>true</PublishTrimmed>
<PublishSingleFile>true</PublishSingleFile>
<RuntimeIdentifier>win10-x64</RuntimeIdentifier> <RuntimeIdentifier>win10-x64</RuntimeIdentifier>
<Configurations>Debug;Release</Configurations> <Configurations>Debug;Release</Configurations>
<Platforms>AnyCPU;x64</Platforms> <Platforms>AnyCPU;x64</Platforms>