2022-08-30 15:00:58 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
|
|
|
|
namespace SharpChat {
|
|
|
|
|
public enum ChatRateLimitState {
|
|
|
|
|
None,
|
|
|
|
|
Warning,
|
|
|
|
|
Kick,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class ChatRateLimiter {
|
|
|
|
|
private const int FLOOD_PROTECTION_AMOUNT = 30;
|
|
|
|
|
private const int FLOOD_PROTECTION_THRESHOLD = 10;
|
|
|
|
|
|
2023-02-07 15:01:56 +00:00
|
|
|
|
private readonly Queue<DateTimeOffset> TimePoints = new();
|
2022-08-30 15:00:58 +00:00
|
|
|
|
|
|
|
|
|
public ChatRateLimitState State {
|
|
|
|
|
get {
|
2023-02-07 15:01:56 +00:00
|
|
|
|
lock(TimePoints) {
|
|
|
|
|
if(TimePoints.Count == FLOOD_PROTECTION_AMOUNT) {
|
|
|
|
|
if((TimePoints.Last() - TimePoints.First()).TotalSeconds <= FLOOD_PROTECTION_THRESHOLD)
|
2022-08-30 15:00:58 +00:00
|
|
|
|
return ChatRateLimitState.Kick;
|
|
|
|
|
|
2023-02-07 15:01:56 +00:00
|
|
|
|
if((TimePoints.Last() - TimePoints.Skip(5).First()).TotalSeconds <= FLOOD_PROTECTION_THRESHOLD)
|
2022-08-30 15:00:58 +00:00
|
|
|
|
return ChatRateLimitState.Warning;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ChatRateLimitState.None;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void AddTimePoint(DateTimeOffset? dto = null) {
|
2023-02-07 15:01:56 +00:00
|
|
|
|
if(!dto.HasValue)
|
2022-08-30 15:00:58 +00:00
|
|
|
|
dto = DateTimeOffset.Now;
|
|
|
|
|
|
2023-02-07 15:01:56 +00:00
|
|
|
|
lock(TimePoints) {
|
|
|
|
|
if(TimePoints.Count >= FLOOD_PROTECTION_AMOUNT)
|
2022-08-30 15:00:58 +00:00
|
|
|
|
TimePoints.Dequeue();
|
|
|
|
|
|
|
|
|
|
TimePoints.Enqueue(dto.Value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|