2021-08-26 18:35:05 -04:00
|
|
|
|
using System;
|
2021-08-29 14:10:10 -04:00
|
|
|
|
using System.Collections.Generic;
|
2021-08-26 18:35:05 -04:00
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using Data.Abstractions;
|
|
|
|
|
using Data.Models.Client;
|
2022-06-09 10:56:41 -04:00
|
|
|
|
using Data.Models.Client.Stats;
|
2021-08-26 18:35:05 -04:00
|
|
|
|
using Data.Models.Server;
|
|
|
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
using SharedLibraryCore;
|
2021-08-29 14:10:10 -04:00
|
|
|
|
using SharedLibraryCore.Dtos;
|
2021-08-26 18:35:05 -04:00
|
|
|
|
using SharedLibraryCore.Interfaces;
|
|
|
|
|
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
|
|
|
|
|
|
|
|
namespace IW4MAdmin.Application.Misc
|
|
|
|
|
{
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
|
public class ServerDataViewer : IServerDataViewer
|
|
|
|
|
{
|
|
|
|
|
private readonly ILogger _logger;
|
2021-09-14 19:12:20 -04:00
|
|
|
|
private readonly IDataValueCache<EFServerSnapshot, (int?, DateTime?)> _snapshotCache;
|
2021-08-26 18:35:05 -04:00
|
|
|
|
private readonly IDataValueCache<EFClient, (int, int)> _serverStatsCache;
|
2021-08-29 14:10:10 -04:00
|
|
|
|
private readonly IDataValueCache<EFServerSnapshot, List<ClientHistoryInfo>> _clientHistoryCache;
|
2022-06-09 10:56:41 -04:00
|
|
|
|
private readonly IDataValueCache<EFClientRankingHistory, int> _rankedClientsCache;
|
2021-08-26 18:35:05 -04:00
|
|
|
|
|
|
|
|
|
private readonly TimeSpan? _cacheTimeSpan =
|
2021-11-15 11:25:55 -05:00
|
|
|
|
Utilities.IsDevelopment ? TimeSpan.FromSeconds(30) : (TimeSpan?) TimeSpan.FromMinutes(10);
|
2021-08-26 18:35:05 -04:00
|
|
|
|
|
2021-09-14 19:12:20 -04:00
|
|
|
|
public ServerDataViewer(ILogger<ServerDataViewer> logger, IDataValueCache<EFServerSnapshot, (int?, DateTime?)> snapshotCache,
|
2021-08-29 14:10:10 -04:00
|
|
|
|
IDataValueCache<EFClient, (int, int)> serverStatsCache,
|
2022-06-09 10:56:41 -04:00
|
|
|
|
IDataValueCache<EFServerSnapshot, List<ClientHistoryInfo>> clientHistoryCache, IDataValueCache<EFClientRankingHistory, int> rankedClientsCache)
|
2021-08-26 18:35:05 -04:00
|
|
|
|
{
|
|
|
|
|
_logger = logger;
|
|
|
|
|
_snapshotCache = snapshotCache;
|
|
|
|
|
_serverStatsCache = serverStatsCache;
|
2021-08-29 14:10:10 -04:00
|
|
|
|
_clientHistoryCache = clientHistoryCache;
|
2022-06-09 10:56:41 -04:00
|
|
|
|
_rankedClientsCache = rankedClientsCache;
|
2021-08-26 18:35:05 -04:00
|
|
|
|
}
|
|
|
|
|
|
2021-11-15 11:25:55 -05:00
|
|
|
|
public async Task<(int?, DateTime?)>
|
|
|
|
|
MaxConcurrentClientsAsync(long? serverId = null, TimeSpan? overPeriod = null,
|
2021-08-26 18:35:05 -04:00
|
|
|
|
CancellationToken token = default)
|
|
|
|
|
{
|
|
|
|
|
_snapshotCache.SetCacheItem(async (snapshots, cancellationToken) =>
|
|
|
|
|
{
|
|
|
|
|
var oldestEntry = overPeriod.HasValue
|
|
|
|
|
? DateTime.UtcNow - overPeriod.Value
|
|
|
|
|
: DateTime.UtcNow.AddDays(-1);
|
2021-09-14 19:12:20 -04:00
|
|
|
|
|
|
|
|
|
int? maxClients;
|
|
|
|
|
DateTime? maxClientsTime;
|
2021-08-26 18:35:05 -04:00
|
|
|
|
|
|
|
|
|
if (serverId != null)
|
|
|
|
|
{
|
2021-09-14 19:12:20 -04:00
|
|
|
|
var clients = await snapshots.Where(snapshot => snapshot.ServerId == serverId)
|
2021-08-26 18:35:05 -04:00
|
|
|
|
.Where(snapshot => snapshot.CapturedAt >= oldestEntry)
|
2021-09-14 19:12:20 -04:00
|
|
|
|
.OrderByDescending(snapshot => snapshot.ClientCount)
|
|
|
|
|
.Select(snapshot => new
|
|
|
|
|
{
|
|
|
|
|
snapshot.ClientCount,
|
|
|
|
|
snapshot.CapturedAt
|
|
|
|
|
})
|
|
|
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
|
|
|
|
|
|
|
|
maxClients = clients?.ClientCount;
|
|
|
|
|
maxClientsTime = clients?.CapturedAt;
|
2021-08-26 18:35:05 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-09-14 19:12:20 -04:00
|
|
|
|
var clients = await snapshots.Where(snapshot => snapshot.CapturedAt >= oldestEntry)
|
2021-08-26 18:35:05 -04:00
|
|
|
|
.GroupBy(snapshot => snapshot.PeriodBlock)
|
2021-09-14 19:12:20 -04:00
|
|
|
|
.Select(grp => new
|
|
|
|
|
{
|
|
|
|
|
ClientCount = grp.Sum(snapshot => (int?) snapshot.ClientCount),
|
|
|
|
|
Time = grp.Max(snapshot => (DateTime?) snapshot.CapturedAt)
|
|
|
|
|
})
|
|
|
|
|
.OrderByDescending(snapshot => snapshot.ClientCount)
|
|
|
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
|
|
|
|
|
|
|
|
maxClients = clients?.ClientCount;
|
|
|
|
|
maxClientsTime = clients?.Time;
|
2021-08-26 18:35:05 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_logger.LogDebug("Max concurrent clients since {Start} is {Clients}", oldestEntry, maxClients);
|
|
|
|
|
|
2021-09-14 19:12:20 -04:00
|
|
|
|
return (maxClients, maxClientsTime);
|
2021-11-15 11:25:55 -05:00
|
|
|
|
}, nameof(MaxConcurrentClientsAsync), _cacheTimeSpan, true);
|
2021-08-26 18:35:05 -04:00
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return await _snapshotCache.GetCacheItem(nameof(MaxConcurrentClientsAsync), token);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
_logger.LogError(ex, "Could not retrieve data for {Name}", nameof(MaxConcurrentClientsAsync));
|
2021-09-14 19:12:20 -04:00
|
|
|
|
return (null, null);
|
2021-08-26 18:35:05 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<(int, int)> ClientCountsAsync(TimeSpan? overPeriod = null, CancellationToken token = default)
|
|
|
|
|
{
|
|
|
|
|
_serverStatsCache.SetCacheItem(async (set, cancellationToken) =>
|
|
|
|
|
{
|
|
|
|
|
var count = await set.CountAsync(cancellationToken);
|
|
|
|
|
var startOfPeriod =
|
|
|
|
|
DateTime.UtcNow.AddHours(-overPeriod?.TotalHours ?? -24);
|
|
|
|
|
var recentCount = await set.CountAsync(client => client.LastConnection >= startOfPeriod,
|
|
|
|
|
cancellationToken);
|
|
|
|
|
|
|
|
|
|
return (count, recentCount);
|
2021-11-15 11:25:55 -05:00
|
|
|
|
}, nameof(_serverStatsCache), _cacheTimeSpan, true);
|
2021-08-26 18:35:05 -04:00
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return await _serverStatsCache.GetCacheItem(nameof(_serverStatsCache), token);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
_logger.LogError(ex, "Could not retrieve data for {Name}", nameof(ClientCountsAsync));
|
|
|
|
|
return (0, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-08-29 14:10:10 -04:00
|
|
|
|
|
|
|
|
|
public async Task<IEnumerable<ClientHistoryInfo>> ClientHistoryAsync(TimeSpan? overPeriod = null, CancellationToken token = default)
|
|
|
|
|
{
|
|
|
|
|
_clientHistoryCache.SetCacheItem(async (set, cancellationToken) =>
|
|
|
|
|
{
|
|
|
|
|
var oldestEntry = overPeriod.HasValue
|
|
|
|
|
? DateTime.UtcNow - overPeriod.Value
|
|
|
|
|
: DateTime.UtcNow.AddHours(-12);
|
|
|
|
|
|
|
|
|
|
var history = await set.Where(snapshot => snapshot.CapturedAt >= oldestEntry)
|
|
|
|
|
.Select(snapshot =>
|
|
|
|
|
new
|
|
|
|
|
{
|
|
|
|
|
snapshot.ServerId,
|
|
|
|
|
snapshot.CapturedAt,
|
2022-03-29 17:42:53 -04:00
|
|
|
|
snapshot.ClientCount,
|
|
|
|
|
snapshot.ConnectionInterrupted,
|
|
|
|
|
MapName = snapshot.Map.Name,
|
2021-08-29 14:10:10 -04:00
|
|
|
|
})
|
|
|
|
|
.OrderBy(snapshot => snapshot.CapturedAt)
|
|
|
|
|
.ToListAsync(cancellationToken);
|
|
|
|
|
|
|
|
|
|
return history.GroupBy(snapshot => snapshot.ServerId).Select(byServer => new ClientHistoryInfo
|
|
|
|
|
{
|
|
|
|
|
ServerId = byServer.Key,
|
2022-03-29 17:42:53 -04:00
|
|
|
|
ClientCounts = byServer.Select(snapshot => new ClientCountSnapshot
|
|
|
|
|
{ Time = snapshot.CapturedAt, ClientCount = snapshot.ClientCount, ConnectionInterrupted = snapshot.ConnectionInterrupted ?? false, Map = snapshot.MapName}).ToList()
|
2021-08-29 14:10:10 -04:00
|
|
|
|
}).ToList();
|
|
|
|
|
}, nameof(_clientHistoryCache), TimeSpan.MaxValue);
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return await _clientHistoryCache.GetCacheItem(nameof(_clientHistoryCache), token);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
_logger.LogError(ex, "Could not retrieve data for {Name}", nameof(ClientHistoryAsync));
|
|
|
|
|
return Enumerable.Empty<ClientHistoryInfo>();
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-06-09 10:56:41 -04:00
|
|
|
|
|
|
|
|
|
public async Task<int> RankedClientsCountAsync(long? serverId = null, CancellationToken token = default)
|
|
|
|
|
{
|
|
|
|
|
_rankedClientsCache.SetCacheItem(async (set, cancellationToken) =>
|
|
|
|
|
{
|
|
|
|
|
var fifteenDaysAgo = DateTime.UtcNow.AddDays(-15);
|
|
|
|
|
return await set
|
|
|
|
|
.Where(rating => rating.Newest)
|
|
|
|
|
.Where(rating => rating.ServerId == serverId)
|
|
|
|
|
.Where(rating => rating.CreatedDateTime >= fifteenDaysAgo)
|
|
|
|
|
.Where(rating => rating.Client.Level != EFClient.Permission.Banned)
|
|
|
|
|
.Where(rating => rating.Ranking != null)
|
|
|
|
|
.CountAsync(cancellationToken);
|
2023-04-05 10:54:57 -04:00
|
|
|
|
}, nameof(_rankedClientsCache), serverId is null ? null: new[] { (object)serverId }, _cacheTimeSpan);
|
2022-06-09 10:56:41 -04:00
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return await _rankedClientsCache.GetCacheItem(nameof(_rankedClientsCache), serverId, token);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
_logger.LogError(ex, "Could not retrieve data for {Name}", nameof(RankedClientsCountAsync));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-08-26 18:35:05 -04:00
|
|
|
|
}
|
2022-03-29 17:42:53 -04:00
|
|
|
|
}
|