67 lines
2.0 KiB
JavaScript
67 lines
2.0 KiB
JavaScript
const redis = require('redis');
|
|
|
|
module.exports = (config, onConnect, onError) => {
|
|
const client = config['modules']['hit_counter'] ? redis.createClient(config['redis']) : { connected: false, on: () => { /* ignore */ } };
|
|
|
|
client.on('connect', onConnect);
|
|
client.on('error', onError);
|
|
|
|
const visitors = {};
|
|
|
|
const count = (req, path, disable, cb) => {
|
|
if (!client.connected || disable) {
|
|
cb();
|
|
} else {
|
|
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
|
|
visitors[path] = (visitors[path] || {});
|
|
const now = Date.now();
|
|
const isNewVisitor = (now - (visitors[path][ip] || 0)) > config['hit_counter']['unique_visitor_timeout'];
|
|
visitors[path][ip] = now;
|
|
client
|
|
.multi()
|
|
.hincrby(path, 'h', 1)
|
|
.hincrby(path, 'v', isNewVisitor ? 1 : 0)
|
|
.exec(cb);
|
|
}
|
|
};
|
|
|
|
const cleanVisitors = (path) => {
|
|
visitors[path] = (visitors[path] || {});
|
|
const now = Date.now();
|
|
let count = 0;
|
|
for (let ip in visitors[path]) {
|
|
if ((now - visitors[path][ip]) > config['hit_counter']['unique_visitor_timeout']) {
|
|
delete visitors[path][ip];
|
|
} else {
|
|
count++;
|
|
}
|
|
}
|
|
return count;
|
|
};
|
|
|
|
const read = (path, cb) => {
|
|
if (!client.connected) {
|
|
cb({
|
|
path: path,
|
|
hits: 0,
|
|
total_visitors: 0,
|
|
current_visitors: cleanVisitors(path),
|
|
});
|
|
} else {
|
|
client.hgetall(path, (_, value) => {
|
|
cb({
|
|
path: path,
|
|
hits: value ? parseInt(value.h) || 0 : 0,
|
|
total_visitors: value ? parseInt(value.v) || 0 : 0,
|
|
current_visitors: cleanVisitors(path),
|
|
});
|
|
});
|
|
}
|
|
};
|
|
|
|
return {
|
|
count: count,
|
|
read: read,
|
|
};
|
|
};
|