Files
CS2-SimpleAdmin/CS2-SimpleAdmin/Managers/CacheManager.cs
Dawid Bepierszcz f69f1277f8 1.7.7-alpha
- Fixed (@all,@team,@lifestate) spam with discord webhook
- Currently `small` actions for ban optimizations
2025-05-20 23:51:59 +02:00

168 lines
6.0 KiB
C#

using System.Collections.Concurrent;
using CS2_SimpleAdmin.Models;
using Dapper;
using Microsoft.Extensions.Logging;
namespace CS2_SimpleAdmin.Managers;
internal class CacheManager
{
private readonly ConcurrentDictionary<int, BanRecord> _banCache = new();
private readonly ConcurrentDictionary<ulong, (HashSet<string> ips, DateTime used_at)> _playerIpsCache = new();
private DateTime _lastUpdateTime = DateTime.MinValue;
private bool _isInitialized;
public async Task InitializeCacheAsync()
{
if (CS2_SimpleAdmin.Database == null) return;
if (!CS2_SimpleAdmin.ServerLoaded)
return;
if (_isInitialized) return;
try
{
await using var connection = await CS2_SimpleAdmin.Database.GetConnectionAsync();
var bans = await connection.QueryAsync<BanRecord>(
"""
SELECT
id AS Id,
player_name AS PlayerName,
player_steamid AS PlayerSteamId,
player_ip AS PlayerIp,
admin_steamid AS AdminSteamId,
admin_name AS AdminName,
reason AS Reason,
duration AS Duration,
ends AS Ends,
created AS Created,
server_id AS ServerId,
status AS Status,
updated_at AS UpdatedAt
FROM sa_bans
""");
var ipHistory = await connection.QueryAsync<(ulong steamid, string address, DateTime used_at)>(
"SELECT steamid, address, used_at FROM sa_players_ips");
foreach (var ban in bans)
{
_banCache.TryAdd(ban.Id, ban);
}
foreach (var group in ipHistory.GroupBy(x => x.steamid))
{
var ips = new HashSet<string>(group.Select(x => x.address));
var lastUsed = group.Max(x => x.used_at);
_playerIpsCache[group.Key] = (ips, lastUsed);
}
_lastUpdateTime = DateTime.Now;
_isInitialized = true;
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public async Task RefreshCacheAsync()
{
if (CS2_SimpleAdmin.Database == null) return;
if (!_isInitialized) return;
try
{
await using var connection = await CS2_SimpleAdmin.Database.GetConnectionAsync();
var updatedBans = (await connection.QueryAsync<BanRecord>(
"SELECT * FROM `sa_bans` WHERE updated_at > @lastUpdate OR created > @lastUpdate ORDER BY updated_at DESC",
new { lastUpdate = _lastUpdateTime }
)).ToList();
var ipHistory = await connection.QueryAsync<(ulong steamid, string address, DateTime used_at)>(
"SELECT steamid, address, used_at FROM sa_players_ips");
// foreach (var group in ipHistory.GroupBy(x => x.steamid))
// {
// var ips = new HashSet<string>(group.Select(x => x.address));
// var lastUsed = group.Max(x => x.used_at);
// _playerIpsCache[group.Key] = (ips, lastUsed);
// }
var groupedData = ipHistory.GroupBy(x => x.steamid).ToList();
Parallel.ForEach(groupedData, group =>
{
var ips = new HashSet<string>(group.Select(x => x.address));
var lastUsed = group.Max(x => x.used_at);
_playerIpsCache.AddOrUpdate(
group.Key,
_ => (ips, lastUsed),
(_, existing) =>
{
existing.ips.UnionWith(ips);
return (existing.ips,
lastUsed > existing.used_at ? lastUsed : existing.used_at);
});
});
if (updatedBans.Count == 0)
return;
foreach (var ban in updatedBans)
{
_banCache.AddOrUpdate(ban.Id, ban, (_, _) => ban);
}
_lastUpdateTime = DateTime.Now;
}
catch (Exception e)
{
// ignored
}
}
public List<BanRecord> GetAllBans() => _banCache.Values.ToList();
public List<BanRecord> GetActiveBans() => _banCache.Values.Where(b => b.Status == "ACTIVE").ToList();
public List<BanRecord> GetPlayerBansBySteamId(string steamId) => _banCache.Values.Where(b => b.PlayerSteamId == steamId).ToList();
private bool IsIpBanned(string ipAddress)
{
return _banCache.Values.Any(b =>
b.Status == "ACTIVE" &&
!string.IsNullOrEmpty(b.PlayerIp) &&
b.PlayerIp.Equals(ipAddress, StringComparison.OrdinalIgnoreCase));
}
public bool IsPlayerBanned(string? steamId, string? ipAddress) =>
_banCache.Values.Any(b =>
b.Status == "ACTIVE" && (
(steamId != null &&
b.PlayerSteamId != null &&
b.PlayerSteamId.Equals(steamId, StringComparison.OrdinalIgnoreCase)) ||
(ipAddress != null &&
b.PlayerIp != null &&
b.PlayerIp.Equals(ipAddress, StringComparison.OrdinalIgnoreCase))
));
public bool IsPlayerOrAnyIpBanned(ulong steamId)
{
var steamIdStr = steamId.ToString();
if (_banCache.Values.Any(b =>
b.Status == "ACTIVE" &&
b.PlayerSteamId?.Equals(steamIdStr, StringComparison.OrdinalIgnoreCase) == true))
{
return true;
}
return _playerIpsCache.TryGetValue(steamId, out var ipList) && ipList.ips.Any(IsIpBanned);
}
public bool HasIpForPlayer(ulong steamId, string ipAddress)
{
return _playerIpsCache.TryGetValue(steamId, out var ipList)
&& ipList.ips.Contains(ipAddress);
}
}