-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
121 lines (107 loc) · 3.46 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
var mmemoize = function () {
var crypto = require('crypto');
var Memcached = require('memcached');
var memcached;
var that = {};
if (arguments.length === 0) {
throw new Error('No memcached connection string/object given.');
} else if (typeof arguments[0] === 'object' &&
arguments[0].connect !== undefined) {
// found a Memcached() instance by duck typing, use it:
memcached = arguments[0];
} else if (arguments.length == 1) {
memcached = new Memcached(arguments[0]);
} else {
memcached = new Memcached(arguments[0], arguments[1]);
}
var configDefaults = {
ttl: 120,
hashAlgorithm: 'sha1'
};
var config = (arguments.length > 1 &&
Array.prototype.pop.call(arguments)) || {};
for (var cProp in configDefaults) {
if (configDefaults.hasOwnProperty(cProp) && config[cProp] === undefined) {
config[cProp] = configDefaults[cProp];
}
}
var memoize = function (fct, keyPrefix, ttl) {
if (fct.dememoize !== undefined) { return; } // fct() already memoized
var unmemoized = fct; // save original function for dememoization purposes
if (ttl === undefined) {
ttl = config.ttl;
}
var mFct = function () {
var _this = this;
var args = Array.prototype.slice.call(arguments);
var fctCallback,
key;
if (typeof args.slice(-1).pop() === 'function') {
fctCallback = args.pop(); // cache and remove original callback
}
key = calcKey(keyPrefix, args);
memcached.get(key, function (err, mcdResult) {
if (err !== undefined ||
mcdResult === undefined ||
mcdResult === false) { // memcache error or miss:
args.push(function () { // register our new callback:
var fctResult = Array.prototype.slice.call(arguments);
memcached.set(key,
JSON.stringify(fctResult),
ttl,
function (err, result) {
// NOTE that we *ignore any memcache errors* here!
if (fctCallback !== undefined) {
fctCallback.apply(_this, fctResult); // call original callback
}
}
);
});
// actually perform function call for memoization:
fct.apply(_this, args);
}
else { // cache hit:
mcdResult = JSON.parse(mcdResult);
if (fctCallback !== undefined) {
fctCallback.apply(_this, mcdResult); // call original callback
}
}
});
};
var dememoize = function () {
return unmemoized;
};
mFct.dememoize = dememoize;
return mFct;
};
that.memoize = memoize;
// shamelessly borrowed from https://github.com/caolan/async:
var dememoize = function (fct) {
if (fct.dememoize === undefined) { return fct; } // not memoized
return fct.dememoize();
};
that.dememoize = dememoize;
var getConfig = function () {
return { ttl: config.ttl, hashAlgorithm: config.hashAlgorithm };
};
that.getConfig = getConfig;
// PRIVATE METHODS:
var calcKey = function (prefix, args) {
var key,
hasher;
if (typeof args !== 'string') {
args = JSON.stringify(args);
}
if (config.hashAlgorithm !== null) { // hash arguments:
hasher = crypto.createHash(config.hashAlgorithm);
hasher.update(args);
key = prefix + ':' + hasher.digest('hex');
}
else {
key = prefix + ':' + args;
}
return key;
};
return that;
};
module.exports = mmemoize;