local key = KEYS[1] local rate, burst = tonumber(ARGV[1]), tonumber(ARGV[2]) local now, duration = tonumber(ARGV[3]), tonumber(ARGV[4])
local excess, last, forbidden = 0, 0, 0
local res = redis.pcall('GET', key) iftype(res) == "table"and res.err then return {err=res.err} end
if res andtype(res) == "string"then local v = cjson.decode(res) if v and #v > 2then excess, last, forbidden = v[1], v[2], v[3] end
if forbidden == 1then return {3, excess} -- FORBIDDEN end
local ms = math.abs(now - last) excess = excess - rate * ms / 1000 + 1000
if excess < 0then excess = 0 end
if excess > burst then if duration > 0then local res = redis.pcall('SET', key, cjson.encode({excess, now, 1})) iftype(res) == "table"and res.err then return {err=res.err} end
local res = redis.pcall('EXPIRE', key, duration) iftype(res) == "table"and res.err then return {err=res.err} end end
return {2, excess} -- BUSY end end
local res = redis.pcall('SET', key, cjson.encode({excess, now, 0})) iftype(res) == "table"and res.err then return {err=res.err} end
local res = redis.pcall('EXPIRE', key, 60) iftype(res) == "table"and res.err then return {err=res.err} end
local ms = math.abs(now - last) excess = excess - rate * ms / 1000 + 1000
if excess < 0then excess = 0 end
if excess > burst then if duration > 0then local res = redis.pcall('SET', key, cjson.encode({excess, now, 1})) iftype(res) == "table"and res.err then return {err=res.err} end
local res = redis.pcall('EXPIRE', key, duration) iftype(res) == "table"and res.err then return {err=res.err} end end