40 lines
1.1 KiB
Lua
40 lines
1.1 KiB
Lua
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"
|