From 34e02a23e7f88f74ea566f01e636d390534bef37 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 12 Apr 2021 13:19:11 +0530 Subject: [PATCH] deduplicate server code for caching rendered API endpoints --- server.js | 152 +++++++++++++++++++++--------------------------------- 1 file changed, 59 insertions(+), 93 deletions(-) diff --git a/server.js b/server.js index 62e144efa..36ca1a425 100644 --- a/server.js +++ b/server.js @@ -201,46 +201,14 @@ app.use("/customize.dist", Express.static(__dirname + '/customize.dist')); app.use(/^\/[^\/]*$/, Express.static('customize')); app.use(/^\/[^\/]*$/, Express.static('customize.dist')); -var serveConfig = (function () { - // if dev mode: never cache - var cacheString = function () { - return (Env.FRESH_KEY? '-' + Env.FRESH_KEY: '') + (Env.DEV_MODE? '-' + (+new Date()): ''); - }; - - var template = function (host) { - return [ - 'define(function(){', - 'var obj = ' + JSON.stringify({ - requireConf: { - waitSeconds: 600, - urlArgs: 'ver=' + Package.version + cacheString(), - }, - removeDonateButton: (config.removeDonateButton === true), - allowSubscriptions: (config.allowSubscriptions === true), - websocketPath: config.externalWebsocketURL, - httpUnsafeOrigin: config.httpUnsafeOrigin, - adminEmail: Env.adminEmail, - adminKeys: Env.admins, - inactiveTime: Env.inactiveTime, - supportMailbox: Env.supportMailbox, - defaultStorageLimit: Env.defaultStorageLimit, - maxUploadSize: Env.maxUploadSize, - premiumUploadSize: Env.premiumUploadSize, - }, null, '\t'), - 'obj.httpSafeOrigin = ' + (function () { - if (config.httpSafeOrigin) { return '"' + config.httpSafeOrigin + '"'; } - if (config.httpSafePort) { - return "(function () { return window.location.origin.replace(/\:[0-9]+$/, ':" + - config.httpSafePort + "'); }())"; - } - return 'window.location.origin'; - }()), - 'return obj', - '});' - ].join(';\n') - }; +// if dev mode: never cache +var cacheString = function () { + return (Env.FRESH_KEY? '-' + Env.FRESH_KEY: '') + (Env.DEV_MODE? '-' + (+new Date()): ''); +}; +var makeRouteCache = function (template, cacheName) { var cleanUp = {}; + var cache = Env[cacheName] = Env[cacheName] || {}; return function (req, res) { var host = req.headers.host.replace(/\:[0-9]+/, ''); @@ -255,73 +223,71 @@ var serveConfig = (function () { // FIXME mutable // we must be able to clear the cache when updating any mutable key // if there's nothing cached for that key... - if (!Env.configCache[cacheKey]) { + if (!cache[cacheKey]) { // generate the response and cache it in memory - Env.configCache[cacheKey] = template(host); + cache[cacheKey] = template(host); // and create a function to conditionally evict cache entries // which have not been accessed in the last 20 seconds cleanUp[cacheKey] = Util.throttle(function () { delete cleanUp[cacheKey]; - delete Env.configCache[cacheKey]; + delete cache[cacheKey]; }, 20000); } // successive calls to this function cleanUp[cacheKey](); - return void res.send(Env.configCache[cacheKey]); - }; -}()); - -var serveBroadcast = (function () { // XXX deduplicate - var cacheString = function () { - return (Env.FRESH_KEY? '-' + Env.FRESH_KEY: '') + (Env.DEV_MODE? '-' + (+new Date()): ''); - }; - - var template = function (host) { - var maintenance = Env.maintenance; - if (maintenance && maintenance.end && maintenance.end < (+new Date())) { - maintenance = undefined; - } - return [ - 'define(function(){', // XXX maybe this could just be JSON - 'return ' + JSON.stringify({ - lastBroadcastHash: Env.lastBroadcastHash, - surveyURL: Env.surveyURL, - maintenance: maintenance - }, null, '\t'), - '});' - ].join(';\n') + return void res.send(cache[cacheKey]); }; +}; - var cleanUp = {}; - - return function (req, res) { - var host = req.headers.host.replace(/\:[0-9]+/, ''); - res.setHeader('Content-Type', 'text/javascript'); - // don't cache anything if you're in dev mode - if (Env.DEV_MODE) { - return void res.send(template(host)); - } - // generate a lookup key for the cache - var cacheKey = host + ':' + cacheString(); - - // XXX do we need a cache for /api/broadcast? - if (!Env.broadcastCache[cacheKey]) { - // generate the response and cache it in memory - Env.broadcastCache[cacheKey] = template(host); - // and create a function to conditionally evict cache entries - // which have not been accessed in the last 20 seconds - cleanUp[cacheKey] = Util.throttle(function () { - delete cleanUp[cacheKey]; - delete Env.broadcastCache[cacheKey]; - }, 20000); - } - - // successive calls to this function - cleanUp[cacheKey](); - return void res.send(Env.broadcastCache[cacheKey]); - }; -}()); +var serveConfig = makeRouteCache(function (host) { + return [ + 'define(function(){', + 'var obj = ' + JSON.stringify({ + requireConf: { + waitSeconds: 600, + urlArgs: 'ver=' + Package.version + cacheString(), + }, + removeDonateButton: (config.removeDonateButton === true), + allowSubscriptions: (config.allowSubscriptions === true), + websocketPath: config.externalWebsocketURL, + httpUnsafeOrigin: config.httpUnsafeOrigin, + adminEmail: Env.adminEmail, + adminKeys: Env.admins, + inactiveTime: Env.inactiveTime, + supportMailbox: Env.supportMailbox, + defaultStorageLimit: Env.defaultStorageLimit, + maxUploadSize: Env.maxUploadSize, + premiumUploadSize: Env.premiumUploadSize, + }, null, '\t'), + 'obj.httpSafeOrigin = ' + (function () { + if (config.httpSafeOrigin) { return '"' + config.httpSafeOrigin + '"'; } + if (config.httpSafePort) { + return "(function () { return window.location.origin.replace(/\:[0-9]+$/, ':" + + config.httpSafePort + "'); }())"; + } + return 'window.location.origin'; + }()), + 'return obj', + '});' + ].join(';\n') +}, 'configCache'); + +var serveBroadcast = makeRouteCache(function (host) { + var maintenance = Env.maintenance; + if (maintenance && maintenance.end && maintenance.end < (+new Date())) { + maintenance = undefined; + } + return [ + 'define(function(){', + 'return ' + JSON.stringify({ + lastBroadcastHash: Env.lastBroadcastHash, + surveyURL: Env.surveyURL, + maintenance: maintenance + }, null, '\t'), + '});' + ].join(';\n') +}, 'broadcastCache'); app.get('/api/config', serveConfig); app.get('/api/broadcast', serveBroadcast);