2023-11-17 07:47:40 +01:00
|
|
|
const { LRUCache } = require('lru-cache')
|
|
|
|
const Logger = require('../Logger')
|
2023-11-22 17:40:42 +01:00
|
|
|
const Database = require('../Database')
|
2023-11-17 07:47:40 +01:00
|
|
|
|
|
|
|
class ApiCacheManager {
|
2023-11-23 08:53:52 +01:00
|
|
|
|
2023-11-25 22:49:56 +01:00
|
|
|
defaultCacheOptions = { max: 1000, maxSize: 10 * 1000 * 1000, sizeCalculation: item => (item.body.length + JSON.stringify(item.headers).length) }
|
2023-11-23 08:53:52 +01:00
|
|
|
defaultTtlOptions = { ttl: 30 * 60 * 1000 }
|
|
|
|
|
|
|
|
constructor(cache = new LRUCache(this.defaultCacheOptions), ttlOptions = this.defaultTtlOptions) {
|
|
|
|
this.cache = cache
|
|
|
|
this.ttlOptions = ttlOptions
|
2023-11-17 07:47:40 +01:00
|
|
|
}
|
|
|
|
|
2023-11-22 17:40:42 +01:00
|
|
|
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()
|
2023-11-17 07:47:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
get middleware() {
|
|
|
|
return (req, res, next) => {
|
2023-11-22 17:40:42 +01:00
|
|
|
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}`)
|
2023-11-25 22:49:56 +01:00
|
|
|
res.set(cached.headers)
|
|
|
|
res.status(cached.statusCode)
|
|
|
|
res.send(cached.body)
|
2023-11-22 17:40:42 +01:00
|
|
|
return
|
|
|
|
}
|
2023-11-23 08:53:52 +01:00
|
|
|
res.originalSend = res.send
|
2023-11-22 17:40:42 +01:00
|
|
|
res.send = (body) => {
|
|
|
|
Logger.debug(`[ApiCacheManager] Cache miss: ${stringifiedKey}`)
|
2023-11-25 22:49:56 +01:00
|
|
|
const cached = { body, headers: res.getHeaders(), statusCode: res.statusCode }
|
2023-11-22 17:40:42 +01:00
|
|
|
if (key.url.search(/^\/libraries\/.*?\/personalized/) !== -1) {
|
2023-11-23 08:53:52 +01:00
|
|
|
Logger.debug(`[ApiCacheManager] Caching with ${this.ttlOptions.ttl} ms TTL`)
|
2023-11-25 22:49:56 +01:00
|
|
|
this.cache.set(stringifiedKey, cached, this.ttlOptions)
|
2023-11-22 17:40:42 +01:00
|
|
|
} else {
|
2023-11-25 22:49:56 +01:00
|
|
|
this.cache.set(stringifiedKey, cached)
|
2023-11-17 07:47:40 +01:00
|
|
|
}
|
2023-11-23 08:53:52 +01:00
|
|
|
res.originalSend(body)
|
2023-11-22 17:40:42 +01:00
|
|
|
}
|
|
|
|
next()
|
2023-11-17 07:47:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
module.exports = ApiCacheManager
|