Skip to content

Commit

Permalink
feat: support rolling (#82)
Browse files Browse the repository at this point in the history
* feat: support rolling

* f

* feat: pass options to store
  • Loading branch information
dead-horse committed Jun 16, 2017
1 parent 5ba45dd commit 558ecf3
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 8 deletions.
6 changes: 4 additions & 2 deletions Readme.md
Expand Up @@ -54,7 +54,9 @@ var CONFIG = {
overwrite: true, /** (boolean) can overwrite or not (default true) */
httpOnly: true, /** (boolean) httpOnly or not (default true) */
signed: true, /** (boolean) signed or not (default true) */
rolling: false, /** (boolean) Force a session identifier cookie to be set on every response. The expiration is reset to the original maxAge, resetting the expiration countdown. default is false **/
};

app.use(session(CONFIG, app));
// or if you prefer all default config, just use => app.use(session(app));

Expand Down Expand Up @@ -111,8 +113,8 @@ app.use(convert(session(app)));

You can store the session content in external stores(redis, mongodb or other DBs) by pass `options.store` with three methods(need to be generator function or async function):

- `get(key)`: get session object by key
- `set(key, sess, maxAge)`: set session object for key, with a `maxAge` (in ms)
- `get(key, maxAge, { rolling })`: get session object by key
- `set(key, sess, maxAge, { rolling, changed })`: set session object for key, with a `maxAge` (in ms)
- `destroy(key)`: destroy session for key


Expand Down
17 changes: 11 additions & 6 deletions lib/context.js
Expand Up @@ -79,7 +79,7 @@ class ContextSession {
return;
}

const json = yield this.store.get(externalKey);
const json = yield this.store.get(externalKey, opts.maxAge, { rolling: opts.rolling });
if (!this.valid(json)) {
// create a new `externalKey`
this.create();
Expand Down Expand Up @@ -203,19 +203,21 @@ class ContextSession {
}

// force save session when `session._requireSave` set
let changed = true;
if (!session._requireSave) {
const json = session.toJSON();
// do nothing if new and not populated
if (!prevHash && !Object.keys(json).length) return;
// do nothing if not changed
if (prevHash === util.hash(json)) return;
changed = prevHash !== util.hash(json);
// do nothing if not changed and not in rolling mode
if (!this.opts.rolling && !changed) return;
}

if (typeof opts.beforeSave === 'function') {
debug('before save');
opts.beforeSave(ctx, session);
}
yield this.save();
yield this.save(changed);
}

/**
Expand All @@ -238,7 +240,7 @@ class ContextSession {
* @api private
*/

* save() {
* save(changed) {
const opts = this.opts;
const key = opts.key;
const externalKey = this.externalKey;
Expand All @@ -258,7 +260,10 @@ class ContextSession {
// save to external store
if (externalKey) {
debug('save %j to external key %s', json, externalKey);
yield this.store.set(externalKey, json, maxAge);
yield this.store.set(externalKey, json, maxAge, {
changed,
rolling: opts.rolling,
});
this.ctx.cookies.set(key, externalKey, opts);
return;
}
Expand Down
40 changes: 40 additions & 0 deletions test/cookie.test.js
Expand Up @@ -755,6 +755,46 @@ describe('Koa Session Cookie', () => {
});
});
});

describe('when rolling set to true', () => {
let app;
before(() => {
app = App({ rolling: true });

app.use(function* () {
console.log(this.path);
if (this.path === '/set') this.session = { foo: 'bar' };
this.body = this.session;
});
});

it('should not send set-cookie when session not exists', () => {
return request(app.callback())
.get('/')
.expect({})
.expect(res => {
should.not.exist(res.headers['set-cookie']);
});
});

it('should send set-cookie when session exists and not change', done => {
request(app.callback())
.get('/set')
.expect({ foo: 'bar' })
.end((err, res) => {
should.not.exist(err);
res.headers['set-cookie'].should.have.length(2);
const cookie = res.headers['set-cookie'].join(';');
request(app.callback())
.get('/')
.set('cookie', cookie)
.expect(res => {
res.headers['set-cookie'].should.have.length(2);
})
.expect({ foo: 'bar' }, done);
});
});
});
});

function App(options) {
Expand Down
38 changes: 38 additions & 0 deletions test/store.test.js
Expand Up @@ -628,6 +628,44 @@ describe('Koa Session External Store', () => {
});
});

describe('when rolling set to true', () => {
let app;
before(() => {
app = App({ rolling: true });

app.use(function* () {
if (this.path === '/set') this.session = { foo: 'bar' };
this.body = this.session;
});
});

it('should not send set-cookie when session not exists', () => {
return request(app.callback())
.get('/')
.expect({})
.expect(res => {
should.not.exist(res.headers['set-cookie']);
});
});

it('should send set-cookie when session exists and not change', done => {
request(app.callback())
.get('/set')
.expect({ foo: 'bar' })
.end((err, res) => {
should.not.exist(err);
res.headers['set-cookie'].should.have.length(2);
const cookie = res.headers['set-cookie'].join(';');
request(app.callback())
.get('/')
.set('cookie', cookie)
.expect(res => {
res.headers['set-cookie'].should.have.length(2);
})
.expect({ foo: 'bar' }, done);
});
});
});
});

function App(options) {
Expand Down

0 comments on commit 558ecf3

Please sign in to comment.