update top level client count stats to support filtering per game
This commit is contained in:
parent
c53e0de7d0
commit
92992dfb13
@ -4,6 +4,7 @@ using System.Linq;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Data.Abstractions;
|
using Data.Abstractions;
|
||||||
|
using Data.Models;
|
||||||
using Data.Models.Client;
|
using Data.Models.Client;
|
||||||
using Data.Models.Client.Stats;
|
using Data.Models.Client.Stats;
|
||||||
using Data.Models.Server;
|
using Data.Models.Server;
|
||||||
@ -40,11 +41,20 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async Task<(int?, DateTime?)>
|
public async Task<(int?, DateTime?)>
|
||||||
MaxConcurrentClientsAsync(long? serverId = null, TimeSpan? overPeriod = null,
|
MaxConcurrentClientsAsync(long? serverId = null, Reference.Game? gameCode = null, TimeSpan? overPeriod = null,
|
||||||
CancellationToken token = default)
|
CancellationToken token = default)
|
||||||
{
|
{
|
||||||
_snapshotCache.SetCacheItem(async (snapshots, cancellationToken) =>
|
_snapshotCache.SetCacheItem(async (snapshots, ids, cancellationToken) =>
|
||||||
{
|
{
|
||||||
|
Reference.Game? game = null;
|
||||||
|
long? id = null;
|
||||||
|
|
||||||
|
if (ids.Any())
|
||||||
|
{
|
||||||
|
game = (Reference.Game?)ids.First();
|
||||||
|
id = (long?)ids.Last();
|
||||||
|
}
|
||||||
|
|
||||||
var oldestEntry = overPeriod.HasValue
|
var oldestEntry = overPeriod.HasValue
|
||||||
? DateTime.UtcNow - overPeriod.Value
|
? DateTime.UtcNow - overPeriod.Value
|
||||||
: DateTime.UtcNow.AddDays(-1);
|
: DateTime.UtcNow.AddDays(-1);
|
||||||
@ -52,9 +62,10 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
int? maxClients;
|
int? maxClients;
|
||||||
DateTime? maxClientsTime;
|
DateTime? maxClientsTime;
|
||||||
|
|
||||||
if (serverId != null)
|
if (id != null)
|
||||||
{
|
{
|
||||||
var clients = await snapshots.Where(snapshot => snapshot.ServerId == serverId)
|
var clients = await snapshots.Where(snapshot => snapshot.ServerId == id)
|
||||||
|
.Where(snapshot => game == null || snapshot.Server.GameName == game)
|
||||||
.Where(snapshot => snapshot.CapturedAt >= oldestEntry)
|
.Where(snapshot => snapshot.CapturedAt >= oldestEntry)
|
||||||
.OrderByDescending(snapshot => snapshot.ClientCount)
|
.OrderByDescending(snapshot => snapshot.ClientCount)
|
||||||
.Select(snapshot => new
|
.Select(snapshot => new
|
||||||
@ -71,11 +82,12 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var clients = await snapshots.Where(snapshot => snapshot.CapturedAt >= oldestEntry)
|
var clients = await snapshots.Where(snapshot => snapshot.CapturedAt >= oldestEntry)
|
||||||
|
.Where(snapshot => game == null || snapshot.Server.GameName == game)
|
||||||
.GroupBy(snapshot => snapshot.PeriodBlock)
|
.GroupBy(snapshot => snapshot.PeriodBlock)
|
||||||
.Select(grp => new
|
.Select(grp => new
|
||||||
{
|
{
|
||||||
ClientCount = grp.Sum(snapshot => (int?) snapshot.ClientCount),
|
ClientCount = grp.Sum(snapshot => (int?)snapshot.ClientCount),
|
||||||
Time = grp.Max(snapshot => (DateTime?) snapshot.CapturedAt)
|
Time = grp.Max(snapshot => (DateTime?)snapshot.CapturedAt)
|
||||||
})
|
})
|
||||||
.OrderByDescending(snapshot => snapshot.ClientCount)
|
.OrderByDescending(snapshot => snapshot.ClientCount)
|
||||||
.FirstOrDefaultAsync(cancellationToken);
|
.FirstOrDefaultAsync(cancellationToken);
|
||||||
@ -87,11 +99,12 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
_logger.LogDebug("Max concurrent clients since {Start} is {Clients}", oldestEntry, maxClients);
|
_logger.LogDebug("Max concurrent clients since {Start} is {Clients}", oldestEntry, maxClients);
|
||||||
|
|
||||||
return (maxClients, maxClientsTime);
|
return (maxClients, maxClientsTime);
|
||||||
}, nameof(MaxConcurrentClientsAsync), _cacheTimeSpan, true);
|
}, nameof(MaxConcurrentClientsAsync), new object[] { gameCode, serverId }, _cacheTimeSpan, true);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return await _snapshotCache.GetCacheItem(nameof(MaxConcurrentClientsAsync), token);
|
return await _snapshotCache.GetCacheItem(nameof(MaxConcurrentClientsAsync),
|
||||||
|
new object[] { gameCode, serverId }, token);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -100,22 +113,30 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<(int, int)> ClientCountsAsync(TimeSpan? overPeriod = null, CancellationToken token = default)
|
public async Task<(int, int)> ClientCountsAsync(TimeSpan? overPeriod = null, Reference.Game? gameCode = null, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
_serverStatsCache.SetCacheItem(async (set, cancellationToken) =>
|
_serverStatsCache.SetCacheItem(async (set, ids, cancellationToken) =>
|
||||||
{
|
{
|
||||||
var count = await set.CountAsync(cancellationToken);
|
Reference.Game? game = null;
|
||||||
|
|
||||||
|
if (ids.Any())
|
||||||
|
{
|
||||||
|
game = (Reference.Game?)ids.First();
|
||||||
|
}
|
||||||
|
|
||||||
|
var count = await set.CountAsync(item => game == null || item.GameName == game,
|
||||||
|
cancellationToken);
|
||||||
var startOfPeriod =
|
var startOfPeriod =
|
||||||
DateTime.UtcNow.AddHours(-overPeriod?.TotalHours ?? -24);
|
DateTime.UtcNow.AddHours(-overPeriod?.TotalHours ?? -24);
|
||||||
var recentCount = await set.CountAsync(client => client.LastConnection >= startOfPeriod,
|
var recentCount = await set.CountAsync(client => (game == null || client.GameName == game) && client.LastConnection >= startOfPeriod,
|
||||||
cancellationToken);
|
cancellationToken);
|
||||||
|
|
||||||
return (count, recentCount);
|
return (count, recentCount);
|
||||||
}, nameof(_serverStatsCache), _cacheTimeSpan, true);
|
}, nameof(_serverStatsCache), new object[] { gameCode }, _cacheTimeSpan, true);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return await _serverStatsCache.GetCacheItem(nameof(_serverStatsCache), token);
|
return await _serverStatsCache.GetCacheItem(nameof(_serverStatsCache), new object[] { gameCode }, token);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -166,21 +187,28 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
|
|
||||||
public async Task<int> RankedClientsCountAsync(long? serverId = null, CancellationToken token = default)
|
public async Task<int> RankedClientsCountAsync(long? serverId = null, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
_rankedClientsCache.SetCacheItem(async (set, cancellationToken) =>
|
_rankedClientsCache.SetCacheItem((set, ids, cancellationToken) =>
|
||||||
{
|
{
|
||||||
|
long? id = null;
|
||||||
|
|
||||||
|
if (ids.Any())
|
||||||
|
{
|
||||||
|
id = (long?)ids.First();
|
||||||
|
}
|
||||||
|
|
||||||
var fifteenDaysAgo = DateTime.UtcNow.AddDays(-15);
|
var fifteenDaysAgo = DateTime.UtcNow.AddDays(-15);
|
||||||
return await set
|
return set
|
||||||
.Where(rating => rating.Newest)
|
.Where(rating => rating.Newest)
|
||||||
.Where(rating => rating.ServerId == serverId)
|
.Where(rating => rating.ServerId == id)
|
||||||
.Where(rating => rating.CreatedDateTime >= fifteenDaysAgo)
|
.Where(rating => rating.CreatedDateTime >= fifteenDaysAgo)
|
||||||
.Where(rating => rating.Client.Level != EFClient.Permission.Banned)
|
.Where(rating => rating.Client.Level != EFClient.Permission.Banned)
|
||||||
.Where(rating => rating.Ranking != null)
|
.Where(rating => rating.Ranking != null)
|
||||||
.CountAsync(cancellationToken);
|
.CountAsync(cancellationToken);
|
||||||
}, nameof(_rankedClientsCache), serverId is null ? null: new[] { (object)serverId }, _cacheTimeSpan);
|
}, nameof(_rankedClientsCache), new object[] { serverId }, _cacheTimeSpan);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return await _rankedClientsCache.GetCacheItem(nameof(_rankedClientsCache), serverId, token);
|
return await _rankedClientsCache.GetCacheItem(nameof(_rankedClientsCache), new object[] { serverId }, token);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -11,10 +11,11 @@ namespace Data.Abstractions
|
|||||||
void SetCacheItem(Func<DbSet<TEntityType>, CancellationToken, Task<TReturnType>> itemGetter, string keyName,
|
void SetCacheItem(Func<DbSet<TEntityType>, CancellationToken, Task<TReturnType>> itemGetter, string keyName,
|
||||||
TimeSpan? expirationTime = null, bool autoRefresh = false);
|
TimeSpan? expirationTime = null, bool autoRefresh = false);
|
||||||
|
|
||||||
void SetCacheItem(Func<DbSet<TEntityType>, CancellationToken, Task<TReturnType>> itemGetter, string keyName,
|
void SetCacheItem(Func<DbSet<TEntityType>, IEnumerable<object>, CancellationToken, Task<TReturnType>> itemGetter, string keyName,
|
||||||
IEnumerable<object> ids = null, TimeSpan? expirationTime = null, bool autoRefresh = false);
|
IEnumerable<object> ids = null, TimeSpan? expirationTime = null, bool autoRefresh = false);
|
||||||
|
|
||||||
Task<TReturnType> GetCacheItem(string keyName, CancellationToken token = default);
|
Task<TReturnType> GetCacheItem(string keyName, CancellationToken token = default);
|
||||||
Task<TReturnType> GetCacheItem(string keyName, object id = null, CancellationToken token = default);
|
|
||||||
|
Task<TReturnType> GetCacheItem(string keyName, IEnumerable<object> ids = null, CancellationToken token = default);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ namespace Data.Helpers
|
|||||||
private readonly IDatabaseContextFactory _contextFactory;
|
private readonly IDatabaseContextFactory _contextFactory;
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<string, Dictionary<object, CacheState<TReturnType>>> _cacheStates = new();
|
private readonly ConcurrentDictionary<string, Dictionary<object, CacheState<TReturnType>>> _cacheStates = new();
|
||||||
private readonly object _defaultKey = new();
|
private readonly string _defaultKey = null;
|
||||||
|
|
||||||
private bool _autoRefresh;
|
private bool _autoRefresh;
|
||||||
private const int DefaultExpireMinutes = 15;
|
private const int DefaultExpireMinutes = 15;
|
||||||
@ -29,7 +29,7 @@ namespace Data.Helpers
|
|||||||
public string Key { get; set; }
|
public string Key { get; set; }
|
||||||
public DateTime LastRetrieval { get; set; }
|
public DateTime LastRetrieval { get; set; }
|
||||||
public TimeSpan ExpirationTime { get; set; }
|
public TimeSpan ExpirationTime { get; set; }
|
||||||
public Func<DbSet<TEntityType>, CancellationToken, Task<TCacheType>> Getter { get; set; }
|
public Func<DbSet<TEntityType>, IEnumerable<object>, CancellationToken, Task<TCacheType>> Getter { get; set; }
|
||||||
public TCacheType Value { get; set; }
|
public TCacheType Value { get; set; }
|
||||||
public bool IsSet { get; set; }
|
public bool IsSet { get; set; }
|
||||||
|
|
||||||
@ -53,10 +53,10 @@ namespace Data.Helpers
|
|||||||
public void SetCacheItem(Func<DbSet<TEntityType>, CancellationToken, Task<TReturnType>> getter, string key,
|
public void SetCacheItem(Func<DbSet<TEntityType>, CancellationToken, Task<TReturnType>> getter, string key,
|
||||||
TimeSpan? expirationTime = null, bool autoRefresh = false)
|
TimeSpan? expirationTime = null, bool autoRefresh = false)
|
||||||
{
|
{
|
||||||
SetCacheItem(getter, key, null, expirationTime, autoRefresh);
|
SetCacheItem((set, _, token) => getter(set, token), key, null, expirationTime, autoRefresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetCacheItem(Func<DbSet<TEntityType>, CancellationToken, Task<TReturnType>> getter, string key,
|
public void SetCacheItem(Func<DbSet<TEntityType>, IEnumerable<object>, CancellationToken, Task<TReturnType>> getter, string key,
|
||||||
IEnumerable<object> ids = null, TimeSpan? expirationTime = null, bool autoRefresh = false)
|
IEnumerable<object> ids = null, TimeSpan? expirationTime = null, bool autoRefresh = false)
|
||||||
{
|
{
|
||||||
ids ??= new[] { _defaultKey };
|
ids ??= new[] { _defaultKey };
|
||||||
@ -66,15 +66,14 @@ namespace Data.Helpers
|
|||||||
_cacheStates.TryAdd(key, new Dictionary<object, CacheState<TReturnType>>());
|
_cacheStates.TryAdd(key, new Dictionary<object, CacheState<TReturnType>>());
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var id in ids)
|
|
||||||
{
|
|
||||||
var cacheInstance = _cacheStates[key];
|
var cacheInstance = _cacheStates[key];
|
||||||
|
var id = GenerateKeyFromIds(ids);
|
||||||
|
|
||||||
lock (_cacheStates)
|
lock (_cacheStates)
|
||||||
{
|
{
|
||||||
if (cacheInstance.ContainsKey(id))
|
if (cacheInstance.ContainsKey(id))
|
||||||
{
|
{
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,15 +97,14 @@ namespace Data.Helpers
|
|||||||
}
|
}
|
||||||
|
|
||||||
_timer = new Timer(state.ExpirationTime.TotalMilliseconds);
|
_timer = new Timer(state.ExpirationTime.TotalMilliseconds);
|
||||||
_timer.Elapsed += async (sender, args) => await RunCacheUpdate(state, CancellationToken.None);
|
_timer.Elapsed += async (sender, args) => await RunCacheUpdate(state, ids, CancellationToken.None);
|
||||||
_timer.Start();
|
_timer.Start();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public Task<TReturnType> GetCacheItem(string keyName, CancellationToken cancellationToken = default) =>
|
public Task<TReturnType> GetCacheItem(string keyName, CancellationToken cancellationToken = default) =>
|
||||||
GetCacheItem(keyName, null, cancellationToken);
|
GetCacheItem(keyName, null, cancellationToken);
|
||||||
|
|
||||||
public async Task<TReturnType> GetCacheItem(string keyName, object id = null,
|
public async Task<TReturnType> GetCacheItem(string keyName, IEnumerable<object> ids = null,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
if (!_cacheStates.ContainsKey(keyName))
|
if (!_cacheStates.ContainsKey(keyName))
|
||||||
@ -120,27 +118,27 @@ namespace Data.Helpers
|
|||||||
|
|
||||||
lock (_cacheStates)
|
lock (_cacheStates)
|
||||||
{
|
{
|
||||||
state = id is null ? cacheInstance.Values.First() : _cacheStates[keyName][id];
|
state = ids is null ? cacheInstance.Values.First() : _cacheStates[keyName][GenerateKeyFromIds(ids)];
|
||||||
}
|
}
|
||||||
|
|
||||||
// when auto refresh is off we want to check the expiration and value
|
// when auto refresh is off we want to check the expiration and value
|
||||||
// when auto refresh is on, we want to only check the value, because it'll be refreshed automatically
|
// when auto refresh is on, we want to only check the value, because it'll be refreshed automatically
|
||||||
if ((state.IsExpired || !state.IsSet) && !_autoRefresh || _autoRefresh && !state.IsSet)
|
if ((state.IsExpired || !state.IsSet) && !_autoRefresh || _autoRefresh && !state.IsSet)
|
||||||
{
|
{
|
||||||
await RunCacheUpdate(state, cancellationToken);
|
await RunCacheUpdate(state, ids, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.Value;
|
return state.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RunCacheUpdate(CacheState<TReturnType> state, CancellationToken token)
|
private async Task RunCacheUpdate(CacheState<TReturnType> state, IEnumerable<object> ids, CancellationToken token)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Running update for {ClassName} {@State}", GetType().Name, state);
|
_logger.LogDebug("Running update for {ClassName} {@State}", GetType().Name, state);
|
||||||
await using var context = _contextFactory.CreateContext(false);
|
await using var context = _contextFactory.CreateContext(false);
|
||||||
var set = context.Set<TEntityType>();
|
var set = context.Set<TEntityType>();
|
||||||
var value = await state.Getter(set, token);
|
var value = await state.Getter(set, ids, token);
|
||||||
state.Value = value;
|
state.Value = value;
|
||||||
state.IsSet = true;
|
state.IsSet = true;
|
||||||
state.LastRetrieval = DateTime.Now;
|
state.LastRetrieval = DateTime.Now;
|
||||||
@ -150,5 +148,8 @@ namespace Data.Helpers
|
|||||||
_logger.LogError(ex, "Could not get cached value for {Key}", state.Key);
|
_logger.LogError(ex, "Could not get cached value for {Key}", state.Key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string GenerateKeyFromIds(IEnumerable<object> ids) =>
|
||||||
|
string.Join("_", ids.Select(id => id?.ToString() ?? "null"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using static SharedLibraryCore.Server;
|
using Data.Models;
|
||||||
|
|
||||||
namespace SharedLibraryCore.Dtos
|
namespace SharedLibraryCore.Dtos
|
||||||
{
|
{
|
||||||
@ -15,11 +15,11 @@ namespace SharedLibraryCore.Dtos
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// specifies the game name filter
|
/// specifies the game name filter
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Game? Game { get; set; }
|
public Reference.Game? Game { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// collection of unique game names being monitored
|
/// collection of unique game names being monitored
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Game[] ActiveServerGames { get; set; }
|
public Reference.Game[] ActiveServerGames { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Data.Models;
|
||||||
using SharedLibraryCore.Dtos;
|
using SharedLibraryCore.Dtos;
|
||||||
|
|
||||||
namespace SharedLibraryCore.Interfaces
|
namespace SharedLibraryCore.Interfaces
|
||||||
@ -15,19 +16,21 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
/// Retrieves the max concurrent clients over a give time period for all servers or given server id
|
/// Retrieves the max concurrent clients over a give time period for all servers or given server id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="serverId">ServerId to query on</param>
|
/// <param name="serverId">ServerId to query on</param>
|
||||||
|
/// <param name="gameCode"><see cref="Reference.Game"/></param>
|
||||||
/// <param name="overPeriod">how far in the past to search</param>
|
/// <param name="overPeriod">how far in the past to search</param>
|
||||||
/// <param name="token">CancellationToken</param>
|
/// <param name="token">CancellationToken</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<(int?, DateTime?)> MaxConcurrentClientsAsync(long? serverId = null, TimeSpan? overPeriod = null,
|
Task<(int?, DateTime?)> MaxConcurrentClientsAsync(long? serverId = null, Reference.Game? gameCode = null, TimeSpan? overPeriod = null,
|
||||||
CancellationToken token = default);
|
CancellationToken token = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the total number of clients connected and total clients connected in the given time frame
|
/// Gets the total number of clients connected and total clients connected in the given time frame
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="overPeriod">how far in the past to search</param>
|
/// <param name="overPeriod">how far in the past to search</param>
|
||||||
|
/// <param name="gameCode"><see cref="Reference.Game"/></param>
|
||||||
/// <param name="token">CancellationToken</param>
|
/// <param name="token">CancellationToken</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<(int, int)> ClientCountsAsync(TimeSpan? overPeriod = null, CancellationToken token = default);
|
Task<(int, int)> ClientCountsAsync(TimeSpan? overPeriod = null, Reference.Game? gameCode = null, CancellationToken token = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves the client count and history over the given period
|
/// Retrieves the client count and history over the given period
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Data.Models;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
@ -21,13 +22,13 @@ public class Info : BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<IActionResult> Get(int period = 24, CancellationToken token = default)
|
public async Task<IActionResult> Get(int period = 24, Reference.Game? game = null, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
// todo: this is hardcoded currently because the cache doesn't take into consideration the duration, so
|
// todo: this is hardcoded currently because the cache doesn't take into consideration the duration, so
|
||||||
// we could impact the webfront usage too
|
// we could impact the webfront usage too
|
||||||
var duration = TimeSpan.FromHours(24);
|
var duration = TimeSpan.FromHours(24);
|
||||||
var (totalClients, totalRecentClients) =
|
var (totalClients, totalRecentClients) =
|
||||||
await _serverDataViewer.ClientCountsAsync(duration, token);
|
await _serverDataViewer.ClientCountsAsync(duration, game, token);
|
||||||
var (maxConcurrent, maxConcurrentTime) = await _serverDataViewer.MaxConcurrentClientsAsync(overPeriod: duration, token: token);
|
var (maxConcurrent, maxConcurrentTime) = await _serverDataViewer.MaxConcurrentClientsAsync(overPeriod: duration, token: token);
|
||||||
var response = new InfoResponse
|
var response = new InfoResponse
|
||||||
{
|
{
|
||||||
|
@ -7,8 +7,8 @@ using SharedLibraryCore.Interfaces;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Data.Models;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using static SharedLibraryCore.Server;
|
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||||||
|
|
||||||
namespace WebfrontCore.Controllers
|
namespace WebfrontCore.Controllers
|
||||||
@ -27,26 +27,31 @@ namespace WebfrontCore.Controllers
|
|||||||
_serverDataViewer = serverDataViewer;
|
_serverDataViewer = serverDataViewer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IActionResult> Index(Game? game = null, CancellationToken cancellationToken = default)
|
public async Task<IActionResult> Index(Reference.Game? game = null,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
ViewBag.Description = Localization["WEBFRONT_DESCRIPTION_HOME"];
|
ViewBag.Description = Localization["WEBFRONT_DESCRIPTION_HOME"];
|
||||||
ViewBag.Title = Localization["WEBFRONT_HOME_TITLE"];
|
ViewBag.Title = Localization["WEBFRONT_HOME_TITLE"];
|
||||||
ViewBag.Keywords = Localization["WEBFRONT_KEWORDS_HOME"];
|
ViewBag.Keywords = Localization["WEBFRONT_KEWORDS_HOME"];
|
||||||
|
|
||||||
var servers = Manager.GetServers().Where(_server => !game.HasValue || _server.GameName == game);
|
var servers = Manager.GetServers().Where(server => game is null || server.GameName == (Server.Game?)game)
|
||||||
var (clientCount, time) = await _serverDataViewer.MaxConcurrentClientsAsync(token: cancellationToken);
|
.ToList();
|
||||||
var (count, recentCount) = await _serverDataViewer.ClientCountsAsync(token: cancellationToken);
|
var (clientCount, time) =
|
||||||
|
await _serverDataViewer.MaxConcurrentClientsAsync(gameCode: game, token: cancellationToken);
|
||||||
|
var (count, recentCount) =
|
||||||
|
await _serverDataViewer.ClientCountsAsync(gameCode: game, token: cancellationToken);
|
||||||
|
|
||||||
var model = new IW4MAdminInfo()
|
var model = new IW4MAdminInfo
|
||||||
{
|
{
|
||||||
TotalAvailableClientSlots = servers.Sum(_server => _server.MaxClients),
|
TotalAvailableClientSlots = servers.Sum(server => server.MaxClients),
|
||||||
TotalOccupiedClientSlots = servers.SelectMany(_server => _server.GetClientsAsList()).Count(),
|
TotalOccupiedClientSlots = servers.SelectMany(server => server.GetClientsAsList()).Count(),
|
||||||
TotalClientCount = count,
|
TotalClientCount = count,
|
||||||
RecentClientCount = recentCount,
|
RecentClientCount = recentCount,
|
||||||
MaxConcurrentClients = clientCount ?? 0,
|
MaxConcurrentClients = clientCount ?? 0,
|
||||||
MaxConcurrentClientsTime = time ?? DateTime.UtcNow,
|
MaxConcurrentClientsTime = time ?? DateTime.UtcNow,
|
||||||
Game = game,
|
Game = game,
|
||||||
ActiveServerGames = Manager.GetServers().Select(_server => _server.GameName).Distinct().ToArray()
|
ActiveServerGames = Manager.GetServers().Select(server => (Reference.Game)server.GameName).Distinct()
|
||||||
|
.ToArray()
|
||||||
};
|
};
|
||||||
|
|
||||||
return View(model);
|
return View(model);
|
||||||
|
@ -10,7 +10,6 @@ using Data.Models.Client.Stats;
|
|||||||
using IW4MAdmin.Plugins.Stats.Helpers;
|
using IW4MAdmin.Plugins.Stats.Helpers;
|
||||||
using SharedLibraryCore.Configuration;
|
using SharedLibraryCore.Configuration;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using static SharedLibraryCore.Server;
|
|
||||||
|
|
||||||
namespace WebfrontCore.ViewComponents
|
namespace WebfrontCore.ViewComponents
|
||||||
{
|
{
|
||||||
@ -28,19 +27,20 @@ namespace WebfrontCore.ViewComponents
|
|||||||
_defaultSettings = defaultSettings;
|
_defaultSettings = defaultSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IViewComponentResult Invoke(Game? game)
|
public IViewComponentResult Invoke(Reference.Game? game)
|
||||||
{
|
{
|
||||||
if (game.HasValue)
|
if (game.HasValue)
|
||||||
{
|
{
|
||||||
ViewBag.Maps = _defaultSettings.Maps.FirstOrDefault(map => map.Game == game)?.Maps.ToList() ??
|
ViewBag.Maps = _defaultSettings.Maps?.FirstOrDefault(map => map.Game == (Server.Game)game)?.Maps
|
||||||
new List<Map>();
|
?.ToList() ?? new List<Map>();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ViewBag.Maps = _defaultSettings.Maps.SelectMany(maps => maps.Maps).ToList();
|
ViewBag.Maps = _defaultSettings.Maps?.SelectMany(maps => maps.Maps).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
var servers = Program.Manager.GetServers().Where(server => !game.HasValue || server.GameName == game);
|
var servers = Program.Manager.GetServers()
|
||||||
|
.Where(server => game is null || server.GameName == (Server.Game)game);
|
||||||
|
|
||||||
var serverInfo = new List<ServerInfo>();
|
var serverInfo = new List<ServerInfo>();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user