mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
246 lines
8.3 KiB
C#
246 lines
8.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.Extensions.Logging;
|
|
using Nettle;
|
|
using Wabbajack.Common;
|
|
using Wabbajack.Server;
|
|
using Wabbajack.Server.DataLayer;
|
|
using Wabbajack.Server.DTOs;
|
|
using Wabbajack.Server.Services;
|
|
using WebSocketSharp;
|
|
using LogLevel = Microsoft.Extensions.Logging.LogLevel;
|
|
|
|
namespace Wabbajack.BuildServer.Controllers
|
|
{
|
|
[ApiController]
|
|
[Route("/metrics")]
|
|
public class MetricsController : ControllerBase
|
|
{
|
|
private SqlService _sql;
|
|
private ILogger<MetricsController> _logger;
|
|
private MetricsKeyCache _keyCache;
|
|
|
|
public MetricsController(ILogger<MetricsController> logger, SqlService sql, MetricsKeyCache keyCache)
|
|
{
|
|
_sql = sql;
|
|
_logger = logger;
|
|
_keyCache = keyCache;
|
|
}
|
|
|
|
[HttpGet]
|
|
[Route("{subject}/{value}")]
|
|
public async Task<Result> LogMetricAsync(string subject, string value)
|
|
{
|
|
var date = DateTime.UtcNow;
|
|
var metricsKey = Request.Headers[Consts.MetricsKeyHeader].FirstOrDefault();
|
|
if (metricsKey != null)
|
|
await _keyCache.AddKey(metricsKey);
|
|
|
|
// Used in tests
|
|
if (value == "Default" || value == "untitled" || subject == "failed_download" || Guid.TryParse(value, out _))
|
|
return new Result { Timestamp = date};
|
|
|
|
await Log(date, subject, value, metricsKey);
|
|
return new Result { Timestamp = date};
|
|
}
|
|
|
|
[HttpGet]
|
|
[Route("report/{subject}")]
|
|
[ResponseCache(Duration = 60 * 60)]
|
|
public async Task<IActionResult> MetricsReport(string subject)
|
|
{
|
|
var metrics = (await _sql.MetricsReport(subject)).ToList();
|
|
var labels = metrics.GroupBy(m => m.Date)
|
|
.OrderBy(m => m.Key)
|
|
.Select(m => m.Key)
|
|
.ToArray();
|
|
var labelStrings = labels.Select(l => l.ToString("MM-dd-yyy")).ToList();
|
|
var results = metrics
|
|
.GroupBy(m => m.Subject)
|
|
.Select(g =>
|
|
{
|
|
var indexed = g.ToDictionary(m => m.Date, m => m.Count);
|
|
return new MetricResult
|
|
{
|
|
SeriesName = g.Key,
|
|
Labels = labelStrings,
|
|
Values = labels.Select(l => indexed.TryGetValue(l, out var found) ? found : 0).ToList()
|
|
};
|
|
});
|
|
return Ok(results.ToList());
|
|
}
|
|
|
|
[HttpGet]
|
|
[Route("badge/{name}/total_installs_badge.json")]
|
|
public async Task<IActionResult> TotalInstallsBadge(string name)
|
|
{
|
|
var results = await _sql.TotalInstalls(name);
|
|
|
|
Response.ContentType = "application/json";
|
|
|
|
return Ok(results == 0
|
|
? new Badge($"Modlist {name} not found!", "Error") {color = "red"}
|
|
: new Badge("Installations: ", "____") {color = "green"});
|
|
}
|
|
|
|
[HttpGet]
|
|
[Route("badge/{name}/unique_installs_badge.json")]
|
|
public async Task<IActionResult> UniqueInstallsBadge(string name)
|
|
{
|
|
var results = await _sql.UniqueInstalls(name);
|
|
|
|
Response.ContentType = "application/json";
|
|
|
|
return Ok(results == 0
|
|
? new Badge($"Modlist {name} not found!", "Error") {color = "red"}
|
|
: new Badge("Installations: ", "____"){color = "green"}) ;
|
|
}
|
|
|
|
private static readonly Func<object, string> ReportTemplate = NettleEngine.GetCompiler().Compile(@"
|
|
<html><body>
|
|
<h2>Tar Report for {{$.key}}</h2>
|
|
<h3>Ban Status: {{$.status}}</h3>
|
|
<table>
|
|
{{each $.log }}
|
|
<tr>
|
|
<td>{{$.Timestamp}}</td>
|
|
<td>{{$.Path}}</td>
|
|
<td>{{$.Key}}</td>
|
|
</tr>
|
|
{{/each}}
|
|
</table>
|
|
</body></html>
|
|
");
|
|
|
|
[HttpGet]
|
|
[Route("tarlog/{key}")]
|
|
public async Task<IActionResult> TarLog(string key)
|
|
{
|
|
var isTarKey = await _sql.IsTarKey(key);
|
|
|
|
List<(DateTime, string, string)> report = new List<(DateTime, string, string)>();
|
|
|
|
if (isTarKey) report = await _sql.FullTarReport(key);
|
|
|
|
var response = ReportTemplate(new
|
|
{
|
|
key = key,
|
|
status = isTarKey ? "BANNED" : "NOT BANNED",
|
|
log = report.Select(entry => new
|
|
{
|
|
Timestamp = entry.Item1,
|
|
Path = entry.Item2,
|
|
Key = entry.Item3
|
|
}).ToList()
|
|
});
|
|
return new ContentResult
|
|
{
|
|
ContentType = "text/html",
|
|
StatusCode = (int) HttpStatusCode.OK,
|
|
Content = response
|
|
};
|
|
|
|
}
|
|
|
|
private async Task Log(DateTime timestamp, string action, string subject, string metricsKey = null)
|
|
{
|
|
//_logger.Log(LogLevel.Information, $"Log - {timestamp} {action} {subject} {metricsKey}");
|
|
await _sql.IngestMetric(new Metric
|
|
{
|
|
Timestamp = timestamp, Action = action, Subject = subject, MetricsKey = metricsKey
|
|
});
|
|
}
|
|
|
|
public class Result
|
|
{
|
|
public DateTime Timestamp { get; set; }
|
|
}
|
|
|
|
class TotalListTemplateData
|
|
{
|
|
public string Title { get; set; }
|
|
public long Total { get; set; }
|
|
public Item[] Items { get; set; }
|
|
|
|
public class Item
|
|
{
|
|
public long Count { get; set; }
|
|
public string Title { get; set; }
|
|
}
|
|
}
|
|
|
|
private static Func<object, string> _totalListTemplate;
|
|
|
|
|
|
private static Func<object, string> TotalListTemplate
|
|
{
|
|
get
|
|
{
|
|
if (_totalListTemplate == null)
|
|
{
|
|
var resource = Assembly.GetExecutingAssembly()
|
|
.GetManifestResourceStream("Wabbajack.Server.Controllers.Templates.TotalListTemplate.html")!
|
|
.ReadAll();
|
|
_totalListTemplate = NettleEngine.GetCompiler().Compile(Encoding.UTF8.GetString(resource));
|
|
}
|
|
|
|
return _totalListTemplate;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
[HttpGet("total_installs.html")]
|
|
[ResponseCache(Duration = 60 * 60)]
|
|
public async Task<ContentResult> TotalInstalls()
|
|
{
|
|
var data = await _sql.GetTotalInstalls();
|
|
var result = TotalListTemplate(new TotalListTemplateData
|
|
{
|
|
Title = "Total Installs",
|
|
Total = data.Sum(d => d.Item2),
|
|
Items = data.Select(d => new TotalListTemplateData.Item {Title = d.Item1, Count = d.Item2})
|
|
.ToArray()
|
|
});
|
|
return new ContentResult {
|
|
ContentType = "text/html",
|
|
StatusCode = (int)HttpStatusCode.OK,
|
|
Content = result};
|
|
}
|
|
|
|
[HttpGet("total_unique_installs.html")]
|
|
[ResponseCache(Duration = 60 * 60)]
|
|
public async Task<ContentResult> TotalUniqueInstalls()
|
|
{
|
|
var data = await _sql.GetTotalUniqueInstalls();
|
|
var result = TotalListTemplate(new TotalListTemplateData
|
|
{
|
|
Title = "Total Unique Installs",
|
|
Total = data.Sum(d => d.Item2),
|
|
Items = data.Select(d => new TotalListTemplateData.Item {Title = d.Item1, Count = d.Item2})
|
|
.ToArray()
|
|
});
|
|
return new ContentResult {
|
|
ContentType = "text/html",
|
|
StatusCode = (int)HttpStatusCode.OK,
|
|
Content = result};
|
|
}
|
|
|
|
[HttpGet("dump.json")]
|
|
public async Task<IActionResult> DataDump()
|
|
{
|
|
return Ok(await _sql.MetricsDump().ToArrayAsync());
|
|
}
|
|
|
|
}
|
|
}
|