diff --git a/SharedLibraryCore/Dtos/ClientHistoryInfo.cs b/SharedLibraryCore/Dtos/ClientHistoryInfo.cs index 876be62f5..cf764219e 100644 --- a/SharedLibraryCore/Dtos/ClientHistoryInfo.cs +++ b/SharedLibraryCore/Dtos/ClientHistoryInfo.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Text.Json.Serialization; namespace SharedLibraryCore.Dtos { @@ -11,11 +12,17 @@ namespace SharedLibraryCore.Dtos public class ClientCountSnapshot { + [JsonIgnore] public DateTime Time { get; set; } + [JsonPropertyName("ts")] public string TimeString => Time.ToString("yyyy-MM-ddTHH:mm:ssZ"); + [JsonPropertyName("cc")] public int ClientCount { get; set; } + [JsonPropertyName("ci")] public bool ConnectionInterrupted { get;set; } + [JsonIgnore] public string Map { get; set; } + [JsonPropertyName("ma")] public string MapAlias { get; set; } } } diff --git a/WebfrontCore/Controllers/API/Server.cs b/WebfrontCore/Controllers/API/Server.cs index 66ca820aa..023274fbd 100644 --- a/WebfrontCore/Controllers/API/Server.cs +++ b/WebfrontCore/Controllers/API/Server.cs @@ -1,8 +1,12 @@ using System; +using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using SharedLibraryCore; +using SharedLibraryCore.Configuration; +using SharedLibraryCore.Dtos; using SharedLibraryCore.Interfaces; using WebfrontCore.Controllers.API.Models; @@ -12,9 +16,14 @@ namespace WebfrontCore.Controllers.API [Route("api/[controller]")] public class Server : BaseController { - - public Server(IManager manager) : base(manager) + private readonly IServerDataViewer _serverDataViewer; + private readonly ApplicationConfiguration _applicationConfiguration; + + public Server(IManager manager, IServerDataViewer serverDataViewer, + ApplicationConfiguration applicationConfiguration) : base(manager) { + _serverDataViewer = serverDataViewer; + _applicationConfiguration = applicationConfiguration; } [HttpGet] @@ -110,5 +119,48 @@ namespace WebfrontCore.Controllers.API completedEvent.Output }); } + + [HttpGet("{id}/history")] + public async Task GetClientHistory(string id) + { + var foundServer = Manager.GetServers().FirstOrDefault(server => server.Id == id); + + if (foundServer == null) + { + return new NotFoundResult(); + } + + var clientHistory = (await _serverDataViewer.ClientHistoryAsync(_applicationConfiguration.MaxClientHistoryTime, + CancellationToken.None))? + .FirstOrDefault(history => history.ServerId == foundServer.LegacyDatabaseId) ?? + new ClientHistoryInfo + { + ServerId = foundServer.LegacyDatabaseId, + ClientCounts = new List() + }; + + var counts = clientHistory.ClientCounts?.AsEnumerable() ?? Enumerable.Empty(); + + if (foundServer.ClientHistory.ClientCounts.Any()) + { + counts = counts.Union(foundServer.ClientHistory.ClientCounts.Where(history => + history.Time > (clientHistory.ClientCounts?.LastOrDefault()?.Time ?? DateTime.MinValue))) + .Where(history => history.Time >= DateTime.UtcNow - _applicationConfiguration.MaxClientHistoryTime); + } + + if (ViewBag.Maps?.Count == 0) + { + return Json(counts.ToList()); + } + + var clientCountSnapshots = counts.ToList(); + foreach (var count in clientCountSnapshots) + { + count.MapAlias = foundServer.Maps.FirstOrDefault(map => map.Name == count.Map)?.Alias ?? + count.Map; + } + + return Json(clientCountSnapshots); + } } } diff --git a/WebfrontCore/ViewComponents/ServerListViewComponent.cs b/WebfrontCore/ViewComponents/ServerListViewComponent.cs index aac16b78e..94970cc5b 100644 --- a/WebfrontCore/ViewComponents/ServerListViewComponent.cs +++ b/WebfrontCore/ViewComponents/ServerListViewComponent.cs @@ -1,29 +1,21 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using SharedLibraryCore; using SharedLibraryCore.Dtos; using System.Linq; -using System.Threading; using Data.Models; using Data.Models.Client.Stats; using IW4MAdmin.Plugins.Stats.Helpers; using SharedLibraryCore.Configuration; -using SharedLibraryCore.Interfaces; namespace WebfrontCore.ViewComponents { public class ServerListViewComponent : ViewComponent { - private readonly IServerDataViewer _serverDataViewer; - private readonly ApplicationConfiguration _appConfig; private readonly DefaultSettings _defaultSettings; - public ServerListViewComponent(IServerDataViewer serverDataViewer, - ApplicationConfiguration applicationConfiguration, DefaultSettings defaultSettings) + public ServerListViewComponent(DefaultSettings defaultSettings) { - _serverDataViewer = serverDataViewer; - _appConfig = applicationConfiguration; _defaultSettings = defaultSettings; } @@ -46,25 +38,6 @@ namespace WebfrontCore.ViewComponents foreach (var server in servers) { - var serverId = server.GetIdForServer().Result; - var clientHistory = _serverDataViewer.ClientHistoryAsync(_appConfig.MaxClientHistoryTime, - CancellationToken.None).Result? - .FirstOrDefault(history => history.ServerId == serverId) ?? - new ClientHistoryInfo - { - ServerId = serverId, - ClientCounts = new List() - }; - - var counts = clientHistory.ClientCounts?.AsEnumerable() ?? Enumerable.Empty(); - - if (server.ClientHistory.ClientCounts.Any()) - { - counts = counts.Union(server.ClientHistory.ClientCounts.Where(history => - history.Time > (clientHistory.ClientCounts?.LastOrDefault()?.Time ?? DateTime.MinValue))) - .Where(history => history.Time >= DateTime.UtcNow - _appConfig.MaxClientHistoryTime); - } - serverInfo.Add(new ServerInfo { Name = server.Hostname, @@ -76,11 +49,7 @@ namespace WebfrontCore.ViewComponents MaxClients = server.MaxClients, PrivateClientSlots = server.PrivateClientSlots, GameType = server.GametypeName, - ClientHistory = new ClientHistoryInfo - { - ServerId = server.EndPoint, - ClientCounts = counts.ToList() - }, + ClientHistory = new ClientHistoryInfo(), Players = server.GetClientsAsList() .Select(client => new PlayerInfo { diff --git a/WebfrontCore/Views/Server/_Server.cshtml b/WebfrontCore/Views/Server/_Server.cshtml index 77674ab25..3ee7d02fe 100644 --- a/WebfrontCore/Views/Server/_Server.cshtml +++ b/WebfrontCore/Views/Server/_Server.cshtml @@ -82,8 +82,7 @@ }
-
diff --git a/WebfrontCore/wwwroot/js/server.js b/WebfrontCore/wwwroot/js/server.js index a60db1d26..c7cace248 100644 --- a/WebfrontCore/wwwroot/js/server.js +++ b/WebfrontCore/wwwroot/js/server.js @@ -27,25 +27,25 @@ function getPlayerHistoryChart(playerHistory, i, width, maxClients) { let lastMap = ''; playerHistory.forEach((elem, i) => { - if (elem.map !== lastMap) { + if (elem.ma !== lastMap) { mapChange.push(i); - lastMap = elem.map; + lastMap = elem; } if (elem.connectionInterrupted) { offlineTime.push({ clientCount: maxClients, - timeString: elem.timeString + timeString: elem.ts }); onlineTime.push({ clientCount: 0, - timeString: elem.timeString + timeString: elem.ts }) } else { offlineTime.push({ clientCount: 0, - timeString: elem.timeString + timeString: elem.ts }); onlineTime.push(elem) @@ -60,9 +60,9 @@ function getPlayerHistoryChart(playerHistory, i, width, maxClients) { return new Chart(document.getElementById(`server_history_canvas_${i}`), { type: 'line', data: { - labels: playerHistory.map(history => history.timeString), + labels: playerHistory.map(history => history.ts), datasets: [{ - data: onlineTime.map(history => history.clientCount), + data: onlineTime.map(history => history.cc), backgroundColor: fillColor, borderColor: primaryColor, borderWidth: 2, @@ -70,7 +70,7 @@ function getPlayerHistoryChart(playerHistory, i, width, maxClients) { hoverBorderWidth: 2 }, { - data: offlineTime.map(history => history.clientCount), + data: offlineTime.map(history => history.cc), backgroundColor: createDiagonalPattern(offlineFillColor), borderColor: offlineFillColor, borderWidth: 2, @@ -88,7 +88,7 @@ function getPlayerHistoryChart(playerHistory, i, width, maxClients) { callbacks: { // todo: localization at some point title: context => moment(context[0].label).local().calendar(), - label: context => context.datasetIndex !== 1 ? `${context.value} ${_localization['WEBFRONT_SCRIPT_SERVER_PLAYERS']} | ${playerHistory[context.index].mapAlias}` : context.value === '0' ? '' : _localization['WEBFRONT_SCRIPT_SERVER_UNREACHABLE'], + label: context => context.datasetIndex !== 1 ? `${context.value} ${_localization['WEBFRONT_SCRIPT_SERVER_PLAYERS']} | ${playerHistory[context.index].ma}` : context.value === '0' ? '' : _localization['WEBFRONT_SCRIPT_SERVER_UNREACHABLE'], }, mode: 'nearest', intersect: false, @@ -153,13 +153,14 @@ $(document).ready(function () { $(this).parent().parent().find('.server-header-ip-address').show(); }); - $('.server-history-row').each(function (index, element) { - let clientHistory = $(this).data('clienthistory-ex'); + $('.server-history-row').each(async function (index, element) { const serverId = $(this).data('serverid'); + const serverEp = $(this).data('server-endpoint'); setInterval(() => refreshClientActivity(serverId), 2000 + (index * 100)); let maxClients = parseInt($('#server_header_' + serverId + ' .server-maxclients').text()); let width = $('.server-header').first().width(); - getPlayerHistoryChart(clientHistory, serverId, width, maxClients); + const clientHistory = await fetch(`/api/server/${serverEp}/history`); + getPlayerHistoryChart(await clientHistory.json(), serverId, width, maxClients); }); $('.moment-date').each((index, element) => {