using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Nettle; using Wabbajack.Common.StatusFeed; using Wabbajack.Server; using Wabbajack.Server.DataLayer; using Wabbajack.Server.DTOs; using Wabbajack.Server.Services; namespace Wabbajack.BuildServer.Controllers { [Route("/heartbeat")] public class Heartbeat : ControllerBase { static Heartbeat() { _startTime = DateTime.Now; } private static DateTime _startTime; private QuickSync _quickSync; private ListValidator _listValidator; public Heartbeat(ILogger logger, SqlService sql, GlobalInformation globalInformation, QuickSync quickSync, ListValidator listValidator) { _globalInformation = globalInformation; _sql = sql; _logger = logger; _quickSync = quickSync; _listValidator = listValidator; } private const int MAX_LOG_SIZE = 128; private static List Log = new List(); private GlobalInformation _globalInformation; private SqlService _sql; private ILogger _logger; public static void AddToLog(IStatusMessage msg) { lock (Log) { Log.Add(msg.ToString()); if (Log.Count > MAX_LOG_SIZE) Log.RemoveAt(0); } } [HttpGet] public async Task GetHeartbeat() { return Ok(new HeartbeatResult { Uptime = DateTime.Now - _startTime, LastNexusUpdate = _globalInformation.TimeSinceLastNexusSync, }); } private static readonly Func HandleGetReport = NettleEngine.GetCompiler().Compile(@"

Server Status

Service Overview ({{services.Length}}):

Lists ({{lists.Length}}):

    {{each $.lists }}
  • {{$.Name}} - {{$.Time}}
  • {{/each}}
"); [HttpGet("report")] public async Task Report() { var response = HandleGetReport(new { services = (await _quickSync.Report()) .Select(s => new {Name = s.Key.Name, Time = s.Value.LastRunTime, MaxTime = s.Value.Delay, IsLate = s.Value.LastRunTime > s.Value.Delay}) .OrderBy(s => s.Name) .ToArray(), lists = _listValidator.ValidationInfo.Select(s => new {Name = s.Key, Time = s.Value.ValidationTime}) .OrderBy(l => l.Name) .ToArray() }); return new ContentResult { ContentType = "text/html", StatusCode = (int) HttpStatusCode.OK, Content = response }; } private static readonly Func HandleGetServiceReport = NettleEngine.GetCompiler().Compile(@"

Service Status: {{Name}} {{TimeSinceLastRun}}

Service Overview ({{ActiveWorkQueue.Length}}):

    {{each $.ActiveWorkQueue }}
  • {{$.Name}} {{$.Time}}
  • {{/each}}
"); [HttpGet("report/services/{serviceName}.html")] public async Task ReportServiceStatus(string serviceName) { var services = await _quickSync.Report(); var info = services.First(kvp => kvp.Key.Name == serviceName); var response = HandleGetServiceReport(new { Name = info.Key.Name, TimeSinceLastRun = DateTime.UtcNow - info.Value.LastRunTime, ActiveWorkQueue = info.Value.ActiveWork.Select(p => new { Name = p.Item1, Time = DateTime.UtcNow - p.Item2 }).OrderByDescending(kp => kp.Time) .ToArray() }); return new ContentResult { ContentType = "text/html", StatusCode = (int) HttpStatusCode.OK, Content = response }; } } }