diff --git a/CryptoExchange.Net/RateLimiting/Guards/RateLimitGuard.cs b/CryptoExchange.Net/RateLimiting/Guards/RateLimitGuard.cs index e9e5127..385f065 100644 --- a/CryptoExchange.Net/RateLimiting/Guards/RateLimitGuard.cs +++ b/CryptoExchange.Net/RateLimiting/Guards/RateLimitGuard.cs @@ -110,7 +110,7 @@ namespace CryptoExchange.Net.RateLimiting.Guards var delay = tracker.GetWaitTime(requestWeight); if (delay == default) - return LimitCheck.NotNeeded; + return LimitCheck.NotNeeded(Limit, TimeSpan, tracker.Current); return LimitCheck.Needed(delay, Limit, TimeSpan, tracker.Current); } diff --git a/CryptoExchange.Net/RateLimiting/Guards/SingleLimitGuard.cs b/CryptoExchange.Net/RateLimiting/Guards/SingleLimitGuard.cs index 1b53963..6ad431b 100644 --- a/CryptoExchange.Net/RateLimiting/Guards/SingleLimitGuard.cs +++ b/CryptoExchange.Net/RateLimiting/Guards/SingleLimitGuard.cs @@ -64,7 +64,7 @@ namespace CryptoExchange.Net.RateLimiting.Guards var delay = tracker.GetWaitTime(requestWeight); if (delay == default) - return LimitCheck.NotNeeded; + return LimitCheck.NotNeeded(_limit, _period, tracker.Current); return LimitCheck.Needed(delay, _limit, _period, tracker.Current); } diff --git a/CryptoExchange.Net/RateLimiting/Interfaces/IRateLimitGate.cs b/CryptoExchange.Net/RateLimiting/Interfaces/IRateLimitGate.cs index a907860..2d76498 100644 --- a/CryptoExchange.Net/RateLimiting/Interfaces/IRateLimitGate.cs +++ b/CryptoExchange.Net/RateLimiting/Interfaces/IRateLimitGate.cs @@ -16,6 +16,11 @@ namespace CryptoExchange.Net.RateLimiting.Interfaces /// event Action RateLimitTriggered; + /// + /// Event when the rate limit is updated. Note that it's only updated when a request is send, so there are no specific updates when the current usage is decaying. + /// + event Action? RateLimitUpdated; + /// /// Add a rate limit guard /// diff --git a/CryptoExchange.Net/RateLimiting/LimitCheck.cs b/CryptoExchange.Net/RateLimiting/LimitCheck.cs index 691d67f..678f963 100644 --- a/CryptoExchange.Net/RateLimiting/LimitCheck.cs +++ b/CryptoExchange.Net/RateLimiting/LimitCheck.cs @@ -45,7 +45,7 @@ namespace CryptoExchange.Net.RateLimiting /// /// No wait needed /// - public static LimitCheck NotNeeded { get; } = new LimitCheck(true, default, default, default, default); + public static LimitCheck NotNeeded(int limit, TimeSpan period, int current) => new(true, default, limit, period, current); /// /// Wait needed diff --git a/CryptoExchange.Net/RateLimiting/RateLimitEvent.cs b/CryptoExchange.Net/RateLimiting/RateLimitEvent.cs index 25331fe..c79e03e 100644 --- a/CryptoExchange.Net/RateLimiting/RateLimitEvent.cs +++ b/CryptoExchange.Net/RateLimiting/RateLimitEvent.cs @@ -4,10 +4,14 @@ using System; namespace CryptoExchange.Net.RateLimiting { /// - /// Rate limit event + /// Rate limit triggered event /// public record RateLimitEvent { + /// + /// Id of the item the limit was checked for + /// + public int ItemId { get; set; } /// /// Name of the API limit that is reached /// @@ -52,18 +56,9 @@ namespace CryptoExchange.Net.RateLimiting /// /// ctor /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public RateLimitEvent(string apiLimit, string limitDescription, RequestDefinition definition, string host, int current, int requestWeight, int? limit, TimeSpan? timePeriod, TimeSpan? delayTime, RateLimitingBehaviour behaviour) + public RateLimitEvent(int itemId, string apiLimit, string limitDescription, RequestDefinition definition, string host, int current, int requestWeight, int? limit, TimeSpan? timePeriod, TimeSpan? delayTime, RateLimitingBehaviour behaviour) { + ItemId = itemId; ApiLimit = apiLimit; LimitDescription = limitDescription; RequestDefinition = definition; diff --git a/CryptoExchange.Net/RateLimiting/RateLimitGate.cs b/CryptoExchange.Net/RateLimiting/RateLimitGate.cs index 60aaca5..4adb4a5 100644 --- a/CryptoExchange.Net/RateLimiting/RateLimitGate.cs +++ b/CryptoExchange.Net/RateLimiting/RateLimitGate.cs @@ -23,6 +23,8 @@ namespace CryptoExchange.Net.RateLimiting /// public event Action? RateLimitTriggered; + /// + public event Action? RateLimitUpdated; /// /// ctor @@ -105,7 +107,7 @@ namespace CryptoExchange.Net.RateLimiting else logger.RateLimitRequestFailed(itemId, definition.Path, guard.Name, guard.Description); - RateLimitTriggered?.Invoke(new RateLimitEvent(_name, guard.Description, definition, host, result.Current, requestWeight, result.Limit, result.Period, result.Delay, rateLimitingBehaviour)); + RateLimitTriggered?.Invoke(new RateLimitEvent(itemId, _name, guard.Description, definition, host, result.Current, requestWeight, result.Limit, result.Period, result.Delay, rateLimitingBehaviour)); return new CallResult(new ClientRateLimitError($"Rate limit check failed on guard {guard.Name}; {guard.Description}")); } @@ -120,7 +122,7 @@ namespace CryptoExchange.Net.RateLimiting else logger.RateLimitDelayingRequest(itemId, definition.Path, result.Delay, guard.Name, description); - RateLimitTriggered?.Invoke(new RateLimitEvent(_name, guard.Description, definition, host, result.Current, requestWeight, result.Limit, result.Period, result.Delay, rateLimitingBehaviour)); + RateLimitTriggered?.Invoke(new RateLimitEvent(itemId, _name, guard.Description, definition, host, result.Current, requestWeight, result.Limit, result.Period, result.Delay, rateLimitingBehaviour)); await Task.Delay((int)result.Delay.TotalMilliseconds + 1, ct).ConfigureAwait(false); await _semaphore.WaitAsync(ct).ConfigureAwait(false); return await CheckGuardsAsync(guards, logger, itemId, type, definition, host, apiKey, requestWeight, rateLimitingBehaviour, ct).ConfigureAwait(false); @@ -133,6 +135,8 @@ namespace CryptoExchange.Net.RateLimiting var result = guard.ApplyWeight(type, definition, host, apiKey, requestWeight); if (result.IsApplied) { + RateLimitUpdated?.Invoke(new RateLimitUpdateEvent(itemId, _name, guard.Description, result.Current, result.Limit, result.Period)); + if (type == RateLimitItemType.Connection) logger.RateLimitAppliedConnection(itemId, guard.Name, guard.Description, result.Current); else diff --git a/CryptoExchange.Net/RateLimiting/RateLimitUpdateEvent.cs b/CryptoExchange.Net/RateLimiting/RateLimitUpdateEvent.cs new file mode 100644 index 0000000..341b822 --- /dev/null +++ b/CryptoExchange.Net/RateLimiting/RateLimitUpdateEvent.cs @@ -0,0 +1,50 @@ +using CryptoExchange.Net.Objects; +using System; + +namespace CryptoExchange.Net.RateLimiting +{ + /// + /// Rate limit update event + /// + public record RateLimitUpdateEvent + { + /// + /// Id of the item the limit was checked for + /// + public int ItemId { get; set; } + /// + /// Name of the API limit that is reached + /// + public string ApiLimit { get; set; } = string.Empty; + /// + /// Description of the limit that is reached + /// + public string LimitDescription { get; set; } = string.Empty; + /// + /// The current counter value + /// + public int Current { get; set; } + /// + /// The limit per time period + /// + public int? Limit { get; set; } + /// + /// The time period the limit is for + /// + public TimeSpan? TimePeriod { get; set; } + + /// + /// ctor + /// + public RateLimitUpdateEvent(int itemId, string apiLimit, string limitDescription, int current, int? limit, TimeSpan? timePeriod) + { + ItemId = itemId; + ApiLimit = apiLimit; + LimitDescription = limitDescription; + Current = current; + Limit = limit; + TimePeriod = timePeriod; + } + + } +}