Skip to content

Instantly share code, notes, and snippets.

@andris9
Created September 22, 2016 12:49
Show Gist options
  • Save andris9/5edc847fa261d69b88edbc2e9d78708d to your computer and use it in GitHub Desktop.
Save andris9/5edc847fa261d69b88edbc2e9d78708d to your computer and use it in GitHub Desktop.
Simple in-memory session handler
/* eslint-env es6 */
'use strict';
const EventEmitter = require('events');
const crypto = require('crypto');
class Session extends EventEmitter {
constructor() {
super();
this.timer = false;
this.sessions = new Map();
this.ttl = [];
}
create(id, data, ttl) {
id = id || crypto.randomBytes(10).toString('hex');
ttl = Number(ttl) || false;
let exists = this.sessions.has(id);
this.sessions.set(id, {
id,
data,
ttl
});
if (ttl) {
this.updateTTL(id, ttl);
}
this.emit(exists ? 'updated' : 'created', id, data);
return id;
}
check(id) {
if (!this.sessions.has(id)) {
return false;
}
let data = this.sessions.get(id).data;
let ttl = this.sessions.get(id).ttl;
if (!ttl) {
return data;
}
this.updateTTL(id, ttl);
return data;
}
updateTTL(id, ttl) {
let nextTimeout = Date.now() + ttl;
let checks = 2;
for (let i = this.ttl.length - 1; i >= 0; i--) {
if (this.ttl[i].id === id) {
// remove existing
this.ttl.splice(i, 1);
if (--checks === 0) {
break;
}
} else if (this.ttl[i].timeout < nextTimeout) {
// add new
this.ttl.splice(i + 1, 0, {
timeout: nextTimeout,
id
});
nextTimeout = false;
if (--checks === 0) {
break;
}
}
}
if (nextTimeout) {
// we have a new closest TTL
clearTimeout(this.timer);
this.ttl.unshift({
timeout: nextTimeout,
id
});
this.timer = setTimeout(() => this.checkTTL(), ttl + 10);
}
}
checkTTL() {
clearTimeout(this.timer);
let remove = 0;
let time = Date.now();
for (let i = 0, len = this.ttl.length; i < len; i++) {
if (this.ttl[i].timeout <= time) {
this.emit('expired', this.ttl[i].id, this.sessions.get(this.ttl[i].id));
this.sessions.delete(this.ttl[i].id);
remove++;
} else {
break;
}
}
if (remove) {
this.ttl.splice(0, remove);
}
if (this.ttl.length) {
this.timer = setTimeout(() => this.checkTTL(), this.ttl[0].timeout + 10);
}
}
}
module.exports = Session;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment