80 lines
3 KiB
C#
80 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);
|
|
}
|
|
}
|
|
}
|
|
}
|