From 2221c4e74915e8145866df7a841f1ee77024304c Mon Sep 17 00:00:00 2001 From: Chomp Date: Thu, 17 Jul 2025 12:54:40 +0100 Subject: [PATCH] Added early concept of a status page --- .../Models/Spt/Config/CoreConfig.cs | 6 ++ .../Services/PostDbLoadService.cs | 2 + .../SPTarkov.Server.Core/Status/StatusPage.cs | 59 +++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 Libraries/SPTarkov.Server.Core/Status/StatusPage.cs diff --git a/Libraries/SPTarkov.Server.Core/Models/Spt/Config/CoreConfig.cs b/Libraries/SPTarkov.Server.Core/Models/Spt/Config/CoreConfig.cs index 0118cbcc..51274b0f 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Spt/Config/CoreConfig.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Spt/Config/CoreConfig.cs @@ -56,6 +56,12 @@ public record CoreConfig : BaseConfig [JsonPropertyName("buildTime")] public string? BuildTime { get; set; } + /// + /// Timestamp of server start up + /// + [JsonPropertyName("serverStartTime")] + public long? ServerStartTime { get; set; } + /// /// Server locale keys that will be added to the bottom of the startup watermark /// diff --git a/Libraries/SPTarkov.Server.Core/Services/PostDbLoadService.cs b/Libraries/SPTarkov.Server.Core/Services/PostDbLoadService.cs index 822663a3..68a44588 100644 --- a/Libraries/SPTarkov.Server.Core/Services/PostDbLoadService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/PostDbLoadService.cs @@ -34,6 +34,8 @@ public class PostDbLoadService( public void PerformPostDbLoadActions() { + _coreConfig.ServerStartTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + // Regenerate base cache now mods are loaded and game is starting // Mods that add items and use the baseClass service generate the cache including their items, the next mod that // add items gets left out,causing warnings diff --git a/Libraries/SPTarkov.Server.Core/Status/StatusPage.cs b/Libraries/SPTarkov.Server.Core/Status/StatusPage.cs new file mode 100644 index 00000000..fe177891 --- /dev/null +++ b/Libraries/SPTarkov.Server.Core/Status/StatusPage.cs @@ -0,0 +1,59 @@ +using System.Text; +using SPTarkov.DI.Annotations; +using SPTarkov.Server.Core.Models.Spt.Config; +using SPTarkov.Server.Core.Servers; +using SPTarkov.Server.Core.Servers.Http; +using SPTarkov.Server.Core.Services; +using SPTarkov.Server.Core.Utils; + +namespace SPTarkov.Server.Core.Status +{ + [Injectable] + public class StatusPage( + TimeUtil timeUtil, + ProfileActivityService profileActivityService, + ConfigServer configServer + ) : IHttpListener + { + protected readonly CoreConfig _coreConfig = configServer.GetConfig(); + + public bool CanHandle(string sessionId, HttpRequest req) + { + return req.Method == "GET" && req.Path.Value.Contains("/status"); + } + + public async Task Handle(string sessionId, HttpRequest req, HttpResponse resp) + { + var sptVersion = $"SPT version: {ProgramStatics.SPT_VERSION()}"; + var debugEnabled = $"Debug enabled: {ProgramStatics.DEBUG()}"; + var modsEnabled = $"Mods enabled: {ProgramStatics.MODS()}"; + var timeStarted = + $"Started : {timeUtil.GetDateTimeFromTimeStamp(_coreConfig.ServerStartTime.Value)}"; + var uptime = + $"Uptime: {DateTimeOffset.UtcNow.ToUnixTimeSeconds() - _coreConfig.ServerStartTime} seconds".ToArray(); + var activeProfiles = profileActivityService.GetActiveProfileIdsWithinMinutes(30); + var activePlayerCount = + $"Profiles active in last 30 minutes: {activeProfiles.Count}. {string.Join(",", activeProfiles)}"; + + resp.StatusCode = 200; + resp.ContentType = "text/html"; + + await resp.Body.WriteAsync(Encoding.ASCII.GetBytes(sptVersion)); + await resp.Body.WriteAsync(Encoding.ASCII.GetBytes("
")); + await resp.Body.WriteAsync(Encoding.ASCII.GetBytes(debugEnabled)); + await resp.Body.WriteAsync(Encoding.ASCII.GetBytes("
")); + await resp.Body.WriteAsync(Encoding.ASCII.GetBytes(modsEnabled)); + await resp.Body.WriteAsync(Encoding.ASCII.GetBytes("
")); + + await resp.Body.WriteAsync(Encoding.ASCII.GetBytes(timeStarted)); + await resp.Body.WriteAsync(Encoding.ASCII.GetBytes("
")); + await resp.Body.WriteAsync(Encoding.ASCII.GetBytes(uptime)); + await resp.Body.WriteAsync(Encoding.ASCII.GetBytes("
")); + await resp.Body.WriteAsync(Encoding.ASCII.GetBytes(activePlayerCount)); + await resp.Body.WriteAsync(Encoding.ASCII.GetBytes("
")); + + await resp.StartAsync(); + await resp.CompleteAsync(); + } + } +}