1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
|
local function validateParams(period, limit, ip_limit, expire) if not (tonumber(period) == 600 or tonumber(period) == 3600 or tonumber(period) == 86400) then return false end if not (tonumber(limit) and tonumber(ip_limit) and tonumber(expire)) then return false end return true end
local function setLimit(key, period, limit, ip_limit, expire) if not validateParams(period, limit, ip_limit, expire) then return 1 end local now = redis.call("TIME")[1] local user_key = "user:" .. key .. ":" .. period local ip_key = "ip:" .. key .. ":" .. period local user_count = tonumber(redis.call("GET", user_key) or "0") local ip_count = tonumber(redis.call("GET", ip_key) or "0") local user_expire = tonumber(redis.call("PTTL", user_key) or "-1") local ip_expire = tonumber(redis.call("PTTL", ip_key) or "-1")
if user_expire < 0 then redis.call("SETEX", user_key, expire, "0") end if ip_expire < 0 then redis.call("SETEX", ip_key, expire, "0") end
if user_count >= limit or ip_count >= ip_limit then return 0 end
local period_start = now - (now % period) local period_end = period_start + period
redis.call("MULTI") redis.call("INCR", user_key) redis.call("EXPIREAT", user_key, period_end) redis.call("INCR", ip_key) redis.call("EXPIREAT", ip_key, period_end)
local result = redis.call("EXEC") if tonumber(result[1]) > limit or tonumber(result[3]) > ip_limit then return 0 end
local total_count = user_count + ip_count + 1 if total_count > 500 then redis.call("EXPIRE", user_key, 60) redis.call("EXPIRE", ip_key, 60) end
return 1 end
redis.replicate_commands()
return setLimit(KEYS[1], ARGV[1], ARGV[2], ARGV[3], ARGV[4])
|