public static async Task ProcessRateLimitedAsync(string redisId, ICacheClient cache, Func <Task <RestResponse> > t) { string key = $"discord:ratelimit:" + redisId; Ratelimit rateLimit = await cache.GetAsync <Ratelimit>(key); if (rateLimit != null) { rateLimit.Remaining--; await cache.UpsertAsync(key, rateLimit); } if (!IsRatelimited(rateLimit)) { var response = await t(); await HandleRateLimit(cache, response, rateLimit, key); } }
private static async Task HandleRateLimit(ICacheClient cache, RestResponse rc, Ratelimit ratelimit, string key) { if (!IsRatelimited(ratelimit)) { if (rc.HttpResponseMessage.Headers.Contains("X-RateLimit-Limit")) { ratelimit = new Ratelimit(); ratelimit.Remaining = int.Parse(rc.HttpResponseMessage.Headers.GetValues("X-RateLimit-Remaining").ToList().FirstOrDefault()); ratelimit.Limit = int.Parse(rc.HttpResponseMessage.Headers.GetValues("X-RateLimit-Limit").ToList().FirstOrDefault()); ratelimit.Reset = long.Parse(rc.HttpResponseMessage.Headers.GetValues("X-RateLimit-Reset").ToList().FirstOrDefault()); if (rc.HttpResponseMessage.Headers.Contains("X-RateLimit-Global")) { ratelimit.Global = int.Parse(rc.HttpResponseMessage.Headers.GetValues("X-RateLimit-Global").ToList().FirstOrDefault()); } await cache.UpsertAsync(key, ratelimit); } } }
/// <summary> /// Checks if the ratelimit is valid and/or is expired. /// </summary> /// <param name="rl">The instance that is being checked.</param> /// <returns>Whether the instance is being ratelimited</returns> public static bool IsRatelimited(Ratelimit rl) { return((rl.Global <= 0 || rl.Remaining <= 0) && DateTime.UtcNow <= DateTimeOffset.FromUnixTimeSeconds(rl.Reset)); }
private static bool IsRatelimited(Ratelimit rl) { return((rl?.Remaining ?? 1) <= 0 && DateTime.UtcNow <= DateTimeOffset.FromUnixTimeSeconds(rl?.Reset ?? 0)); }