mirror of
https://github.com/ajayyy/SponsorBlockServer.git
synced 2025-12-19 14:09:06 +03:00
Merge pull request #156 from MRuy/147-add-cache-for-gettopusers
Add cache for getTopUsers
This commit is contained in:
@@ -23,6 +23,7 @@
|
|||||||
"readOnly": false,
|
"readOnly": false,
|
||||||
"webhooks": [],
|
"webhooks": [],
|
||||||
"categoryList": ["sponsor", "intro", "outro", "interaction", "selfpromo", "music_offtopic"], // List of supported categories any other category will be rejected
|
"categoryList": ["sponsor", "intro", "outro", "interaction", "selfpromo", "music_offtopic"], // List of supported categories any other category will be rejected
|
||||||
|
"getTopUsersCacheTimeMinutes": 5, // cacheTime for getTopUsers result in minutes
|
||||||
"maxNumberOfActiveWarnings": 3, // Users with this number of warnings will be blocked until warnings expire
|
"maxNumberOfActiveWarnings": 3, // Users with this number of warnings will be blocked until warnings expire
|
||||||
"hoursAfterWarningExpire": 24,
|
"hoursAfterWarningExpire": 24,
|
||||||
"rateLimit": {
|
"rateLimit": {
|
||||||
|
|||||||
@@ -1,34 +1,18 @@
|
|||||||
var db = require('../databases/databases.js').db;
|
var db = require('../databases/databases.js').db;
|
||||||
|
const logger = require('../utils/logger.js');
|
||||||
|
const createMemoryCache = require('../utils/createMemoryCache.js');
|
||||||
|
const config = require('../config.js');
|
||||||
|
|
||||||
module.exports = function getTopUsers (req, res) {
|
const MILLISECONDS_IN_MINUTE = 60000;
|
||||||
let sortType = req.query.sortType;
|
const getTopUsersWithCache = createMemoryCache(generateTopUsersStats, config.getTopUsersCacheTimeMinutes * MILLISECONDS_IN_MINUTE);
|
||||||
let categoryStatsEnabled = req.query.categoryStats;
|
|
||||||
|
|
||||||
if (sortType == undefined) {
|
function generateTopUsersStats(sortBy, categoryStatsEnabled = false) {
|
||||||
//invalid request
|
return new Promise((resolve, reject) => {
|
||||||
res.sendStatus(400);
|
const userNames = [];
|
||||||
return;
|
const viewCounts = [];
|
||||||
}
|
const totalSubmissions = [];
|
||||||
|
const minutesSaved = [];
|
||||||
//setup which sort type to use
|
const categoryStats = categoryStatsEnabled ? [] : undefined;
|
||||||
let sortBy = "";
|
|
||||||
if (sortType == 0) {
|
|
||||||
sortBy = "minutesSaved";
|
|
||||||
} else if (sortType == 1) {
|
|
||||||
sortBy = "viewCount";
|
|
||||||
} else if (sortType == 2) {
|
|
||||||
sortBy = "totalSubmissions";
|
|
||||||
} else {
|
|
||||||
//invalid request
|
|
||||||
res.sendStatus(400);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let userNames = [];
|
|
||||||
let viewCounts = [];
|
|
||||||
let totalSubmissions = [];
|
|
||||||
let minutesSaved = [];
|
|
||||||
let categoryStats = categoryStatsEnabled ? [] : undefined;
|
|
||||||
|
|
||||||
let additionalFields = '';
|
let additionalFields = '';
|
||||||
if (categoryStatsEnabled) {
|
if (categoryStatsEnabled) {
|
||||||
@@ -40,7 +24,7 @@ module.exports = function getTopUsers (req, res) {
|
|||||||
"SUM(CASE WHEN category = 'music_offtopic' THEN 1 ELSE 0 END) as categoryMusicOfftopic, ";
|
"SUM(CASE WHEN category = 'music_offtopic' THEN 1 ELSE 0 END) as categoryMusicOfftopic, ";
|
||||||
}
|
}
|
||||||
|
|
||||||
let rows = db.prepare('all', "SELECT COUNT(*) as totalSubmissions, SUM(views) as viewCount," +
|
const rows = db.prepare('all', "SELECT COUNT(*) as totalSubmissions, SUM(views) as viewCount," +
|
||||||
"SUM((sponsorTimes.endTime - sponsorTimes.startTime) / 60 * sponsorTimes.views) as minutesSaved, " +
|
"SUM((sponsorTimes.endTime - sponsorTimes.startTime) / 60 * sponsorTimes.views) as minutesSaved, " +
|
||||||
"SUM(votes) as userVotes, " +
|
"SUM(votes) as userVotes, " +
|
||||||
additionalFields +
|
additionalFields +
|
||||||
@@ -68,12 +52,41 @@ module.exports = function getTopUsers (req, res) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//send this result
|
resolve({
|
||||||
res.send({
|
|
||||||
userNames,
|
userNames,
|
||||||
viewCounts,
|
viewCounts,
|
||||||
totalSubmissions,
|
totalSubmissions,
|
||||||
minutesSaved,
|
minutesSaved,
|
||||||
categoryStats
|
categoryStats
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = async function getTopUsers (req, res) {
|
||||||
|
let sortType = req.query.sortType;
|
||||||
|
let categoryStatsEnabled = req.query.categoryStats;
|
||||||
|
|
||||||
|
if (sortType == undefined) {
|
||||||
|
//invalid request
|
||||||
|
res.sendStatus(400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//setup which sort type to use
|
||||||
|
let sortBy = '';
|
||||||
|
if (sortType == 0) {
|
||||||
|
sortBy = 'minutesSaved';
|
||||||
|
} else if (sortType == 1) {
|
||||||
|
sortBy = 'viewCount';
|
||||||
|
} else if (sortType == 2) {
|
||||||
|
sortBy = 'totalSubmissions';
|
||||||
|
} else {
|
||||||
|
//invalid request
|
||||||
|
return res.sendStatus(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
const stats = await getTopUsersWithCache(sortBy, categoryStatsEnabled);
|
||||||
|
|
||||||
|
//send this result
|
||||||
|
res.send(stats);
|
||||||
}
|
}
|
||||||
42
src/utils/createMemoryCache.js
Normal file
42
src/utils/createMemoryCache.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
module.exports = function createMemoryCache(memoryFn, cacheTimeMs) {
|
||||||
|
// holds the promise results
|
||||||
|
const cache = new Map();
|
||||||
|
// holds the promises that are not fulfilled
|
||||||
|
const promiseMemory = new Map();
|
||||||
|
return (...args) => {
|
||||||
|
// create cacheKey by joining arguments as string
|
||||||
|
const cacheKey = args.join('.');
|
||||||
|
// check if promising is already running
|
||||||
|
if (promiseMemory.has(cacheKey)) {
|
||||||
|
return promiseMemory.get(cacheKey);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// check if result is in cache
|
||||||
|
if (cache.has(cacheKey)) {
|
||||||
|
const cacheItem = cache.get(cacheKey);
|
||||||
|
const now = Date.now();
|
||||||
|
// check if cache is valid
|
||||||
|
if (!(cacheItem.cacheTime + cacheTimeMs < now)) {
|
||||||
|
return Promise.resolve(cacheItem.result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// create new promise
|
||||||
|
const promise = new Promise(async (resolve, reject) => {
|
||||||
|
resolve((await memoryFn(...args)));
|
||||||
|
});
|
||||||
|
// store promise reference until fulfilled
|
||||||
|
promiseMemory.set(cacheKey, promise);
|
||||||
|
return promise.then(result => {
|
||||||
|
// store promise result in cache
|
||||||
|
cache.set(cacheKey, {
|
||||||
|
result,
|
||||||
|
cacheTime: Date.now(),
|
||||||
|
});
|
||||||
|
// remove fulfilled promise from memory
|
||||||
|
promiseMemory.delete(cacheKey);
|
||||||
|
// return promise result
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user