public RateLimitCounter ProcessRequest(ClientRequestIdentity requestIdentity, RateLimitOptions option) { RateLimitCounter counter = new RateLimitCounter(DateTime.UtcNow, 1); var rule = option.RateLimitRule; var counterId = ComputeCounterKey(requestIdentity, option); // serial reads and writes lock (_processLocker) { var entry = _counterHandler.Get(counterId); if (entry.HasValue) { // entry has not expired if (entry.Value.Timestamp + TimeSpan.FromSeconds(rule.PeriodTimespan) >= DateTime.UtcNow) { // increment request count var totalRequests = entry.Value.TotalRequests + 1; // deep copy counter = new RateLimitCounter(entry.Value.Timestamp, totalRequests); } } // stores: id (string) - timestamp (datetime) - total_requests (long) _counterHandler.Set(counterId, counter, TimeSpan.FromSeconds(rule.PeriodTimespan)); } return(counter); }
public RateLimitResult Process(ClientRequestIdentity clientRequestIdentity, RateLimitPolicy rateLimitPolicy, CancellationToken cancellationToken) { if (clientRequestIdentity == null) { throw new ArgumentNullException(nameof(clientRequestIdentity)); } if (rateLimitPolicy == null) { return(RateLimitResult.NoLimit("no rate limit policy.")); } if (rateLimitPolicy.ClientIsRequired && string.IsNullOrWhiteSpace(clientRequestIdentity.ClientId)) { return(RateLimitResult.Limited("client id is required.")); } if (rateLimitPolicy.IsWhitelisted(clientRequestIdentity, out RateLimitNameListPolicyMatchedResult result)) { return(RateLimitResult.NoLimit(result.ToString())); } var matchedRules = rateLimitPolicy.GetMatchedRules(clientRequestIdentity); if (matchedRules != null && matchedRules.Any()) { lock (o_lock) { var rulesDict = new Dictionary <string, Tuple <RateLimitRule, RateLimitCounter> >(); foreach (var rule in matchedRules) { if (rule.Limit > 0) { var counterKey = ComputeCounterKey(rule); var counter = GetCounter(counterKey, rule); // check if key expired if (counter.Timestamp + rule.PeriodTimespan.Value < DateTime.UtcNow) { continue; } // check if limit is reached if (counter.Count > rule.Limit) { return(RateLimitResult.Limited(rule.ToString())); } rulesDict.Add(counterKey, Tuple.Create(rule, counter)); } else { return(RateLimitResult.Limited(rule.ToString())); } } if (rulesDict.Any()) { foreach (var item in rulesDict) { _rateLimitCounterHandler.Set(item.Key, item.Value.Item2, item.Value.Item1.PeriodTimespan.Value); } } } } return(RateLimitResult.Default); }
public RateLimitCounter ProcessRequest(ClientRequestIdentity requestIdentity, RateLimitOptions option) { RateLimitCounter counter = new RateLimitCounter(DateTime.UtcNow, 1); var rule = option.RateLimitRule; var counterId = ComputeCounterKey(requestIdentity, option); // serial reads and writes lock (_processLocker) { var entry = _counterHandler.Get(counterId); if (entry.HasValue) { // entry has not expired if (entry.Value.Timestamp + TimeSpan.FromSeconds(rule.PeriodTimespan) >= DateTime.UtcNow) { // increment request count var totalRequests = entry.Value.TotalRequests + 1; // deep copy counter = new RateLimitCounter(entry.Value.Timestamp, totalRequests); } } } if (counter.TotalRequests > rule.Limit) { var retryAfter = RetryAfterFrom(counter.Timestamp, rule); if (retryAfter > 0) { var expirationTime = TimeSpan.FromSeconds(rule.PeriodTimespan); _counterHandler.Set(counterId, counter, expirationTime); } else { _counterHandler.Remove(counterId); } } else { var expirationTime = ConvertToTimeSpan(rule.Period); _counterHandler.Set(counterId, counter, expirationTime); } return(counter); }