sharp-chat/SharpChat.Common/RateLimiting/RateLimitManager.cs
2022-08-30 17:05:29 +02:00

81 lines
3 KiB
C#

using SharpChat.Configuration;
using SharpChat.Protocol;
using SharpChat.Users;
using System;
using System.Collections.Generic;
namespace SharpChat.RateLimiting {
public class RateLimitManager {
public const int DEFAULT_USER_SIZE = 15;
public const int DEFAULT_USER_WARN_SIZE = 10;
public const int DEFAULT_CONN_SIZE = 30;
public const int DEFAULT_MINIMUM_DELAY = 5000;
public const int DEFAULT_KICK_LENGTH = 5;
public const int DEFAULT_KICK_MULTIPLIER = 2;
private CachedValue<int> UserSizeValue { get; }
private CachedValue<int> UserWarnSizeValue { get; }
private CachedValue<int> ConnSizeValue { get; }
private CachedValue<int> MinimumDelayValue { get; }
private CachedValue<int> KickLengthValue { get; }
private CachedValue<int> KickMultiplierValue { get; }
private readonly object ConnectionsSync = new();
private Dictionary<string, RateLimiter> Connections { get; } = new();
private readonly object UsersSync = new();
private Dictionary<long, RateLimiter> Users { get; } = new();
public RateLimitManager(IConfig config) {
UserSizeValue = config.ReadCached(@"userSize", DEFAULT_USER_SIZE);
UserWarnSizeValue = config.ReadCached(@"userWarnSize", DEFAULT_USER_WARN_SIZE);
ConnSizeValue = config.ReadCached(@"connSize", DEFAULT_CONN_SIZE);
MinimumDelayValue = config.ReadCached(@"minDelay", DEFAULT_MINIMUM_DELAY);
KickLengthValue = config.ReadCached(@"kickLength", DEFAULT_KICK_LENGTH);
KickMultiplierValue = config.ReadCached(@"kickMultiplier", DEFAULT_KICK_MULTIPLIER);
}
private RateLimiter CreateForConnection() {
return new RateLimiter(
ConnSizeValue,
-1,
MinimumDelayValue
);
}
private RateLimiter CreateForUser() {
return new RateLimiter(
UserSizeValue,
UserWarnSizeValue,
MinimumDelayValue
);
}
public TimeSpan GetKickLength(int kickCount) {
if(kickCount < 1)
kickCount = 1;
return TimeSpan.FromSeconds(KickLengthValue * (KickMultiplierValue * kickCount));
}
public bool UpdateConnection(IConnection conn) {
lock(ConnectionsSync) {
string connId = conn.ConnectionId;
if(!Connections.ContainsKey(connId))
Connections[connId] = CreateForConnection();
Connections[connId].Update();
return Connections[connId].ShouldKick;
}
}
public (bool kick, bool warn) UpdateUser(IUser user) {
lock(UsersSync) {
long userId = user.UserId;
if(!Users.ContainsKey(userId))
Users[userId] = CreateForUser();
Users[userId].Update();
return (Users[userId].ShouldKick, Users[userId].ShouldWarn);
}
}
}
}