Skip to content

Commit bc39659

Browse files
committed
Add session persistent storage
1 parent 77e5f23 commit bc39659

File tree

5 files changed

+81
-18
lines changed

5 files changed

+81
-18
lines changed

JavaScript/client.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class Client {
5353

5454
sendCookie() {
5555
const { res, preparedCookie } = this;
56-
console.dir({ preparedCookie, headersSent: res.headersSent });
56+
//console.dir({ preparedCookie, headersSent: res.headersSent });
5757
if (preparedCookie.length && !res.headersSent) {
5858
console.dir({ preparedCookie });
5959
res.setHeader('Set-Cookie', preparedCookie);

JavaScript/server.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

33
const http = require('http');
4+
45
const Client = require('./client.js');
56
const Session = require('./session.js');
67

@@ -12,6 +13,7 @@ const routing = {
1213
},
1314
'/api/method1': async client => {
1415
if (client.session) {
16+
client.session.set('method1', 'called');
1517
return { data: 'example result' };
1618
} else {
1719
return { data: 'access is denied' };
@@ -32,12 +34,12 @@ const types = {
3234

3335
http.createServer((req, res) => {
3436
const client = new Client(req, res);
35-
console.dir({
36-
url: req.url,
37-
status: res.statusCode,
38-
cookie: client.cookie,
39-
});
37+
const { method, url, headers } = req;
38+
console.log(`${method} ${url} ${headers.cookie}`);
4039
const handler = routing[req.url];
40+
res.on('finish', () => {
41+
if (client.session) client.session.save();
42+
});
4143
if (handler) {
4244
handler(client)
4345
.then(data => {
@@ -47,7 +49,6 @@ http.createServer((req, res) => {
4749
client.sendCookie();
4850
res.end(result);
4951
}, err => {
50-
console.error(err.stack);
5152
res.statusCode = 500;
5253
res.end('Internal Server Error 500');
5354
});

JavaScript/session.js

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
'use strict';
22

3-
const sessions = new Map();
3+
const storage = require('./storage.js');
44

5-
const TOKEN_LENGTH = 100;
5+
const TOKEN_LENGTH = 32;
66
const ALPHA_UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
77
const ALPHA_LOWER = 'abcdefghijklmnopqrstuvwxyz';
88
const ALPHA = ALPHA_UPPER + ALPHA_LOWER;
@@ -32,33 +32,37 @@ class Session extends Map {
3232
const session = new Session(token);
3333
client.session = session;
3434
client.setCookie('token', token);
35-
sessions.set(token, session);
35+
storage.set(token, session);
3636
return session;
3737
}
3838

3939
static restore(client) {
4040
const { cookie } = client;
4141
const sessionToken = cookie.token;
42-
console.log({ sessionToken });
4342
if (sessionToken) {
44-
const session = sessions.get(sessionToken);
45-
if (session) {
46-
client.token = sessionToken;
47-
client.session = session;
48-
return session;
49-
}
43+
storage.get(sessionToken, (err, session) => {
44+
if (session) {
45+
Object.setPrototypeOf(session, Session.prototype);
46+
client.token = sessionToken;
47+
client.session = session;
48+
}
49+
});
5050
}
5151
}
5252

5353
static drop(client) {
5454
const { token } = client;
5555
if (token) {
56-
sessions.delete(token);
56+
storage.delete(token);
5757
client.deleteCookie('token');
5858
client.token = undefined;
5959
client.session = null;
6060
}
6161
}
62+
63+
save() {
64+
storage.save(this.token);
65+
}
6266
}
6367

6468
module.exports = Session;

JavaScript/sessions/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Stored sessions

JavaScript/storage.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
'use strict';
2+
3+
const fs = require('fs');
4+
const path = require('path');
5+
const v8 = require('v8');
6+
7+
const PATH = `${__dirname}/sessions`;
8+
9+
const safePath = fn => (token, ...args) => {
10+
const callback = args[args.length - 1];
11+
const fileName = path.join(PATH, token);
12+
if (!fileName.startsWith(PATH)) {
13+
callback(new Error('Invalid session token'));
14+
return;
15+
}
16+
fn(fileName, ...args, callback);
17+
};
18+
19+
const readSession = safePath(fs.readFile);
20+
const writeSession = safePath(fs.writeFile);
21+
const deleteSession = safePath(fs.unlink);
22+
23+
class Storage extends Map {
24+
get(key, callback) {
25+
const value = super.get(key);
26+
if (value) {
27+
callback(null, value);
28+
return;
29+
}
30+
readSession(key, (err, data) => {
31+
if (err) {
32+
callback(err);
33+
return;
34+
}
35+
console.log(`Session loaded: ${key}`);
36+
const session = v8.deserialize(data);
37+
super.set(key, session);
38+
callback(null, session);
39+
});
40+
}
41+
42+
save(key) {
43+
const value = super.get(key);
44+
const data = v8.serialize(value);
45+
if (value) writeSession(key, data, () => {
46+
console.log(`Session saved: ${key}`);
47+
});
48+
}
49+
50+
delete(key) {
51+
deleteSession(key, () => {
52+
console.log(`Session deleted: ${key}`);
53+
});
54+
}
55+
}
56+
57+
module.exports = new Storage();

0 commit comments

Comments
 (0)