mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 08:36:12 +01:00
refactor: cleanup ip:recent
This commit is contained in:
@@ -41,9 +41,6 @@
|
||||
"sockets.default-placeholder": "Default: %1",
|
||||
"sockets.delay": "Reconnection Delay",
|
||||
|
||||
"analytics.settings": "Analytics Settings",
|
||||
"analytics.max-cache": "Analytics Cache Max Value",
|
||||
"analytics.max-cache-help": "On high-traffic installs, the cache could be exhausted continuously if there are more concurrent active users than the Max Cache value. (Restart required)",
|
||||
"compression.settings": "Compression Settings",
|
||||
"compression.enable": "Enable Compression",
|
||||
"compression.help": "This setting enables gzip compression. For a high-traffic website in production, the best way to put compression in place is to implement it at a reverse proxy level. You can enable it here for testing purposes."
|
||||
|
||||
@@ -18,6 +18,8 @@ get:
|
||||
latestVersion:
|
||||
type: string
|
||||
nullable: true
|
||||
hideAllTime:
|
||||
type: boolean
|
||||
upgradeAvailable:
|
||||
type: boolean
|
||||
nullable: true
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
const cronJob = require('cron').CronJob;
|
||||
const winston = require('winston');
|
||||
const nconf = require('nconf');
|
||||
const crypto = require('crypto');
|
||||
const util = require('util');
|
||||
const _ = require('lodash');
|
||||
|
||||
@@ -12,36 +11,24 @@ const sleep = util.promisify(setTimeout);
|
||||
const db = require('./database');
|
||||
const utils = require('./utils');
|
||||
const plugins = require('./plugins');
|
||||
const meta = require('./meta');
|
||||
const pubsub = require('./pubsub');
|
||||
const cacheCreate = require('./cache/lru');
|
||||
|
||||
const Analytics = module.exports;
|
||||
|
||||
const secret = nconf.get('secret');
|
||||
|
||||
let local = {
|
||||
counters: {},
|
||||
pageViews: 0,
|
||||
pageViewsRegistered: 0,
|
||||
pageViewsGuest: 0,
|
||||
pageViewsBot: 0,
|
||||
uniqueIPCount: 0,
|
||||
uniquevisitors: 0,
|
||||
};
|
||||
const empty = _.cloneDeep(local);
|
||||
const total = _.cloneDeep(local);
|
||||
|
||||
let ipCache;
|
||||
|
||||
const runJobs = nconf.get('runJobs');
|
||||
|
||||
Analytics.init = async function () {
|
||||
ipCache = cacheCreate({
|
||||
max: parseInt(meta.config['analytics:maxCache'], 10) || 500,
|
||||
ttl: 0,
|
||||
});
|
||||
|
||||
new cronJob('*/10 * * * * *', (async () => {
|
||||
publishLocalAnalytics();
|
||||
if (runJobs) {
|
||||
@@ -50,6 +37,14 @@ Analytics.init = async function () {
|
||||
}
|
||||
}), null, true);
|
||||
|
||||
if (runJobs) {
|
||||
new cronJob('*/30 * * * *', (async () => {
|
||||
const cutoff = Date.now() - 172800000;
|
||||
const ips = await db.getSortedSetRangeByScore('ip:recent', 0, 500, '-inf', cutoff);
|
||||
await db.sortedSetRemove('ip:recent', ips);
|
||||
}), null, true);
|
||||
}
|
||||
|
||||
if (runJobs) {
|
||||
pubsub.on('analytics:publish', (data) => {
|
||||
incrementProperties(total, data.local);
|
||||
@@ -106,22 +101,17 @@ Analytics.pageView = async function (payload) {
|
||||
}
|
||||
|
||||
if (payload.ip) {
|
||||
// Retrieve hash or calculate if not present
|
||||
let hash = ipCache.get(payload.ip + secret);
|
||||
if (!hash) {
|
||||
hash = crypto.createHash('sha1').update(payload.ip + secret).digest('hex');
|
||||
ipCache.set(payload.ip + secret, hash);
|
||||
const score = await db.sortedSetScore('ip:recent', payload.ip);
|
||||
let record = !score;
|
||||
if (score) {
|
||||
const today = new Date();
|
||||
today.setHours(today.getHours(), 0, 0, 0);
|
||||
record = score < today.getTime();
|
||||
}
|
||||
|
||||
const score = await db.sortedSetScore('ip:recent', hash);
|
||||
if (!score) {
|
||||
local.uniqueIPCount += 1;
|
||||
}
|
||||
const today = new Date();
|
||||
today.setHours(today.getHours(), 0, 0, 0);
|
||||
if (!score || score < today.getTime()) {
|
||||
if (record) {
|
||||
local.uniquevisitors += 1;
|
||||
await db.sortedSetAdd('ip:recent', Date.now(), hash);
|
||||
await db.sortedSetAdd('ip:recent', Date.now(), payload.ip);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -176,11 +166,6 @@ Analytics.writeData = async function () {
|
||||
total.uniquevisitors = 0;
|
||||
}
|
||||
|
||||
if (total.uniqueIPCount > 0) {
|
||||
dbQueue.push(db.incrObjectFieldBy('global', 'uniqueIPCount', total.uniqueIPCount));
|
||||
total.uniqueIPCount = 0;
|
||||
}
|
||||
|
||||
for (const [key, value] of Object.entries(total.counters)) {
|
||||
incrByBulk.push([`analytics:${key}`, value, today.getTime()]);
|
||||
metrics.push(key);
|
||||
|
||||
@@ -41,6 +41,7 @@ dashboardController.get = async function (req, res) {
|
||||
lastrestart: lastrestart,
|
||||
showSystemControls: isAdmin,
|
||||
popularSearches: popularSearches,
|
||||
hideAllTime: true,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -128,7 +129,7 @@ async function getStats() {
|
||||
}
|
||||
|
||||
let results = await Promise.all([
|
||||
getStatsFromAnalytics('uniquevisitors', 'uniqueIPCount'),
|
||||
getStatsFromAnalytics('uniquevisitors', ''),
|
||||
getStatsFromAnalytics('logins', 'loginCount'),
|
||||
getStatsForSet('users:joindate', 'userCount'),
|
||||
getStatsForSet('posts:pid', 'postCount'),
|
||||
@@ -227,6 +228,7 @@ function calculateDeltas(results) {
|
||||
}
|
||||
|
||||
async function getGlobalField(field) {
|
||||
if (!field) return 0;
|
||||
const count = await db.getObjectField('global', field);
|
||||
return parseInt(count, 10) || 0;
|
||||
}
|
||||
|
||||
@@ -1,31 +1,33 @@
|
||||
<div class="table-responsive mb-3">
|
||||
<table class="table text-sm">
|
||||
<thead>
|
||||
<table class="table">
|
||||
<thead class="text-xs">
|
||||
<tr>
|
||||
<th></th>
|
||||
<th class="text-end">[[admin/dashboard:stats.yesterday]]</th>
|
||||
<th class="text-end">[[admin/dashboard:stats.today]]</th>
|
||||
<th class="text-end text-nowrap">[[admin/dashboard:stats.yesterday]]</th>
|
||||
<th class="text-end text-nowrap">[[admin/dashboard:stats.today]]</th>
|
||||
<th></th>
|
||||
<th class="text-end">[[admin/dashboard:stats.last-week]]</th>
|
||||
<th class="text-end">[[admin/dashboard:stats.this-week]]</th>
|
||||
<th class="text-end text-nowrap">[[admin/dashboard:stats.last-week]]</th>
|
||||
<th class="text-end text-nowrap">[[admin/dashboard:stats.this-week]]</th>
|
||||
<th></th>
|
||||
<th class="text-end">[[admin/dashboard:stats.last-month]]</th>
|
||||
<th class="text-end">[[admin/dashboard:stats.this-month]]</th>
|
||||
<th class="text-end text-nowrap">[[admin/dashboard:stats.last-month]]</th>
|
||||
<th class="text-end text-nowrap">[[admin/dashboard:stats.this-month]]</th>
|
||||
<th></th>
|
||||
{{{ if !hideAllTime}}}
|
||||
<th class="text-end">[[admin/dashboard:stats.all]]</th>
|
||||
{{{ end }}}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tbody class="text-sm">
|
||||
{{{ each stats }}}
|
||||
<tr>
|
||||
<td>
|
||||
<strong>
|
||||
<td class="fw-bold text-nowrap">
|
||||
|
||||
{{{ if ./href }}}
|
||||
<a href="{./href}">{./name}</a>
|
||||
{{{ else }}}
|
||||
{./name}
|
||||
{{{ end }}}
|
||||
</strong>
|
||||
|
||||
</td>
|
||||
<td class="text-end">{formattedNumber(./yesterday)}</td>
|
||||
<td class="text-end">{formattedNumber(./today)}</td>
|
||||
@@ -38,8 +40,9 @@
|
||||
<td class="text-end">{formattedNumber(./lastmonth)}</td>
|
||||
<td class="text-end">{formattedNumber(./thismonth)}</td>
|
||||
<td class="{./monthTextClass}"><small>{./monthIncrease}%</small></td>
|
||||
|
||||
{{{ if !hideAllTime}}}
|
||||
<td class="text-end">{formattedNumber(./alltime)}</td>
|
||||
{{{ end }}}
|
||||
</tr>
|
||||
{{{ end }}}
|
||||
</tbody>
|
||||
|
||||
@@ -146,20 +146,6 @@
|
||||
|
||||
<hr/>
|
||||
|
||||
<div id="analytics-settings" class="mb-4">
|
||||
<h5 class="fw-bold tracking-tight settings-header">[[admin/settings/advanced:analytics.settings]]</h5>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="analytics:maxCache">[[admin/settings/advanced:analytics.max-cache]]</label>
|
||||
<input class="form-control" id="analytics:maxCache" type="text" value="500" placeholder="500" data-field="analytics:maxCache" />
|
||||
<p class="form-text">
|
||||
[[admin/settings/advanced:analytics.max-cache-help]]
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div id="compression-settings" class="mb-4">
|
||||
<h5 class="fw-bold tracking-tight settings-header">[[admin/settings/advanced:compression.settings]]</h5>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user