-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmemorize.js
113 lines (98 loc) · 3.74 KB
/
memorize.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
'use strict';
var fs = require('fs'),
mkdirp = require('mkdirp'),
path = require('path'),
extend = require('extend');
module.exports = function(options) {
options = extend({
/* Function(req) or regular expression to match the url */
match: false,
memorize: true,
recall: false,
storageDir: 'offline',
/* Function(url, req) or regular expression to normalize the url.
If regular expression is used, the first subpattern will be used as a new url */
normalize: /^.*?\/\/.+?(\/.*$)/, // remove host
verbose: false
}, options);
if (!options.storageDir) throw 'options.storageDir is not defined!';
return function(req, res, next) {
// console.log(req);
if ('GET' !== req.method/* && 'HEAD' != req.method*/) return next();
if (typeof options.match === 'function') {
if (!options.match(req)) {
next();
return;
}
} else if (options.match) {
if (!req.url.match(options.match)) {
next();
return;
}
}
var urlPath = req.url;
if (typeof options.normalize === 'function') {
urlPath = options.normalize(urlPath, req);
} else if (options.normalize) {
urlPath = urlPath.match(options.normalize);
urlPath = urlPath && urlPath[1] ? urlPath[1] : req.url;
}
urlPath = escape(urlPath);
if (urlPath[0] === '/') urlPath = urlPath.substr(1);
if (urlPath === '') urlPath = 'index';
var storageFile = options.storageDir + '/' + urlPath;
if (options.recall) {
// try to serve offline file
if (fs.existsSync(storageFile)) {
fs.createReadStream(storageFile).pipe(res);
return;
}
}
if (options.memorize) {
// memorize the response
var _write = res.write,
_end = res.end,
_writeHead = res.writeHead,
file,
partFile = storageFile + '.part';
var memorize = function(data, enc) {
if (file === false || !data) return; // storing disabled, or no data
if (res.statusCode !== 200) {
if (file === undefined) {
if (options.verbose) console.log('Can\'t memorize ', req.url, ', response code:', res.statusCode);
file = false;
}
return;
}
if (!file) {
// lazy initialize file on first write
mkdirp.sync(path.dirname(partFile));
file = fs.openSync(partFile, 'w');
}
if (typeof data === 'string') data = new Buffer(data, enc);
fs.writeSync(file, data, 0, data.length);
}
res.write = function(data, enc) {
memorize(data, enc);
return _write.call(this, data, enc);
}
res.end = function(data, enc) {
memorize(data, enc);
if (file) {
fs.closeSync(file);
try {
fs.renameSync(partFile, storageFile);
} catch (e) {
console.log('Can\'t rename ', partFile, ' to ', storageFile);
}
}
return _end.call(this, data, enc);
}
res.on('error', function (err) {
if (options.verbose) console.log('Can\'t memorize ', req.url, ', response error:', err);
if (!file) file = false;
});
}
next();
};
}