forked from expressjs/express
/
session.js
205 lines (162 loc) · 3.62 KB
/
session.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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
// Express - Session - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
/**
* Module dependencies.
*/
var utils = require('express/utils')
// --- Session
var Session = Class({
/**
* Initialize session _sid_.
*/
init: function(sid) {
this.id = sid
this.touch()
},
/**
* Update last access time.
*
* @api private
*/
touch: function() {
this.lastAccess = Number(new Date)
}
})
// --- Store
exports.Store = Class({
/**
* Convert to '[NAME Store]'.
*
* @return {string}
* @api public
*/
toString: function() {
return '[' + this.name + ' Store]'
}
})
// --- Store.Memory
exports.Store.Memory = exports.Store.extend({
/**
* Datastore name.
*/
name: 'Memory',
/**
* Initialize in-memory session store.
*/
init: function() {
this.store = {}
},
/**
* Fetch session with the given _sid_ or
* a new Session is returned.
*
* @param {int} sid
* @return {Session}
* @api private
*/
fetch: function(sid) {
return this.store[sid] || new Session(sid)
},
/**
* Commit _session_ data.
*
* @param {Session} session
* @api private
*/
commit: function(session) {
return this.store[session.id] = session
},
/**
* Clear all sessions.
*
* @api public
*/
clear: function() {
this.store = {}
},
/**
* Destroy session using the given _sid_.
*
* @param {int} sid
* @api public
*/
destroy: function(sid) {
delete this.store[sid]
},
/**
* Return the number of sessions currently stored.
*
* @return {int}
* @api public
*/
length: function() {
return $(this.store).length()
},
/**
* Reap sessions older than _ms_.
*
* @param {int} ms
* @api private
*/
reap: function(ms) {
var self = this,
threshold = Number(new Date(Number(new Date) - ms))
$(this.store).each(function(session, sid){
if (session.lastAccess < threshold)
self.destroy(sid)
})
}
})
// --- Session
exports.Session = Plugin.extend({
extend: {
/**
* Initialize memory store and start reaper.
*
* Options:
*
* - dataStore constructor name of session data store, defaults to Store.Memory
* - lifetime lifetime of session in milliseconds, defaults to one day
* - reapInterval, reapEvery interval in milliseconds in which to reap old sessions, defaults to one hour
*
* @param {hash} options
* @api private
*/
init: function(options) {
process.mixin(this, options)
this.store = new (this.dataStore || exports.Store.Memory)(options)
this.startReaper()
},
/**
* Start reaper.
*
* @api private
*/
startReaper: function() {
var self = this,
oneDay = 86400000,
oneHour = 3600000
setInterval(function(){
self.store.reap(self.lifetime || oneDay)
}, self.reapInterval || self.reapEvery || oneHour)
}
},
// --- Events
on: {
/**
* Create session id when not found; delegate to store.
*/
request: function(event) {
var sid
if (!(sid = event.request.cookie('sid')))
event.request.cookie('sid', sid = utils.uid(), set('session cookie'))
event.request.session = exports.Session.store.fetch(sid)
event.request.session.touch()
},
/**
* Delegate to store, allowing it to save sessions changes.
*/
response: function(event) {
exports.Session.store.commit(event.request.session)
}
}
})