mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-05-24 00:52:23 -04:00
60 lines
1.9 KiB
C#
60 lines
1.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace API.Helpers;
|
|
|
|
public class RateLimiter(int maxRequests, TimeSpan duration, bool refillBetween = true)
|
|
{
|
|
private readonly Dictionary<string, (int Tokens, DateTime LastRefill)> _tokenBuckets = new();
|
|
private readonly object _lock = new();
|
|
|
|
public bool TryAcquire(string key)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
if (!_tokenBuckets.TryGetValue(key, out var bucket))
|
|
{
|
|
bucket = (Tokens: maxRequests, LastRefill: DateTime.UtcNow);
|
|
_tokenBuckets[key] = bucket;
|
|
}
|
|
|
|
RefillTokens(key);
|
|
|
|
lock (_lock)
|
|
{
|
|
|
|
if (_tokenBuckets[key].Tokens > 0)
|
|
{
|
|
_tokenBuckets[key] = (Tokens: _tokenBuckets[key].Tokens - 1, LastRefill: _tokenBuckets[key].LastRefill);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private void RefillTokens(string key)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
var now = DateTime.UtcNow;
|
|
var timeSinceLastRefill = now - _tokenBuckets[key].LastRefill;
|
|
var tokensToAdd = (int) (timeSinceLastRefill.TotalSeconds / duration.TotalSeconds);
|
|
|
|
// Refill the bucket if the elapsed time is greater than or equal to the duration
|
|
if (timeSinceLastRefill >= duration)
|
|
{
|
|
_tokenBuckets[key] = (Tokens: maxRequests, LastRefill: now);
|
|
Console.WriteLine($"Tokens Refilled to Max: {maxRequests}");
|
|
}
|
|
else if (tokensToAdd > 0 && refillBetween)
|
|
{
|
|
_tokenBuckets[key] = (Tokens: Math.Min(maxRequests, _tokenBuckets[key].Tokens + tokensToAdd), LastRefill: now);
|
|
Console.WriteLine($"Tokens Refilled: {_tokenBuckets[key].Tokens}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|