-
Notifications
You must be signed in to change notification settings - Fork 4
/
index.js
120 lines (115 loc) · 3.09 KB
/
index.js
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
114
115
116
117
118
119
120
const ThinkRedis = require('think-redis');
const assert = require('assert');
const helper = require('think-helper');
// const debug = require('debug')('think-session-redis');
const initSessionData = Symbol('think-session-redis-init');
const autoSave = Symbol('think-session-save');
/**
* use redis to store session
*/
class RedisSession {
/**
* constructor
* @param {Object} options cookie options
* @param {Object} ctx koa ctx
*/
constructor(options = {}, ctx, cookieOptions) {
assert(options.cookie, '.cookie required');
this.options = options;
this.cookieOptions = cookieOptions || {};
this.redis = new ThinkRedis(helper.omit(this.options, 'cookie,fresh'));
this.ctx = ctx;
this.data = {};
this.status = 0;
this.maxAge = this.options.maxAge || 0;
this.expires = 0;
}
/**
* init session data
*/
[initSessionData]() {
if (this.initPromise) {
return this.initPromise;
}
this[autoSave]();
if (this.options.fresh || this.status === -1) {
this.initPromise = Promise.resolve();
return this.initPromise;
}
this.initPromise = this.redis.get(this.options.cookie).then(content => {
if (helper.isEmpty(content)) return;
content = JSON.parse(content);
if (helper.isEmpty(content)) return;
this.data = content.data || {};
if (content.maxAge) {
this.maxAge = content.maxAge;
}
this.expires = content.expires || 0;
this.autoUpdate();
}).catch(err => {
console.error(err);
});
return this.initPromise;
}
autoUpdate() {
if (this.maxAge && this.expires) {
const rate = (this.expires - Date.now()) / this.maxAge;
if (rate < this.cookieOptions.autoUpdateRate) {
this.status = 1;
this.cookieOptions.maxAge = this.maxAge;
// update cookie maxAge
this.ctx.cookie(this.cookieOptions.name, this.options.cookie, this.cookieOptions);
}
}
}
/**
* auto save session data when it is changed
*/
[autoSave]() {
this.ctx.res.once('finish', () => {
if (this.status === -1) {
return this.redis.delete(this.options.cookie);
} else if (this.status === 1) {
// if not fresh, can not override maxAge (may be set user defined timeout)
return this.redis.set(this.options.cookie, JSON.stringify({
data: this.data,
maxAge: this.maxAge,
expires: Date.now() + this.maxAge
}), 'PX', this.maxAge);
}
});
}
/**
* get session data
* @param {String} name
*/
get(name) {
return this[initSessionData]().then(() => {
return name ? this.data[name] : this.data;
});
}
/**
* set session data
* @param {String} name
* @param {Mixed} value
*/
set(name, value) {
return this[initSessionData]().then(() => {
this.status = 1;
if (value === null) {
delete this.data[name];
} else {
this.data[name] = value;
}
});
}
/**
* delete session data
*/
delete() {
this.status = -1;
this.data = {};
return Promise.resolve();
}
}
module.exports = RedisSession;