diff --git a/CryptoExchange.Net/Clients/RestApiClient.cs b/CryptoExchange.Net/Clients/RestApiClient.cs
index ace6642..d9fb3f9 100644
--- a/CryptoExchange.Net/Clients/RestApiClient.cs
+++ b/CryptoExchange.Net/Clients/RestApiClient.cs
@@ -154,6 +154,7 @@ namespace CryptoExchange.Net.Clients
/// Cancellation token
/// Additional headers for this request
/// Override the request weight for this request definition, for example when the weight depends on the parameters
+ /// Specify the weight to apply to the individual rate limit guard for this request
///
protected virtual Task> SendAsync(
string baseAddress,
@@ -161,7 +162,8 @@ namespace CryptoExchange.Net.Clients
ParameterCollection? parameters,
CancellationToken cancellationToken,
Dictionary? additionalHeaders = null,
- int? weight = null) where T : class
+ int? weight = null,
+ int? weightSingleLimiter = null) where T : class
{
var parameterPosition = definition.ParameterPosition ?? ParameterPositions[definition.Method];
return SendAsync(
@@ -171,7 +173,8 @@ namespace CryptoExchange.Net.Clients
parameterPosition == HttpMethodParameterPosition.InBody ? parameters : null,
cancellationToken,
additionalHeaders,
- weight);
+ weight,
+ weightSingleLimiter);
}
///
@@ -185,6 +188,7 @@ namespace CryptoExchange.Net.Clients
/// Cancellation token
/// Additional headers for this request
/// Override the request weight for this request definition, for example when the weight depends on the parameters
+ /// Specify the weight to apply to the individual rate limit guard for this request
///
protected virtual async Task> SendAsync(
string baseAddress,
@@ -193,7 +197,8 @@ namespace CryptoExchange.Net.Clients
ParameterCollection? bodyParameters,
CancellationToken cancellationToken,
Dictionary? additionalHeaders = null,
- int? weight = null) where T : class
+ int? weight = null,
+ int? weightSingleLimiter = null) where T : class
{
string? cacheKey = null;
if (ShouldCache(definition))
@@ -217,7 +222,7 @@ namespace CryptoExchange.Net.Clients
currentTry++;
var requestId = ExchangeHelpers.NextId();
- var prepareResult = await PrepareAsync(requestId, baseAddress, definition, cancellationToken, additionalHeaders, weight).ConfigureAwait(false);
+ var prepareResult = await PrepareAsync(requestId, baseAddress, definition, cancellationToken, additionalHeaders, weight, weightSingleLimiter).ConfigureAwait(false);
if (!prepareResult)
return new WebCallResult(prepareResult.Error!);
@@ -258,6 +263,7 @@ namespace CryptoExchange.Net.Clients
/// Cancellation token
/// Additional headers for this request
/// Override the request weight for this request
+ /// Specify the weight to apply to the individual rate limit guard for this request
///
///
protected virtual async Task PrepareAsync(
@@ -266,10 +272,9 @@ namespace CryptoExchange.Net.Clients
RequestDefinition definition,
CancellationToken cancellationToken,
Dictionary? additionalHeaders = null,
- int? weight = null)
+ int? weight = null,
+ int? weightSingleLimiter = null)
{
- var requestWeight = weight ?? definition.Weight;
-
// Time sync
if (definition.Authenticated)
{
@@ -295,6 +300,7 @@ namespace CryptoExchange.Net.Clients
}
// Rate limiting
+ var requestWeight = weight ?? definition.Weight;
if (requestWeight != 0)
{
if (definition.RateLimitGate == null)
@@ -316,7 +322,8 @@ namespace CryptoExchange.Net.Clients
if (ClientOptions.RateLimiterEnabled)
{
- var limitResult = await definition.RateLimitGate.ProcessSingleAsync(_logger, requestId, definition.LimitGuard, RateLimitItemType.Request, definition, baseAddress, AuthenticationProvider?._credentials.Key, ClientOptions.RateLimitingBehaviour, cancellationToken).ConfigureAwait(false);
+ var singleRequestWeight = weightSingleLimiter ?? 1;
+ var limitResult = await definition.RateLimitGate.ProcessSingleAsync(_logger, requestId, definition.LimitGuard, RateLimitItemType.Request, definition, baseAddress, AuthenticationProvider?._credentials.Key, singleRequestWeight, ClientOptions.RateLimitingBehaviour, cancellationToken).ConfigureAwait(false);
if (!limitResult)
return new CallResult(limitResult.Error!);
}
diff --git a/CryptoExchange.Net/Objects/RequestDefinitionCache.cs b/CryptoExchange.Net/Objects/RequestDefinitionCache.cs
index acd469f..9c50a0b 100644
--- a/CryptoExchange.Net/Objects/RequestDefinitionCache.cs
+++ b/CryptoExchange.Net/Objects/RequestDefinitionCache.cs
@@ -58,9 +58,38 @@ namespace CryptoExchange.Net.Objects
HttpMethodParameterPosition? parameterPosition = null,
ArrayParametersSerialization? arraySerialization = null,
bool? preventCaching = null)
+ => GetOrCreate(method + path, method, path, rateLimitGate, weight, authenticated, limitGuard, requestBodyFormat, parameterPosition, arraySerialization, preventCaching);
+
+ ///
+ /// Get a definition if it is already in the cache or create a new definition and add it to the cache
+ ///
+ /// Request identifier
+ /// The HttpMethod
+ /// Endpoint path
+ /// The rate limit gate
+ /// The rate limit guard for this specific endpoint
+ /// Request weight
+ /// Endpoint is authenticated
+ /// Request body format
+ /// Parameter position
+ /// Array serialization type
+ /// Prevent request caching
+ ///
+ public RequestDefinition GetOrCreate(
+ string identifier,
+ HttpMethod method,
+ string path,
+ IRateLimitGate? rateLimitGate,
+ int weight,
+ bool authenticated,
+ IRateLimitGuard? limitGuard = null,
+ RequestBodyFormat? requestBodyFormat = null,
+ HttpMethodParameterPosition? parameterPosition = null,
+ ArrayParametersSerialization? arraySerialization = null,
+ bool? preventCaching = null)
{
- if (!_definitions.TryGetValue(method + path, out var def))
+ if (!_definitions.TryGetValue(identifier, out var def))
{
def = new RequestDefinition(path, method)
{
@@ -73,7 +102,7 @@ namespace CryptoExchange.Net.Objects
ParameterPosition = parameterPosition,
PreventCaching = preventCaching ?? false
};
- _definitions.TryAdd(method + path, def);
+ _definitions.TryAdd(identifier, def);
}
return def;
diff --git a/CryptoExchange.Net/RateLimiting/Interfaces/IRateLimitGate.cs b/CryptoExchange.Net/RateLimiting/Interfaces/IRateLimitGate.cs
index 2d76498..e4e7cf2 100644
--- a/CryptoExchange.Net/RateLimiting/Interfaces/IRateLimitGate.cs
+++ b/CryptoExchange.Net/RateLimiting/Interfaces/IRateLimitGate.cs
@@ -68,8 +68,9 @@ namespace CryptoExchange.Net.RateLimiting.Interfaces
/// The host address
/// The API key
/// Behaviour when rate limit is hit
+ /// The weight to apply to the limit guard
/// Cancelation token
/// Error if RateLimitingBehaviour is Fail and rate limit is hit
- Task ProcessSingleAsync(ILogger logger, int itemId, IRateLimitGuard guard, RateLimitItemType type, RequestDefinition definition, string baseAddress, string? apiKey, RateLimitingBehaviour behaviour, CancellationToken ct);
+ Task ProcessSingleAsync(ILogger logger, int itemId, IRateLimitGuard guard, RateLimitItemType type, RequestDefinition definition, string baseAddress, string? apiKey, int requestWeight, RateLimitingBehaviour behaviour, CancellationToken ct);
}
}
diff --git a/CryptoExchange.Net/RateLimiting/RateLimitGate.cs b/CryptoExchange.Net/RateLimiting/RateLimitGate.cs
index 4adb4a5..0557c87 100644
--- a/CryptoExchange.Net/RateLimiting/RateLimitGate.cs
+++ b/CryptoExchange.Net/RateLimiting/RateLimitGate.cs
@@ -69,6 +69,7 @@ namespace CryptoExchange.Net.RateLimiting
RequestDefinition definition,
string host,
string? apiKey,
+ int requestWeight,
RateLimitingBehaviour rateLimitingBehaviour,
CancellationToken ct)
{
@@ -77,7 +78,7 @@ namespace CryptoExchange.Net.RateLimiting
_waitingCount++;
try
{
- return await CheckGuardsAsync(new IRateLimitGuard[] { guard }, logger, itemId, type, definition, host, apiKey, 1, rateLimitingBehaviour, ct).ConfigureAwait(false);
+ return await CheckGuardsAsync(new IRateLimitGuard[] { guard }, logger, itemId, type, definition, host, apiKey, requestWeight, rateLimitingBehaviour, ct).ConfigureAwait(false);
}
catch (TaskCanceledException)
{