local key = KEYS[1] local window_ms = tonumber(ARGV[1]) local global_limit = tonumber(ARGV[2]) local per_key_limit = tonumber(ARGV[3]) local client_field = ARGV[4] local redis_time = redis.call("TIME") local now_ms = tonumber(redis_time[1]) * 1000 + math.floor(tonumber(redis_time[2]) / 1000) local window_id = math.floor(now_ms / window_ms) local stored_window = redis.call("HGET", key, "window") if not stored_window or tonumber(stored_window) ~= window_id then redis.call("DEL", key) redis.call("HSET", key, "window", window_id) end if global_limit > 0 then local global_used = tonumber(redis.call("HGET", key, "global") or "0") if global_used >= global_limit then return "global" end end if per_key_limit > 0 then local client_used = tonumber(redis.call("HGET", key, client_field) or "0") if client_used >= per_key_limit then return "per_key" end end if global_limit > 0 then redis.call("HINCRBY", key, "global", 1) end if per_key_limit > 0 then redis.call("HINCRBY", key, client_field, 1) end redis.call("PEXPIREAT", key, (window_id + 1) * window_ms) return "ok"