Files
shields/lib/analytics.js
Paul Melnikow f271b82670 Nudge forward style checks a la eslint-config-standard (#1082)
Because I despise nitpicking stuff like indentation and spacing in pull request comments, I'd like to nudge forward our automated style checking, at least for new files being added.

I don't want to totally rewrite server.js just to get automated style checking… the blame tracking is just too useful. So let's it's just take care of that when we start splitting it out.

More discussion in #948.
2017-10-01 21:09:43 -04:00

118 lines
3.6 KiB
JavaScript

'use strict';
const fs = require('fs');
// We can either use a process-wide object regularly saved to a JSON file,
// or a Redis equivalent (for multi-process / when the filesystem is unreliable.
let redis;
let useRedis = false;
if (process.env.REDISTOGO_URL) {
const redisToGo = require('url').parse(process.env.REDISTOGO_URL);
redis = require('redis').createClient(redisToGo.port, redisToGo.hostname);
redis.auth(redisToGo.auth.split(':')[1]);
useRedis = true;
}
let analytics = {};
const analyticsAutoSaveFileName = process.env.SHIELDS_ANALYTICS_FILE || './analytics.json';
const analyticsAutoSavePeriod = 10000;
setInterval(function analyticsAutoSave() {
if (useRedis) {
redis.set(analyticsAutoSaveFileName, JSON.stringify(analytics));
} else {
fs.writeFileSync(analyticsAutoSaveFileName, JSON.stringify(analytics));
}
}, analyticsAutoSavePeriod);
function defaultAnalytics() {
const analytics = Object.create(null);
// In case something happens on the 36th.
analytics.vendorMonthly = new Array(36);
resetMonthlyAnalytics(analytics.vendorMonthly);
analytics.rawMonthly = new Array(36);
resetMonthlyAnalytics(analytics.rawMonthly);
analytics.vendorFlatMonthly = new Array(36);
resetMonthlyAnalytics(analytics.vendorFlatMonthly);
analytics.rawFlatMonthly = new Array(36);
resetMonthlyAnalytics(analytics.rawFlatMonthly);
analytics.vendorFlatSquareMonthly = new Array(36);
resetMonthlyAnalytics(analytics.vendorFlatSquareMonthly);
analytics.rawFlatSquareMonthly = new Array(36);
resetMonthlyAnalytics(analytics.rawFlatSquareMonthly);
return analytics;
}
// Auto-load analytics.
function analyticsAutoLoad() {
const defaultAnalyticsObject = defaultAnalytics();
if (useRedis) {
redis.get(analyticsAutoSaveFileName, function(err, value) {
if (err == null && value != null) {
// if/try/return trick:
// if error, then the rest of the function is run.
try {
analytics = JSON.parse(value);
// Extend analytics with a new value.
for (const key in defaultAnalyticsObject) {
if (!(key in analytics)) {
analytics[key] = defaultAnalyticsObject[key];
}
}
return;
} catch(e) {
console.error('Invalid Redis analytics, resetting.');
console.error(e);
}
}
analytics = defaultAnalyticsObject;
});
} else {
// Not using Redis.
try {
analytics = JSON.parse(fs.readFileSync(analyticsAutoSaveFileName));
// Extend analytics with a new value.
for (const key in defaultAnalyticsObject) {
if (!(key in analytics)) {
analytics[key] = defaultAnalyticsObject[key];
}
}
} catch(e) {
if (e.code !== 'ENOENT') {
console.error('Invalid JSON file for analytics, resetting.');
console.error(e);
}
analytics = defaultAnalyticsObject;
}
}
}
let lastDay = (new Date()).getDate();
function resetMonthlyAnalytics(monthlyAnalytics) {
for (let i = 0; i < monthlyAnalytics.length; i++) {
monthlyAnalytics[i] = 0;
}
}
function incrMonthlyAnalytics(monthlyAnalytics) {
try {
const currentDay = (new Date()).getDate();
// If we changed month, reset empty days.
while (lastDay !== currentDay) {
// Assumption: at least a hit a month.
lastDay = (lastDay + 1) % monthlyAnalytics.length;
monthlyAnalytics[lastDay] = 0;
}
monthlyAnalytics[currentDay]++;
} catch(e) { console.error(e.stack); }
}
function getAnalytics() {
return analytics;
}
module.exports = {
analyticsAutoLoad,
incrMonthlyAnalytics,
getAnalytics
};