all files / modules/middleware/session/ MemoryStore.js

85.11% Statements 40/47
73.08% Branches 19/26
77.78% Functions 7/9
85.11% Lines 40/47
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113                                                                                                         11× 11×     11× 10×     11×   11×                                
const d = require("describe-property");
const makeToken = require("../../utils/makeToken");
const Promise = require("../../utils/Promise");
 
const {forEach, keys} = require("ramda");
 
function makeUniqueKey(sessions, keyLength) {
    let key;
    do {
        key = makeToken(keyLength);
    } while (sessions[key]);
 
    return key;
}
 
function pruneStore(store, interval) {
    const timer = setInterval(function () {
        const now = Date.now();
 
        let session;
        forEach(function (key) {
            session = store.sessions[key];
 
            if (session._expiry && session._expiry < now) {
                store.purge(key);
            }
        }, keys(store.sessions));
    }, interval);
 
  // Don't let this timer keep the event loop running.
    timer.unref();
 
    return timer;
}
 
/**
 * Basic server-side storage for sessions that exist within a single process.
 * This should never be used in production, but can be useful in development
 * and testing scenarios when there is only a single server instance.
 *
 * Accepts the following options:
 *
 * - keyLength        The length (in bytes) that will be used for unique cache keys.
 *                    Defaults to 32
 * - purgeInterval    The interval (in milliseconds) at which the cache is
 *                    purged of expired sessions. Defaults to 5000
 * - expireAfter      The number of seconds after which sessions expire.
 *                    Defaults to 0 (no expiration)
 */
function MemoryStore(options) {
    options = options || {};
 
    this.sessions = {};
    this.timer = pruneStore(this, options.purgeInterval || 5000);
    this.keyLength = options.keyLength || 32;
    this.ttl = options.expireAfter
    ? 1000 * options.expireAfter // expireAfter is given in seconds
    : 0;
}
 
Object.defineProperties(MemoryStore.prototype, {
 
    load: d(function (value) {
        const session = this.sessions[value];
 
        if (!session) {
            return Promise.resolve({});
        }
 
    // Verify the session is not expired.
        if (session._expiry && session._expiry <= Date.now()) {
            return Promise.resolve({});
        }
 
        return Promise.resolve(session);
    }),
 
    save: d(function (session) {
        let key = session._id;
        if (!key) {
            key = session._id = makeUniqueKey(this.sessions, this.keyLength);
        }
 
        if (this.ttl) {
            session._expiry = Date.now() + this.ttl;
        }
 
        this.sessions[key] = session;
 
        return Promise.resolve(key);
    }),
 
    purge: d(function (key) {
        Iif (key) {
            delete this.sessions[key];
        } else {
            this.sessions = {};
        }
    }),
 
    destroy: d(function () {
        delete this.sessions;
 
        Eif (this.timer) {
            clearInterval(this.timer);
            delete this.timer;
        }
    })
 
});
 
module.exports = MemoryStore;