mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-08-27 14:25:34 +02:00
Merge pull request #2343 from mikiher/caching
Simple API Caching for /libraries* requests
This commit is contained in:
@@ -32,13 +32,13 @@ const PodcastManager = require('./managers/PodcastManager')
|
||||
const AudioMetadataMangaer = require('./managers/AudioMetadataManager')
|
||||
const RssFeedManager = require('./managers/RssFeedManager')
|
||||
const CronManager = require('./managers/CronManager')
|
||||
const ApiCacheManager = require('./managers/ApiCacheManager')
|
||||
const LibraryScanner = require('./scanner/LibraryScanner')
|
||||
|
||||
//Import the main Passport and Express-Session library
|
||||
const passport = require('passport')
|
||||
const expressSession = require('express-session')
|
||||
|
||||
|
||||
class Server {
|
||||
constructor(SOURCE, PORT, HOST, UID, GID, CONFIG_PATH, METADATA_PATH, ROUTER_BASE_PATH) {
|
||||
this.Port = PORT
|
||||
@@ -73,6 +73,7 @@ class Server {
|
||||
this.audioMetadataManager = new AudioMetadataMangaer()
|
||||
this.rssFeedManager = new RssFeedManager()
|
||||
this.cronManager = new CronManager(this.podcastManager)
|
||||
this.apiCacheManager = new ApiCacheManager()
|
||||
|
||||
// Routers
|
||||
this.apiRouter = new ApiRouter(this)
|
||||
@@ -117,6 +118,7 @@ class Server {
|
||||
|
||||
const libraries = await Database.libraryModel.getAllOldLibraries()
|
||||
await this.cronManager.init(libraries)
|
||||
this.apiCacheManager.init()
|
||||
|
||||
if (Database.serverSettings.scannerDisableWatcher) {
|
||||
Logger.info(`[Server] Watcher is disabled`)
|
||||
|
@@ -192,9 +192,9 @@ class SocketAuthority {
|
||||
|
||||
this.adminEmitter('user_online', client.user.toJSONForPublic(this.Server.playbackSessionManager.sessions))
|
||||
|
||||
// Update user lastSeen
|
||||
// Update user lastSeen without firing sequelize bulk update hooks
|
||||
user.lastSeen = Date.now()
|
||||
await Database.updateUser(user)
|
||||
await Database.userModel.updateFromOld(user, false)
|
||||
|
||||
const initialPayload = {
|
||||
userId: client.user.id,
|
||||
|
54
server/managers/ApiCacheManager.js
Normal file
54
server/managers/ApiCacheManager.js
Normal file
@@ -0,0 +1,54 @@
|
||||
const { LRUCache } = require('lru-cache')
|
||||
const Logger = require('../Logger')
|
||||
const Database = require('../Database')
|
||||
|
||||
class ApiCacheManager {
|
||||
|
||||
defaultCacheOptions = { max: 1000, maxSize: 10 * 1000 * 1000, sizeCalculation: item => (item.body.length + JSON.stringify(item.headers).length) }
|
||||
defaultTtlOptions = { ttl: 30 * 60 * 1000 }
|
||||
|
||||
constructor(cache = new LRUCache(this.defaultCacheOptions), ttlOptions = this.defaultTtlOptions) {
|
||||
this.cache = cache
|
||||
this.ttlOptions = ttlOptions
|
||||
}
|
||||
|
||||
init(database = Database) {
|
||||
let hooks = ['afterCreate', 'afterUpdate', 'afterDestroy', 'afterBulkCreate', 'afterBulkUpdate', 'afterBulkDestroy']
|
||||
hooks.forEach(hook => database.sequelize.addHook(hook, (model) => this.clear(model, hook)))
|
||||
}
|
||||
|
||||
clear(model, hook) {
|
||||
Logger.debug(`[ApiCacheManager] ${model.constructor.name}.${hook}: Clearing cache`)
|
||||
this.cache.clear()
|
||||
}
|
||||
|
||||
get middleware() {
|
||||
return (req, res, next) => {
|
||||
const key = { user: req.user.username, url: req.url }
|
||||
const stringifiedKey = JSON.stringify(key)
|
||||
Logger.debug(`[ApiCacheManager] count: ${this.cache.size} size: ${this.cache.calculatedSize}`)
|
||||
const cached = this.cache.get(stringifiedKey)
|
||||
if (cached) {
|
||||
Logger.debug(`[ApiCacheManager] Cache hit: ${stringifiedKey}`)
|
||||
res.set(cached.headers)
|
||||
res.status(cached.statusCode)
|
||||
res.send(cached.body)
|
||||
return
|
||||
}
|
||||
res.originalSend = res.send
|
||||
res.send = (body) => {
|
||||
Logger.debug(`[ApiCacheManager] Cache miss: ${stringifiedKey}`)
|
||||
const cached = { body, headers: res.getHeaders(), statusCode: res.statusCode }
|
||||
if (key.url.search(/^\/libraries\/.*?\/personalized/) !== -1) {
|
||||
Logger.debug(`[ApiCacheManager] Caching with ${this.ttlOptions.ttl} ms TTL`)
|
||||
this.cache.set(stringifiedKey, cached, this.ttlOptions)
|
||||
} else {
|
||||
this.cache.set(stringifiedKey, cached)
|
||||
}
|
||||
res.originalSend(body)
|
||||
}
|
||||
next()
|
||||
}
|
||||
}
|
||||
}
|
||||
module.exports = ApiCacheManager
|
@@ -99,11 +99,13 @@ class User extends Model {
|
||||
* Update User from old user model
|
||||
*
|
||||
* @param {oldUser} oldUser
|
||||
* @param {boolean} [hooks=true] Run before / after bulk update hooks?
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
static updateFromOld(oldUser) {
|
||||
static updateFromOld(oldUser, hooks = true) {
|
||||
const user = this.getFromOld(oldUser)
|
||||
return this.update(user, {
|
||||
hooks: !!hooks,
|
||||
where: {
|
||||
id: user.id
|
||||
}
|
||||
|
@@ -48,6 +48,7 @@ class ApiRouter {
|
||||
this.cronManager = Server.cronManager
|
||||
this.notificationManager = Server.notificationManager
|
||||
this.emailManager = Server.emailManager
|
||||
this.apiCacheManager = Server.apiCacheManager
|
||||
|
||||
this.router = express()
|
||||
this.router.disable('x-powered-by')
|
||||
@@ -58,6 +59,7 @@ class ApiRouter {
|
||||
//
|
||||
// Library Routes
|
||||
//
|
||||
this.router.get(/^\/libraries/, this.apiCacheManager.middleware)
|
||||
this.router.post('/libraries', LibraryController.create.bind(this))
|
||||
this.router.get('/libraries', LibraryController.findAll.bind(this))
|
||||
this.router.get('/libraries/:id', LibraryController.middleware.bind(this), LibraryController.findOne.bind(this))
|
||||
|
Reference in New Issue
Block a user