Remotely/Shared/Helpers/RateLImiter.cs
2024-07-16 09:25:15 -07:00

82 lines
2.3 KiB
C#

using Microsoft.Extensions.Caching.Memory;
using System.Runtime.CompilerServices;
namespace Remotely.Shared.Helpers;
public static class RateLimiter
{
private static readonly MemoryCache _cache = new(new MemoryCacheOptions());
private static readonly SemaphoreSlim _cacheLock = new(1, 1);
/// <summary>
/// Clears the RateLimiter cache so it is reset to a fresh state.
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static async Task Reset(CancellationToken cancellationToken = default)
{
await _cacheLock.WaitAsync(cancellationToken);
try
{
_cache.Clear();
}
finally
{
_cacheLock.Release();
}
}
/// <summary>
/// <para>
/// Throttles a given func so it is only called once every duration.
/// </para>
/// <para>
/// The key used to identify and debounce the action will be derived from
/// the caller information. Those parameters will be populated automatically
/// and can be left empty.
/// </para>
/// </summary>
public static async Task Throttle(
Func<Task> func,
TimeSpan duration,
[CallerMemberName] string callerMemberName = "",
[CallerFilePath] string callerFilePath = "",
[CallerLineNumber] int callerLineNumber = -1,
CancellationToken cancellationToken = default)
{
var key = $"{callerMemberName}-{callerFilePath}-{callerLineNumber}";
await Throttle(func, duration, key, cancellationToken);
}
/// <summary>
/// <para>
/// Throttles a given func so it is only called once every duration.
/// </para>
/// <para>
/// The provided key will be used to identify and throttle the func.
/// </para>
/// </summary>
public static async Task Throttle(
Func<Task> func,
TimeSpan duration,
string key,
CancellationToken cancellationToken = default)
{
await _cacheLock.WaitAsync(cancellationToken);
try
{
if (_cache.TryGetValue(key, out _))
{
return;
}
await func.Invoke();
_cache.Set(key, string.Empty, duration);
}
finally
{
_cacheLock.Release();
}
}
}