MosswartMassacre/Shared/RateLimiter.cs
2025-05-12 20:27:00 +02:00

59 lines
2 KiB
C#

using System;
using System.Diagnostics;
namespace Mag.Shared
{
public class RateLimiter
{
public readonly int MaxNumberOfEvents;
private readonly double overPeriodInSeconds;
private readonly double targetEventSpacingInSeconds;
private readonly Stopwatch stopwatch = Stopwatch.StartNew();
public RateLimiter(int maxNumberOfEvents, TimeSpan overPeriod)
{
if (maxNumberOfEvents <= 0)
throw new ArgumentOutOfRangeException(nameof(maxNumberOfEvents), $"{nameof(maxNumberOfEvents)} must be greater than 0");
if (overPeriod <= TimeSpan.Zero)
throw new ArgumentOutOfRangeException(nameof(overPeriod), $"{nameof(overPeriod)} must be greater than TimeSpan.Zero");
MaxNumberOfEvents = maxNumberOfEvents;
overPeriodInSeconds = overPeriod.TotalSeconds;
targetEventSpacingInSeconds = overPeriodInSeconds / maxNumberOfEvents;
}
private int numberOfEventsRegistered;
/// <summary>
/// Result > 0 : We're able to meet our target rate and must pause between events.<para />
/// Result = 0 : We're running right no time. A new event should be registered without delay.<para />
/// Result &lt; 0 : We're running behind. A new event should be registered without delay. We're failing to meet our target rate.
/// </summary>
/// <returns></returns>
public double GetSecondsToWaitBeforeNextEvent()
{
var elapsedSeconds = stopwatch.Elapsed.TotalSeconds;
return ((targetEventSpacingInSeconds * numberOfEventsRegistered) - elapsedSeconds);
}
public void RegisterEvent()
{
numberOfEventsRegistered++;
var elapsedSeconds = stopwatch.Elapsed.TotalSeconds;
if (numberOfEventsRegistered > MaxNumberOfEvents || elapsedSeconds > overPeriodInSeconds)
{
numberOfEventsRegistered = 1;
stopwatch.Reset();
stopwatch.Start();
}
}
}
}