2017-05-02 21:17:37 +08:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
const Scripty = require('node-redis-scripty');
|
|
|
|
|
2017-07-18 16:17:36 +08:00
|
|
|
const ttlCounterScript = `
|
|
|
|
local key = KEYS[1];
|
2017-05-02 21:17:37 +08:00
|
|
|
local increment = tonumber(ARGV[1]) or 0;
|
|
|
|
local limit = tonumber(ARGV[2]) or 0;
|
2017-07-18 16:17:36 +08:00
|
|
|
local current = tonumber(redis.call("GET", key)) or 0;
|
2017-05-02 21:17:37 +08:00
|
|
|
|
|
|
|
if current >= limit then
|
2017-07-18 16:17:36 +08:00
|
|
|
local ttl = tonumber(redis.call("TTL", key)) or 0;
|
2017-05-02 21:17:37 +08:00
|
|
|
return {0, current, ttl};
|
|
|
|
end;
|
|
|
|
|
2017-07-18 16:17:36 +08:00
|
|
|
local updated = tonumber(redis.call("INCRBY", key, increment));
|
2017-05-02 21:17:37 +08:00
|
|
|
if current == 0 then
|
2017-07-18 16:17:36 +08:00
|
|
|
redis.call("EXPIRE", key, 86400);
|
2017-05-02 21:17:37 +08:00
|
|
|
end;
|
|
|
|
|
2017-07-18 16:17:36 +08:00
|
|
|
local ttl = tonumber(redis.call("TTL", key)) or 0;
|
2017-05-02 21:17:37 +08:00
|
|
|
|
|
|
|
return {1, updated, ttl};
|
|
|
|
`;
|
|
|
|
|
2017-07-18 16:17:36 +08:00
|
|
|
const cachedCounterScript = `
|
|
|
|
local key = KEYS[1];
|
|
|
|
local increment = tonumber(ARGV[1]) or 0;
|
|
|
|
local ttl = tonumber(ARGV[2]) or 0;
|
|
|
|
|
|
|
|
if redis.call("EXISTS", key) == 1 then
|
|
|
|
redis.call("INCRBY", key, increment);
|
2017-07-20 21:42:08 +08:00
|
|
|
local sum = tonumber(redis.call("GET", key)) or 0;
|
2017-07-18 16:17:36 +08:00
|
|
|
-- extend the life of this counter by ttl seconds
|
|
|
|
redis.call("EXPIRE", key, ttl);
|
2017-07-20 21:42:08 +08:00
|
|
|
return sum;
|
2017-07-18 16:17:36 +08:00
|
|
|
else
|
|
|
|
return nil;
|
|
|
|
end
|
|
|
|
`;
|
|
|
|
|
2017-05-02 21:17:37 +08:00
|
|
|
module.exports = redis => {
|
|
|
|
let scripty = new Scripty(redis);
|
|
|
|
|
|
|
|
return {
|
|
|
|
ttlcounter(key, count, max, callback) {
|
2017-07-18 16:17:36 +08:00
|
|
|
scripty.loadScript('ttlcounter', ttlCounterScript, (err, script) => {
|
2017-05-02 21:17:37 +08:00
|
|
|
if (err) {
|
|
|
|
return callback(err);
|
|
|
|
}
|
|
|
|
script.run(1, key, count, max, (err, res) => {
|
|
|
|
if (err) {
|
|
|
|
return callback(err);
|
|
|
|
}
|
|
|
|
return callback(null, {
|
2017-06-03 14:51:58 +08:00
|
|
|
success: !!((res && res[0]) || 0),
|
|
|
|
value: (res && res[1]) || 0,
|
|
|
|
ttl: (res && res[2]) || 0
|
2017-05-02 21:17:37 +08:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2017-07-18 16:17:36 +08:00
|
|
|
},
|
|
|
|
|
|
|
|
cachedcounter(key, count, ttl, callback) {
|
|
|
|
scripty.loadScript('cachedCounter', cachedCounterScript, (err, script) => {
|
|
|
|
if (err) {
|
|
|
|
return callback(err);
|
|
|
|
}
|
2017-07-20 21:42:08 +08:00
|
|
|
|
|
|
|
script.run(
|
|
|
|
1,
|
|
|
|
key,
|
|
|
|
count,
|
|
|
|
ttl,
|
|
|
|
(
|
|
|
|
err,
|
|
|
|
res => {
|
|
|
|
if (err) {
|
|
|
|
return callback(err);
|
|
|
|
}
|
|
|
|
callback(null, res);
|
|
|
|
}
|
|
|
|
)
|
|
|
|
);
|
2017-07-18 16:17:36 +08:00
|
|
|
});
|
2017-05-02 21:17:37 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|