1
0
mirror of https://github.com/JKorf/CryptoExchange.Net synced 2025-06-08 16:36:15 +00:00

Merge pull request #75 from burakoner/master

Rate Limiter Credits parameter to SendRequest method
This commit is contained in:
Jan Korf 2021-01-11 09:31:20 +01:00 committed by GitHub
commit edbca6a680
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 74 additions and 8 deletions

View File

@ -1,4 +1,4 @@
using CryptoExchange.Net.Objects; using CryptoExchange.Net.Objects;
namespace CryptoExchange.Net.Interfaces namespace CryptoExchange.Net.Interfaces
{ {
@ -13,7 +13,8 @@ namespace CryptoExchange.Net.Interfaces
/// <param name="client"></param> /// <param name="client"></param>
/// <param name="url"></param> /// <param name="url"></param>
/// <param name="limitBehaviour"></param> /// <param name="limitBehaviour"></param>
/// <param name="credits"></param>
/// <returns></returns> /// <returns></returns>
CallResult<double> LimitRequest(RestClient client, string url, RateLimitingBehaviour limitBehaviour); CallResult<double> LimitRequest(RestClient client, string url, RateLimitingBehaviour limitBehaviour, int credits=1);
} }
} }

View File

@ -34,7 +34,7 @@ namespace CryptoExchange.Net.RateLimiter
} }
/// <inheritdoc /> /// <inheritdoc />
public CallResult<double> LimitRequest(RestClient client, string url, RateLimitingBehaviour limitBehaviour) public CallResult<double> LimitRequest(RestClient client, string url, RateLimitingBehaviour limitBehaviour, int credits = 1)
{ {
if(client.authProvider?.Credentials?.Key == null) if(client.authProvider?.Credentials?.Key == null)
return new CallResult<double>(0, null); return new CallResult<double>(0, null);

View File

@ -0,0 +1,65 @@
using CryptoExchange.Net.Interfaces;
using CryptoExchange.Net.Objects;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
namespace CryptoExchange.Net.RateLimiter
{
/// <summary>
/// Limits the amount of requests per time period to a certain limit, counts the total amount of requests.
/// </summary>
public class RateLimiterCredit : IRateLimiter
{
internal List<DateTime> history = new List<DateTime>();
private readonly int limit;
private readonly TimeSpan perTimePeriod;
private readonly object requestLock = new object();
/// <summary>
/// Create a new RateLimiterTotal. This rate limiter limits the amount of requests per time period to a certain limit, counts the total amount of requests.
/// </summary>
/// <param name="limit">The amount to limit to</param>
/// <param name="perTimePeriod">The time period over which the limit counts</param>
public RateLimiterCredit(int limit, TimeSpan perTimePeriod)
{
this.limit = limit;
this.perTimePeriod = perTimePeriod;
}
/// <inheritdoc />
public CallResult<double> LimitRequest(RestClient client, string url, RateLimitingBehaviour limitBehaviour, int credits = 1)
{
var sw = Stopwatch.StartNew();
lock (requestLock)
{
sw.Stop();
double waitTime = 0;
var checkTime = DateTime.UtcNow;
history.RemoveAll(d => d < checkTime - perTimePeriod);
if (history.Count >= limit)
{
waitTime = (history.First() - (checkTime - perTimePeriod)).TotalMilliseconds;
if (waitTime > 0)
{
if (limitBehaviour == RateLimitingBehaviour.Fail)
return new CallResult<double>(waitTime, new RateLimitError($"total limit of {limit} reached"));
Thread.Sleep(Convert.ToInt32(waitTime));
waitTime += sw.ElapsedMilliseconds;
}
}
for (int i = 1; i <= credits; i++)
history.Add(DateTime.UtcNow);
history.Sort();
return new CallResult<double>(waitTime, null);
}
}
}
}

View File

@ -30,7 +30,7 @@ namespace CryptoExchange.Net.RateLimiter
} }
/// <inheritdoc /> /// <inheritdoc />
public CallResult<double> LimitRequest(RestClient client, string url, RateLimitingBehaviour limitingBehaviour) public CallResult<double> LimitRequest(RestClient client, string url, RateLimitingBehaviour limitingBehaviour, int credits = 1)
{ {
int waitTime; int waitTime;
RateLimitObject rlo; RateLimitObject rlo;

View File

@ -31,7 +31,7 @@ namespace CryptoExchange.Net.RateLimiter
} }
/// <inheritdoc /> /// <inheritdoc />
public CallResult<double> LimitRequest(RestClient client, string url, RateLimitingBehaviour limitBehaviour) public CallResult<double> LimitRequest(RestClient client, string url, RateLimitingBehaviour limitBehaviour, int credits = 1)
{ {
var sw = Stopwatch.StartNew(); var sw = Stopwatch.StartNew();
lock (requestLock) lock (requestLock)

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
@ -172,7 +172,7 @@ namespace CryptoExchange.Net
/// <returns></returns> /// <returns></returns>
[return: NotNull] [return: NotNull]
protected virtual async Task<WebCallResult<T>> SendRequest<T>(Uri uri, HttpMethod method, CancellationToken cancellationToken, protected virtual async Task<WebCallResult<T>> SendRequest<T>(Uri uri, HttpMethod method, CancellationToken cancellationToken,
Dictionary<string, object>? parameters = null, bool signed = false, bool checkResult = true, PostParameters? postPosition = null, ArrayParametersSerialization? arraySerialization = null) where T : class Dictionary<string, object>? parameters = null, bool signed = false, bool checkResult = true, PostParameters? postPosition = null, ArrayParametersSerialization? arraySerialization = null, int credits=1) where T : class
{ {
var requestId = NextId(); var requestId = NextId();
log.Write(LogVerbosity.Debug, $"[{requestId}] Creating request for " + uri); log.Write(LogVerbosity.Debug, $"[{requestId}] Creating request for " + uri);
@ -185,7 +185,7 @@ namespace CryptoExchange.Net
var request = ConstructRequest(uri, method, parameters, signed, postPosition ?? postParametersPosition, arraySerialization ?? this.arraySerialization, requestId); var request = ConstructRequest(uri, method, parameters, signed, postPosition ?? postParametersPosition, arraySerialization ?? this.arraySerialization, requestId);
foreach (var limiter in RateLimiters) foreach (var limiter in RateLimiters)
{ {
var limitResult = limiter.LimitRequest(this, uri.AbsolutePath, RateLimitBehaviour); var limitResult = limiter.LimitRequest(this, uri.AbsolutePath, RateLimitBehaviour, credits);
if (!limitResult.Success) if (!limitResult.Success)
{ {
log.Write(LogVerbosity.Debug, $"[{requestId}] Request {uri.AbsolutePath} failed because of rate limit"); log.Write(LogVerbosity.Debug, $"[{requestId}] Request {uri.AbsolutePath} failed because of rate limit");