mirror of
https://github.com/immense/Remotely.git
synced 2025-10-26 11:27:15 +00:00
82 lines
2.3 KiB
C#
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();
|
|
}
|
|
}
|
|
} |