-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
125 lines (104 loc) · 3.07 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
121
122
123
124
125
'use strict';
const sqlite3 = require('sqlite3');
const TABLE_NAME = '__session_store';
const SQL_CREATE_TABLE = `CREATE TABLE IF NOT EXISTS "${TABLE_NAME}" (
id TEXT PRIMARY KEY NOT NULL,
expires INTEGER NOT NULL,
data TEXT);`;
const SQL_GET = `SELECT * FROM "${TABLE_NAME}" WHERE id = ?`;
const SQL_SET = `INSERT OR REPLACE INTO "${TABLE_NAME}" (id, expires, data) VALUES (?, ?, ?)`;
const SQL_DELETE = `DELETE FROM "${TABLE_NAME}" WHERE id = ?`;
const SQL_EXPIRE = `DELETE FROM "${TABLE_NAME}" WHERE expires < ?`;
const DEFAULT_TTL = 30 * 60;
const DEFAULT_INTERVAL = 15 * 60 * 1000;
class SQLiteStore {
/**
* initialize a new SQLiteStore instance
* @param {String} filename sqlite database filename, could be ':memory:'
* @param {Object} opt options
* @return {Null}
*/
constructor(filename, opt) {
this.opt = opt || {};
let sqlite = this.opt.verbose ? sqlite3 : sqlite3.verbose();
this.__db = new sqlite.Database(filename);
this.__db.serialize(() =>
this.__db.exec(SQL_CREATE_TABLE));
// method aliases
this.end = this.destroy;
this.cleanup = this.flush;
// flush interval
setInterval(this.flush.bind(this), this.opt.interval || DEFAULT_INTERVAL);
}
/**
* load session by sid
* @param {String} sid session id
* @return {Promise} async task
*/
get(sid) {
let now = new Date().getTime();
return this.__query(SQL_GET, [sid]).then(result => {
if (result && result.expires > now)
return JSON.parse(result.data);
this.destroy(sid);
return;
});
}
/**
* session start
* @param {String} sid session id
* @param {Object} session session data
* @param {Number} ttl time-to-live in millseconds
*/
set(sid, session, ttl) {
let data = JSON.stringify(session);
let expire;
if (session && session.cookie && session.cookie.expires) {
ttl = 0;
expire = session.cookie.expires
if (!(expire instanceof Date))
expire = new Date(session.cookie.expires);
} else {
expire = new Date();
if (isNaN(ttl))
ttl = this.opt.ttl || DEFAULT_TTL;
}
let expireTime = expire.getTime() + ttl;
return this.__query(SQL_SET, [sid, expireTime, data]);
}
/**
* destroy session
* @return {Promise} async task
*/
destroy(sid) {
return this.__query(SQL_DELETE, [sid]);
}
/**
* clean up exired sessions
* @return {Promise}
*/
flush() {
let now = Math.floor(new Date().getTime());
return this.__query(SQL_EXPIRE, [now]);
}
/**
* shutdown sqlite3
* @return {Promise<Null>}
*/
shutdown() {
return new Promise((resolve, reject) =>
this.__db.close(err => err ? reject(err) : resolve())
);
}
/**
* run query
* @return {Promise} query task
*/
__query(sql, params) {
return new Promise((resolve, reject) => {
let callback = (err, row) => err ? reject(err) : resolve(row);
this.__db.serialize(() => this.__db.get(sql, params, callback));
});
}
}
module.exports = SQLiteStore;