2024-08-04 19:00:10 +02:00
|
|
|
/*!
|
|
|
|
* memorystore
|
|
|
|
* Copyright(c) 2020 Rocco Musolino <@roccomuso>
|
|
|
|
* MIT Licensed
|
|
|
|
*/
|
|
|
|
//
|
|
|
|
// modified for audiobookshelf (update to lru-cache 10)
|
|
|
|
// SOURCE: https://github.com/roccomuso/memorystore
|
|
|
|
//
|
|
|
|
|
2024-08-19 10:17:54 +02:00
|
|
|
const debug = require('debug')('memorystore')
|
2024-08-04 19:00:10 +02:00
|
|
|
const { LRUCache } = require('lru-cache')
|
2024-08-19 10:17:54 +02:00
|
|
|
const { Store } = require('express-session')
|
2024-08-04 19:00:10 +02:00
|
|
|
|
|
|
|
/**
|
2024-08-19 10:17:54 +02:00
|
|
|
* An alternative memory store implementation for express session that prunes stale entries.
|
2024-08-04 19:00:10 +02:00
|
|
|
*
|
2024-08-19 10:17:54 +02:00
|
|
|
* @param {number} checkPeriod stale entry pruning frequency in ms
|
|
|
|
* @param {number} ttl entry time to live in ms
|
|
|
|
* @param {number} max LRU cache max entries
|
2024-08-04 19:00:10 +02:00
|
|
|
*/
|
2024-08-19 10:17:54 +02:00
|
|
|
module.exports = class MemoryStore extends Store {
|
|
|
|
constructor(checkPeriod, ttl, max) {
|
2024-08-27 23:53:18 +02:00
|
|
|
if (typeof checkPeriod !== 'number' || typeof ttl !== 'number' || typeof max !== 'number') {
|
2024-08-19 10:17:54 +02:00
|
|
|
throw Error('All arguments must be provided')
|
2024-08-04 19:00:10 +02:00
|
|
|
}
|
2024-08-19 10:17:54 +02:00
|
|
|
super()
|
|
|
|
this.store = new LRUCache({ ttl, max })
|
|
|
|
let prune = () => {
|
|
|
|
let sizeBefore = this.store.size
|
|
|
|
this.store.purgeStale()
|
|
|
|
debug('PRUNE size changed by %i entries', sizeBefore - this.store.size)
|
|
|
|
}
|
|
|
|
setInterval(prune, Math.floor(checkPeriod)).unref()
|
|
|
|
debug('INIT MemoryStore constructed with checkPeriod "%i", ttl "%i", max "%i"', checkPeriod, ttl, max)
|
2024-08-04 19:00:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Attempt to fetch session by the given `sid`.
|
|
|
|
*
|
|
|
|
* @param {String} sid
|
|
|
|
* @param {Function} fn
|
|
|
|
* @api public
|
|
|
|
*/
|
2024-08-19 10:17:54 +02:00
|
|
|
get(sid, fn) {
|
|
|
|
let err = null
|
|
|
|
let res = null
|
|
|
|
const data = this.store.get(sid)
|
|
|
|
debug('GET %s: %s', sid, data)
|
|
|
|
if (data) {
|
|
|
|
try {
|
|
|
|
res = JSON.parse(data)
|
|
|
|
} catch (e) {
|
|
|
|
err = e
|
|
|
|
}
|
2024-08-04 19:00:10 +02:00
|
|
|
}
|
2024-08-19 10:17:54 +02:00
|
|
|
fn && setImmediate(fn, err, res)
|
2024-08-04 19:00:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Commit the given `sess` object associated with the given `sid`.
|
|
|
|
*
|
|
|
|
* @param {String} sid
|
|
|
|
* @param {Session} sess
|
|
|
|
* @param {Function} fn
|
|
|
|
* @api public
|
|
|
|
*/
|
2024-08-19 10:17:54 +02:00
|
|
|
set(sid, sess, fn) {
|
|
|
|
let err = null
|
2024-08-04 19:00:10 +02:00
|
|
|
try {
|
2024-08-19 10:17:54 +02:00
|
|
|
let jsess = JSON.stringify(sess)
|
|
|
|
debug('SET %s: %s', sid, jsess)
|
|
|
|
this.store.set(sid, jsess)
|
|
|
|
} catch (e) {
|
|
|
|
err = e
|
2024-08-04 19:00:10 +02:00
|
|
|
}
|
2024-08-19 10:17:54 +02:00
|
|
|
fn && setImmediate(fn, err)
|
2024-08-04 19:00:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Destroy the session associated with the given `sid`.
|
|
|
|
*
|
|
|
|
* @param {String} sid
|
2024-08-19 10:17:54 +02:00
|
|
|
* @param {Function} fn
|
2024-08-04 19:00:10 +02:00
|
|
|
* @api public
|
|
|
|
*/
|
2024-08-19 10:17:54 +02:00
|
|
|
destroy(sid, fn) {
|
|
|
|
debug('DESTROY %s', sid)
|
|
|
|
let err = null
|
|
|
|
try {
|
|
|
|
this.store.delete(sid)
|
|
|
|
} catch (e) {
|
|
|
|
err = e
|
2024-08-04 19:00:10 +02:00
|
|
|
}
|
2024-08-19 10:17:54 +02:00
|
|
|
fn && setImmediate(fn, err)
|
2024-08-04 19:00:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2024-08-19 10:17:54 +02:00
|
|
|
* Refresh the time-to-live for the session with the given `sid` without affecting
|
|
|
|
* LRU recency.
|
2024-08-04 19:00:10 +02:00
|
|
|
*
|
|
|
|
* @param {String} sid
|
|
|
|
* @param {Session} sess
|
|
|
|
* @param {Function} fn
|
|
|
|
* @api public
|
|
|
|
*/
|
|
|
|
|
2024-08-19 10:17:54 +02:00
|
|
|
touch(sid, sess, fn) {
|
|
|
|
debug('TOUCH %s', sid)
|
|
|
|
let err = null
|
2024-08-04 19:00:10 +02:00
|
|
|
try {
|
2024-08-19 10:17:54 +02:00
|
|
|
this.store.has(sid, { updateAgeOnHas: true })
|
2024-08-04 19:00:10 +02:00
|
|
|
} catch (e) {
|
|
|
|
err = e
|
|
|
|
}
|
2024-08-19 10:17:54 +02:00
|
|
|
fn && setImmediate(fn, err)
|
2024-08-04 19:00:10 +02:00
|
|
|
}
|
|
|
|
}
|