diff --git a/.idea/dbnavigator.xml b/.idea/dbnavigator.xml
new file mode 100644
index 0000000..fb39777
--- /dev/null
+++ b/.idea/dbnavigator.xml
@@ -0,0 +1,452 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..c6cc8c8
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..28a804d
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..7867bfc
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/session.iml b/.idea/session.iml
new file mode 100644
index 0000000..24643cc
--- /dev/null
+++ b/.idea/session.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000..a1c457a
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,549 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ debug
+ uid
+ Symbol
+ ContextSession
+ externalKey
+ commit
+ commit|commit
+ save
+ ContextSession|ContextSession
+ sessionOptions
+ cookie
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+ false
+ true
+
+
+ true
+ DEFINITION_ORDER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1513734560993
+
+
+ 1513734560993
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/index.js b/index.js
index b095060..2c26c51 100644
--- a/index.js
+++ b/index.js
@@ -20,31 +20,36 @@ const _CONTEXT_SESSION = Symbol('context#_contextSession');
* @param {Application} app, koa application instance
* @api public
*/
-
-module.exports = function(opts, app) {
- // session(app[, opts])
- if (opts && typeof opts.use === 'function') {
- [ app, opts ] = [ opts, app ];
- }
- // app required
- if (!app || typeof app.use !== 'function') {
- throw new TypeError('app instance required: `session(opts, app)`');
- }
-
- opts = formatOpts(opts);
- extendContext(app.context, opts);
-
- return async function session(ctx, next) {
- const sess = ctx[CONTEXT_SESSION];
- if (sess.store) await sess.initFromExternal();
- try {
- await next();
- } catch (err) {
- throw err;
- } finally {
- await sess.commit();
+//TODO opts是中间件的config,app是服务器
+module.exports = function (opts, app) {
+ // session(app[, opts])
+ //TODO hook,防止用户参数写反了
+ if (opts && typeof opts.use === 'function') {
+ [app, opts] = [opts, app];
}
- };
+ // app required
+ //TODO 报错
+ if (!app || typeof app.use !== 'function') {
+ throw new TypeError('app instance required: `session(opts, app)`');
+ }
+ //TODO 把设置格式化
+ opts = formatOpts(opts);
+ //TODO 获取接口
+ extendContext(app.context, opts);
+ //TODO 返回中间件
+ return async function session(ctx, next) {
+ const sess = ctx[CONTEXT_SESSION];
+ //TODO 如果是缓存层的
+ if (sess.store) await sess.initFromExternal();
+ try {
+ await next();
+ } catch (err) {
+ throw err;
+ //TODO 无论什么结果都会执行
+ } finally {
+ await sess.commit();
+ }
+ };
};
/**
@@ -56,49 +61,50 @@ module.exports = function(opts, app) {
*/
function formatOpts(opts) {
- opts = opts || {};
- // key
- opts.key = opts.key || 'koa:sess';
-
- // back-compat maxage
- if (!('maxAge' in opts)) opts.maxAge = opts.maxage;
+ opts = opts || {};
+ // key
+ opts.key = opts.key || 'koa:sess';
- // defaults
- if (opts.overwrite == null) opts.overwrite = true;
- if (opts.httpOnly == null) opts.httpOnly = true;
- if (opts.signed == null) opts.signed = true;
+ // back-compat maxage
+ if (!('maxAge' in opts)) opts.maxAge = opts.maxage;
- debug('session options %j', opts);
+ // defaults
+ if (opts.overwrite == null) opts.overwrite = true;
+ if (opts.httpOnly == null) opts.httpOnly = true;
+ if (opts.signed == null) opts.signed = true;
- // setup encoding/decoding
- if (typeof opts.encode !== 'function') {
- opts.encode = util.encode;
- }
- if (typeof opts.decode !== 'function') {
- opts.decode = util.decode;
- }
+ debug('session options %j', opts);
- const store = opts.store;
- if (store) {
- assert(is.function(store.get), 'store.get must be function');
- assert(is.function(store.set), 'store.set must be function');
- assert(is.function(store.destroy), 'store.destroy must be function');
- }
+ // setup encoding/decoding
+ //TODO encode和decode的函数
+ if (typeof opts.encode !== 'function') {
+ opts.encode = util.encode;
+ }
+ if (typeof opts.decode !== 'function') {
+ opts.decode = util.decode;
+ }
- const ContextStore = opts.ContextStore;
- if (ContextStore) {
- assert(is.class(ContextStore), 'ContextStore must be a class');
- assert(is.function(ContextStore.prototype.get), 'ContextStore.prototype.get must be function');
- assert(is.function(ContextStore.prototype.set), 'ContextStore.prototype.set must be function');
- assert(is.function(ContextStore.prototype.destroy), 'ContextStore.prototype.destroy must be function');
- }
+ const store = opts.store;
+ if (store) {
+ assert(is.function(store.get), 'store.get must be function');
+ assert(is.function(store.set), 'store.set must be function');
+ assert(is.function(store.destroy), 'store.destroy must be function');
+ }
- if (!opts.genid) {
- if (opts.prefix) opts.genid = () => opts.prefix + uid.sync(24);
- else opts.genid = () => uid.sync(24);
- }
+ const ContextStore = opts.ContextStore;
+ if (ContextStore) {
+ assert(is.class(ContextStore), 'ContextStore must be a class');
+ assert(is.function(ContextStore.prototype.get), 'ContextStore.prototype.get must be function');
+ assert(is.function(ContextStore.prototype.set), 'ContextStore.prototype.set must be function');
+ assert(is.function(ContextStore.prototype.destroy), 'ContextStore.prototype.destroy must be function');
+ }
+ //TODO 生成genid的函数
+ if (!opts.genid) {
+ if (opts.prefix) opts.genid = () => opts.prefix + uid.sync(24);
+ else opts.genid = () => uid.sync(24);
+ }
- return opts;
+ return opts;
}
/**
@@ -111,27 +117,27 @@ function formatOpts(opts) {
*/
function extendContext(context, opts) {
- Object.defineProperties(context, {
- [CONTEXT_SESSION]: {
- get() {
- if (this[_CONTEXT_SESSION]) return this[_CONTEXT_SESSION];
- this[_CONTEXT_SESSION] = new ContextSession(this, opts);
- return this[_CONTEXT_SESSION];
- },
- },
- session: {
- get() {
- return this[CONTEXT_SESSION].get();
- },
- set(val) {
- this[CONTEXT_SESSION].set(val);
- },
- configurable: true,
- },
- sessionOptions: {
- get() {
- return this[CONTEXT_SESSION].opts;
- },
- },
- });
+ Object.defineProperties(context, {
+ [CONTEXT_SESSION]: {
+ get() {
+ if (this[_CONTEXT_SESSION]) return this[_CONTEXT_SESSION];
+ this[_CONTEXT_SESSION] = new ContextSession(this, opts);
+ return this[_CONTEXT_SESSION];
+ },
+ },
+ session: {
+ get() {
+ return this[CONTEXT_SESSION].get();
+ },
+ set(val) {
+ this[CONTEXT_SESSION].set(val);
+ },
+ configurable: true,
+ },
+ sessionOptions: {
+ get() {
+ return this[CONTEXT_SESSION].opts;
+ },
+ },
+ });
}
diff --git a/lib/context.js b/lib/context.js
index c4622a1..1aa4609 100644
--- a/lib/context.js
+++ b/lib/context.js
@@ -5,7 +5,7 @@ const Session = require('./session');
const util = require('./util');
const ONE_DAY = 24 * 60 * 60 * 1000;
-
+//TODO externalKey是指在redis中的key
class ContextSession {
/**
* context session constructor
@@ -24,7 +24,7 @@ class ContextSession {
*
* @api public
*/
-
+ //TODO 每个请求进入中间件,就会执行这个,用于得到或创建session
get() {
const session = this.session;
// already retrieved
@@ -43,7 +43,7 @@ class ContextSession {
*
* @api public
*/
-
+ //TODO 设置session
set(val) {
if (val === null) {
this.session = false;
@@ -63,15 +63,15 @@ class ContextSession {
*
* @api public
*/
-
+ //TODO 创建带缓存层的session
async initFromExternal() {
debug('init from external');
const ctx = this.ctx;
const opts = this.opts;
-
+ //TODO 得到缓存层的key,有缓存层时session就是个key
const externalKey = ctx.cookies.get(opts.key, opts);
debug('get external key from cookie %s', externalKey);
-
+ //TODO 如果不存在key
if (!externalKey) {
// create a new `externalKey`
this.create();
@@ -79,6 +79,7 @@ class ContextSession {
}
const json = await this.store.get(externalKey, opts.maxAge, { rolling: opts.rolling });
+ //TODO 如果已经过期
if (!this.valid(json)) {
// create a new `externalKey`
this.create();
@@ -94,13 +95,14 @@ class ContextSession {
* init session from cookie
* @api private
*/
-
+ //TODO 创建没有缓存层的session
initFromCookie() {
debug('init from cookie');
const ctx = this.ctx;
const opts = this.opts;
-
+ //TODO 没有缓存层的session包含了所有数据,opts只是为了signed参数
const cookie = ctx.cookies.get(opts.key, opts);
+ //TODO 第一次请求没有session那就创建
if (!cookie) {
this.create();
return;
@@ -109,6 +111,7 @@ class ContextSession {
let json;
debug('parse %s', cookie);
try {
+ //TODO 解码得到数据
json = opts.decode(cookie);
} catch (err) {
// backwards compatibility:
@@ -118,6 +121,7 @@ class ContextSession {
// but `JSON.parse(string)` will crash.
debug('decode %j error: %s', cookie, err);
if (!(err instanceof SyntaxError)) {
+ //TODO 删除session
// clean this cookie to ensure next request won't throw again
ctx.cookies.set(opts.key, '', opts);
// ctx.onerror will unset all headers, and set those specified in err
@@ -131,12 +135,12 @@ class ContextSession {
}
debug('parsed %j', json);
-
+ //TODO 验证是否过期
if (!this.valid(json)) {
this.create();
return;
}
-
+ //TODO 创建带数据的session
// support access `ctx.session` before session middleware
this.create(json);
this.prevHash = util.hash(this.session.toJSON());
@@ -148,15 +152,15 @@ class ContextSession {
* @return {Boolean} valid
* @api private
*/
-
+ //TODO 验证session是否过期
valid(json) {
if (!json) return false;
-
+ //TODO 如果session过期
if (json._expire && json._expire < Date.now()) {
debug('expired session');
return false;
}
-
+ //TODO 用户自己的验证规则
const valid = this.opts.valid;
if (typeof valid === 'function' && !valid(this.ctx, json)) {
// valid session value fail, ignore this session
@@ -173,10 +177,12 @@ class ContextSession {
* @param {String} [externalKey] session external key
* @api private
*/
-
+ //TODO 创建session,没有参数时创建空session
create(val, externalKey) {
debug('create session with val: %j externalKey: %s', val, externalKey);
+ //TODO 如果使用缓存层,就添加缓存的key
if (this.store) this.externalKey = externalKey || this.opts.genid();
+ //TODO 创建session
this.session = new Session(this.ctx, val);
}
@@ -185,7 +191,7 @@ class ContextSession {
*
* @api public
*/
-
+ //TODO save的hook
async commit() {
const session = this.session;
const prevHash = this.prevHash;
@@ -223,14 +229,15 @@ class ContextSession {
* remove session
* @api private
*/
-
+ //TODO 移除session
async remove() {
const opts = this.opts;
const ctx = this.ctx;
const key = opts.key;
const externalKey = this.externalKey;
-
+ //TODO 如果在缓存层当中就把缓存层的删除
if (externalKey) await this.store.destroy(externalKey);
+ //TODO cookie设置为空
ctx.cookies.set(key, '', opts);
}
@@ -238,14 +245,16 @@ class ContextSession {
* save session
* @api private
*/
-
+ //TODO 把session返回浏览器
async save(changed) {
const opts = this.opts;
const key = opts.key;
const externalKey = this.externalKey;
let json = this.session.toJSON();
// set expire for check
+ //TODO 设置默认的过期水煎
const maxAge = opts.maxAge ? opts.maxAge : ONE_DAY;
+ //TODO 过期时间是session那就是maxAge = undefined
if (maxAge === 'session') {
// do not set _expire in json if maxAge is set to 'session'
// also delete maxAge from options
@@ -256,6 +265,7 @@ class ContextSession {
json._maxAge = maxAge;
}
+ //TODO 有缓存层的话就保存key
// save to external store
if (externalKey) {
debug('save %j to external key %s', json, externalKey);
@@ -266,7 +276,7 @@ class ContextSession {
this.ctx.cookies.set(key, externalKey, opts);
return;
}
-
+ //TODO 没有缓存层就保存数据
// save to cookie
debug('save %j to cookie', json);
json = opts.encode(json);
diff --git a/lib/session.js b/lib/session.js
index b585f2a..dbb6052 100644
--- a/lib/session.js
+++ b/lib/session.js
@@ -11,7 +11,7 @@ class Session {
* @param {Object} obj
* @api private
*/
-
+ //TODO obj是数据
constructor(ctx, obj) {
this._ctx = ctx;
if (!obj) {
@@ -94,7 +94,7 @@ class Session {
* @param {Number}
* @api public
*/
-
+ //TODO 会变成修改所有的session配置
set maxAge(val) {
this._ctx.sessionOptions.maxAge = val;
// maxAge changed, must save to cookie and store
diff --git "a/\346\224\266\350\216\267.md" "b/\346\224\266\350\216\267.md"
new file mode 100644
index 0000000..074301a
--- /dev/null
+++ "b/\346\224\266\350\216\267.md"
@@ -0,0 +1,19 @@
+###### Symbol
+由于这种特点,Symbol类型适合作为标识符,用于对象的属性名,
+保证了属性名之间不会发生冲突。如果一个对象由多个模块构成,
+这样就不会出现同名的属性,也就防止了键值被不小心改写或覆盖。
+###### try/catch/finally
+finally一定会执行
+###### uid-safe库
+###### crc库
+循环冗余校验
+###### 编码解码
+使用base64和JSON进行
+解码
+const body = new Buffer(string, 'base64').toString('utf8');
+const json = JSON.parse(body);
+编码
+const body = JSON.stringify(body);
+new Buffer(body).toString('base64');
+###### 写库多用get,set
+###### 这个库没办法动态设置每个session的过期时间