koa-generic-session = function (options) {
options = options || {};
let key = options.key || 'koa.sid';
let client = options.store || new MemoryStore();
let errorHandler = options.errorHandler || defaultErrorHanlder;
let reconnectTimeout = options.reconnectTimeout || 10000;
let store = new Store(client, {
ttl: options.ttl,
prefix: options.prefix
});
let genSid = options.genSid || uid.sync;
let valid = options.valid || noop;
let beforeSave = options.beforeSave || noop;
let cookie = options.cookie || {};
copy(defaultCookie).to(cookie);
let storeStatus = 'available';
let waitStore = Promise.resolve();
// notify user that this store is not
// meant for a production environment
if ('production' === process.env.NODE_ENV
&& client instanceof MemoryStore) console.warn(warning);
let sessionIdStore = options.sessionIdStore || {
get: function() {
return this.cookies.get(key, cookie);
},
set: function(sid, session) {
this.cookies.set(key, sid, session.cookie);
},
reset: function() {
this.cookies.set(key, null);
}
};
store.on('disconnect', function() {
if (storeStatus !== 'available') return;
storeStatus = 'pending';
waitStore = new Promise(function (resolve, reject) {
setTimeout(function () {
if (storeStatus === 'pending') storeStatus = 'unavailable';
reject(new Error('session store is unavailable'));
}, reconnectTimeout);
store.once('connect', resolve);
});
});
store.on('connect', function() {
storeStatus = 'available';
waitStore = Promise.resolve();
});
// save empty session hash for compare
const EMPTY_SESSION_HASH = hash(generateSession());
return options.defer ? deferSession : session;
function addCommonAPI() {
this._sessionSave = null;
// more flexible
this.__defineGetter__('sessionSave', function () {
return this._sessionSave;
});
this.__defineSetter__('sessionSave', function (save) {
this._sessionSave = save;
});
}
/**
* generate a new session
*/
function generateSession() {
let session = {};
//you can alter the cookie options in nexts
session.cookie = {};
for (let prop in cookie) {
session.cookie[prop] = cookie[prop];
}
compatMaxage(session.cookie);
return session;
}
/**
* check url match cookie's path
*/
function matchPath(ctx) {
let pathname = parse(ctx).pathname;
let cookiePath = cookie.path || '/';
if (cookiePath === '/') {
return true;
}
if (pathname.indexOf(cookiePath) !== 0) {
debug('cookie path not match');
return false;
}
return true;
}
/**
* get session from store
* get sessionId from cookie
* save sessionId into context
* get session from store
*/
function *getSession() {
if (!matchPath(this)) return;
if (storeStatus === 'pending') {
debug('store is disconnect and pending');
yield waitStore;
} else if (storeStatus === 'unavailable') {
debug('store is unavailable');
throw new Error('session store is unavailable');
}
if (!this.sessionId) {
this.sessionId = sessionIdStore.get.call(this);
}
let session;
let isNew = false;
if (!this.sessionId) {
debug('session id not exist, generate a new one');
session = generateSession();
this.sessionId = genSid.call(this, 24);
isNew = true;
} else {
try {
session = yield store.get(this.sessionId);
debug('get session %j with key %s', session, this.sessionId);
} catch (err) {
if (err.code === 'ENOENT') {
debug('get session error, code = ENOENT');
} else {
debug('get session error: ', err.message);
errorHandler(err, 'get', this);
}
}
}
// make sure the session is still valid
if (!session ||
!valid(this, session)) {
debug('session is empty or invalid');
session = generateSession();
this.sessionId = genSid.call(this, 24);
sessionIdStore.re ...
n/a
MemoryStore = function () { this.sessions = {}; }
n/a
index = function (options) {
options = options || {};
let key = options.key || 'koa.sid';
let client = options.store || new MemoryStore();
let errorHandler = options.errorHandler || defaultErrorHanlder;
let reconnectTimeout = options.reconnectTimeout || 10000;
let store = new Store(client, {
ttl: options.ttl,
prefix: options.prefix
});
let genSid = options.genSid || uid.sync;
let valid = options.valid || noop;
let beforeSave = options.beforeSave || noop;
let cookie = options.cookie || {};
copy(defaultCookie).to(cookie);
let storeStatus = 'available';
let waitStore = Promise.resolve();
// notify user that this store is not
// meant for a production environment
if ('production' === process.env.NODE_ENV
&& client instanceof MemoryStore) console.warn(warning);
let sessionIdStore = options.sessionIdStore || {
get: function() {
return this.cookies.get(key, cookie);
},
set: function(sid, session) {
this.cookies.set(key, sid, session.cookie);
},
reset: function() {
this.cookies.set(key, null);
}
};
store.on('disconnect', function() {
if (storeStatus !== 'available') return;
storeStatus = 'pending';
waitStore = new Promise(function (resolve, reject) {
setTimeout(function () {
if (storeStatus === 'pending') storeStatus = 'unavailable';
reject(new Error('session store is unavailable'));
}, reconnectTimeout);
store.once('connect', resolve);
});
});
store.on('connect', function() {
storeStatus = 'available';
waitStore = Promise.resolve();
});
// save empty session hash for compare
const EMPTY_SESSION_HASH = hash(generateSession());
return options.defer ? deferSession : session;
function addCommonAPI() {
this._sessionSave = null;
// more flexible
this.__defineGetter__('sessionSave', function () {
return this._sessionSave;
});
this.__defineSetter__('sessionSave', function (save) {
this._sessionSave = save;
});
}
/**
* generate a new session
*/
function generateSession() {
let session = {};
//you can alter the cookie options in nexts
session.cookie = {};
for (let prop in cookie) {
session.cookie[prop] = cookie[prop];
}
compatMaxage(session.cookie);
return session;
}
/**
* check url match cookie's path
*/
function matchPath(ctx) {
let pathname = parse(ctx).pathname;
let cookiePath = cookie.path || '/';
if (cookiePath === '/') {
return true;
}
if (pathname.indexOf(cookiePath) !== 0) {
debug('cookie path not match');
return false;
}
return true;
}
/**
* get session from store
* get sessionId from cookie
* save sessionId into context
* get session from store
*/
function *getSession() {
if (!matchPath(this)) return;
if (storeStatus === 'pending') {
debug('store is disconnect and pending');
yield waitStore;
} else if (storeStatus === 'unavailable') {
debug('store is unavailable');
throw new Error('session store is unavailable');
}
if (!this.sessionId) {
this.sessionId = sessionIdStore.get.call(this);
}
let session;
let isNew = false;
if (!this.sessionId) {
debug('session id not exist, generate a new one');
session = generateSession();
this.sessionId = genSid.call(this, 24);
isNew = true;
} else {
try {
session = yield store.get(this.sessionId);
debug('get session %j with key %s', session, this.sessionId);
} catch (err) {
if (err.code === 'ENOENT') {
debug('get session error, code = ENOENT');
} else {
debug('get session error: ', err.message);
errorHandler(err, 'get', this);
}
}
}
// make sure the session is still valid
if (!session ||
!valid(this, session)) {
debug('session is empty or invalid');
session = generateSession();
this.sessionId = genSid.call(this, 24);
sessionIdStore.re ...
n/a
function Store(client, options) { this.client = client; this.options = {}; copy(options).and(defaultOptions).to(this.options); EventEmitter.call(this); // delegate client connect / disconnect event if (typeof client.on === 'function') { client.on('disconnect', this.emit.bind(this, 'disconnect')); client.on('connect', this.emit.bind(this, 'connect')); } }
n/a
MemoryStore = function () { this.sessions = {}; }
n/a
function* (sid) { delete this.sessions[sid]; }
...
}
//delete session
if (!session) {
if (!isNew) {
debug('session set to null, destroy session: %s', this.sessionId);
sessionIdStore.reset.call(this);
return yield store.destroy(this.sessionId);
}
return debug('a new session and set to null, ignore destroy');
}
// force saving non-empty session
if(this._sessionSave === true) {
debug('session save forced');
...
function* (sid) { debug('get value %j with key %s', this.sessions[sid], sid); return this.sessions[sid]; }
...
// meant for a production environment
if ('production' === process.env.NODE_ENV
&& client instanceof MemoryStore) console.warn(warning);
let sessionIdStore = options.sessionIdStore || {
get: function() {
return this.cookies.get(key, cookie);
},
set: function(sid, session) {
this.cookies.set(key, sid, session.cookie);
},
reset: function() {
...
function* (sid, val) { debug('set value %j for key %s', val, sid); this.sessions[sid] = val; }
...
let sessionIdStore = options.sessionIdStore || {
get: function() {
return this.cookies.get(key, cookie);
},
set: function(sid, session) {
this.cookies.set(key, sid, session.cookie);
},
reset: function() {
this.cookies.set(key, null);
}
};
...
index = function (options) {
options = options || {};
let key = options.key || 'koa.sid';
let client = options.store || new MemoryStore();
let errorHandler = options.errorHandler || defaultErrorHanlder;
let reconnectTimeout = options.reconnectTimeout || 10000;
let store = new Store(client, {
ttl: options.ttl,
prefix: options.prefix
});
let genSid = options.genSid || uid.sync;
let valid = options.valid || noop;
let beforeSave = options.beforeSave || noop;
let cookie = options.cookie || {};
copy(defaultCookie).to(cookie);
let storeStatus = 'available';
let waitStore = Promise.resolve();
// notify user that this store is not
// meant for a production environment
if ('production' === process.env.NODE_ENV
&& client instanceof MemoryStore) console.warn(warning);
let sessionIdStore = options.sessionIdStore || {
get: function() {
return this.cookies.get(key, cookie);
},
set: function(sid, session) {
this.cookies.set(key, sid, session.cookie);
},
reset: function() {
this.cookies.set(key, null);
}
};
store.on('disconnect', function() {
if (storeStatus !== 'available') return;
storeStatus = 'pending';
waitStore = new Promise(function (resolve, reject) {
setTimeout(function () {
if (storeStatus === 'pending') storeStatus = 'unavailable';
reject(new Error('session store is unavailable'));
}, reconnectTimeout);
store.once('connect', resolve);
});
});
store.on('connect', function() {
storeStatus = 'available';
waitStore = Promise.resolve();
});
// save empty session hash for compare
const EMPTY_SESSION_HASH = hash(generateSession());
return options.defer ? deferSession : session;
function addCommonAPI() {
this._sessionSave = null;
// more flexible
this.__defineGetter__('sessionSave', function () {
return this._sessionSave;
});
this.__defineSetter__('sessionSave', function (save) {
this._sessionSave = save;
});
}
/**
* generate a new session
*/
function generateSession() {
let session = {};
//you can alter the cookie options in nexts
session.cookie = {};
for (let prop in cookie) {
session.cookie[prop] = cookie[prop];
}
compatMaxage(session.cookie);
return session;
}
/**
* check url match cookie's path
*/
function matchPath(ctx) {
let pathname = parse(ctx).pathname;
let cookiePath = cookie.path || '/';
if (cookiePath === '/') {
return true;
}
if (pathname.indexOf(cookiePath) !== 0) {
debug('cookie path not match');
return false;
}
return true;
}
/**
* get session from store
* get sessionId from cookie
* save sessionId into context
* get session from store
*/
function *getSession() {
if (!matchPath(this)) return;
if (storeStatus === 'pending') {
debug('store is disconnect and pending');
yield waitStore;
} else if (storeStatus === 'unavailable') {
debug('store is unavailable');
throw new Error('session store is unavailable');
}
if (!this.sessionId) {
this.sessionId = sessionIdStore.get.call(this);
}
let session;
let isNew = false;
if (!this.sessionId) {
debug('session id not exist, generate a new one');
session = generateSession();
this.sessionId = genSid.call(this, 24);
isNew = true;
} else {
try {
session = yield store.get(this.sessionId);
debug('get session %j with key %s', session, this.sessionId);
} catch (err) {
if (err.code === 'ENOENT') {
debug('get session error, code = ENOENT');
} else {
debug('get session error: ', err.message);
errorHandler(err, 'get', this);
}
}
}
// make sure the session is still valid
if (!session ||
!valid(this, session)) {
debug('session is empty or invalid');
session = generateSession();
this.sessionId = genSid.call(this, 24);
sessionIdStore.re ...
n/a
MemoryStore = function () { this.sessions = {}; }
n/a
function Store(client, options) { this.client = client; this.options = {}; copy(options).and(defaultOptions).to(this.options); EventEmitter.call(this); // delegate client connect / disconnect event if (typeof client.on === 'function') { client.on('disconnect', this.emit.bind(this, 'disconnect')); client.on('connect', this.emit.bind(this, 'connect')); } }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
function* (sid) { sid = this.options.prefix + sid; debug('DEL %s', sid); yield this.client.destroy(sid); debug('DEL %s complete', sid); }
...
}
//delete session
if (!session) {
if (!isNew) {
debug('session set to null, destroy session: %s', this.sessionId);
sessionIdStore.reset.call(this);
return yield store.destroy(this.sessionId);
}
return debug('a new session and set to null, ignore destroy');
}
// force saving non-empty session
if(this._sessionSave === true) {
debug('session save forced');
...
function* (sid) { var data; sid = this.options.prefix + sid; debug('GET %s', sid); data = yield this.client.get(sid); if (!data) { debug('GET empty'); return null; } if (data && data.cookie && typeof data.cookie.expires === 'string') { // make sure data.cookie.expires is a Date data.cookie.expires = new Date(data.cookie.expires); } debug('GOT %j', data); return data; }
...
// meant for a production environment
if ('production' === process.env.NODE_ENV
&& client instanceof MemoryStore) console.warn(warning);
let sessionIdStore = options.sessionIdStore || {
get: function() {
return this.cookies.get(key, cookie);
},
set: function(sid, session) {
this.cookies.set(key, sid, session.cookie);
},
reset: function() {
...
function* (sid, sess) { var ttl = this.options.ttl; if (!ttl) { var maxAge = sess.cookie && sess.cookie.maxAge; if (typeof maxAge === 'number') { ttl = maxAge; } // if has cookie.expires, ignore cookie.maxAge if (sess.cookie && sess.cookie.expires) { ttl = Math.ceil(sess.cookie.expires.getTime() - Date.now()); } } sid = this.options.prefix + sid; debug('SET key: %s, value: %s, ttl: %d', sid, sess, ttl); yield this.client.set(sid, sess, ttl); debug('SET complete'); }
...
let sessionIdStore = options.sessionIdStore || {
get: function() {
return this.cookies.get(key, cookie);
},
set: function(sid, session) {
this.cookies.set(key, sid, session.cookie);
},
reset: function() {
this.cookies.set(key, null);
}
};
...