-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcache.js
More file actions
190 lines (179 loc) · 6.76 KB
/
cache.js
File metadata and controls
190 lines (179 loc) · 6.76 KB
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
const Logging = require('@cheevr/logging');
/**
* A payload object, that can be anything that can be stored by the cache implementation.
* @typedef {*} Payload
*/
/**
* A parent class that implements some of the common features available to all cache instances
* @abstract
*/
class Cache {
/**
*
* @param {Object} features
* @param {boolean} features.ttl Whether the cache implementation enable ttl support
* @param {CacheConfig} config The cache configuration
* @param {string} name The name of this cache instance
*/
constructor(features, config, name) {
this._features = features;
this._config = config;
this._name = name;
this._type = config.type;
this._ttl = features.ttl && config.ttl;
this._log = Logging[config.logger];
this._timeouts = {};
this._log.info('Set up cache with name %s of type %s', this.name, this.type);
}
/**
* Returns the name of this instance
* @returns {string}
*/
get name() {
return this._name;
}
/**
* Returns the type of cache this implementation is using.
* @returns {string}
*/
get type() {
return this._type;
}
/**
* Stores data in cache. Supports both callback or promise interface. Storing a value in cache
* will reset the ttl (if enabled).
* @param {string} type
* @param {string|number} id
* @param {Payload} payload
* @param {Callback} [cb]
* @returns {Promise.<Payload>}
*/
store(type, id, payload, cb) {
type = typeof type === 'string' ? type : String(type);
id = typeof id === 'string' ? id : String(id);
if (this._ttl) {
this._timeouts[type] = this._timeouts[type] || {};
this._timeouts[type][id] && clearTimeout(this._timeouts[type][id]);
this._timeouts[type][id] = setTimeout(this.remove.bind(this), this._ttl, type, id);
}
this._log.trace('Storing payload under key [%s:%s] in %s cache (%s)', type, id, this.name, this.type);
if (cb) {
return this._store(type, id, payload).then(result => cb(null, result)).catch(err => {
this._log.error('Unable to store payload for key [%s:%s] in cache of type %s:', type, id, this.type, err);
cb(err);
})
} else {
return this._store(type, id, payload);
}
}
/**
* Retrieve data from cache. Supports both callback or promise interface. Fetching from cache
* will reset the ttl (if enabled).
* @param {string} type
* @param {string|number} id
* @param {Callback} [cb]
* @returns {Promise.<Payload>}
*/
fetch(type, id, cb) {
type = typeof type === 'string' ? type : String(type);
id = typeof id === 'string' ? id : String(id);
if (this._ttl && this._timeouts[type]) {
this._timeouts[type][id] && clearTimeout(this._timeouts[type][id]);
this._timeouts[type][id] = setTimeout(this.remove.bind(this, type, id), this._ttl);
}
this._log.trace('Fetching payload for key [%s:%s] from %s cache (%s)', type, id, this.name, this.type);
if (cb) {
return this._fetch(type, id).then(result => cb(null, result)).catch(err => {
this._log.error('Unable to fetch payload for key [%s:%s] from cache of type %s:', type, id, this.type, err);
cb(err);
});
} else {
return this._fetch(type, id);
}
}
/**
* Returns a list of payloads for the given type. An order is not guaranteed. Supports both
* callback or promise interface. Will not reset ttl if accessed (if enabled).
* @param {string} type
* @param {Callback} [cb]
* @returns {Promise.<Payload[]>}
*/
list(type, cb) {
type = typeof type === 'string' ? type : String(type);
if (cb) {
this._list(type).then(result => cb(null, result)).catch(err => {
this._log.error('Unable to list payloads for key [%s] from cache of type %s', type, this.type, err);
cb(err);
});
} else {
return this._list(type);
}
}
/**
* Returns a map of id -> payload. Supports both callback or promise interface. Will not reset
* ttl if accessed (if enabled).
* @param {string} type
* @param {Callback} [cb]
* @returns {Promise.<Object<string, Payload>>}
*/
map(type, cb) {
type = typeof type === 'string' ? type : String(type);
if (cb) {
this._map(type).then(result => cb(null, result)).catch(err => {
this._log.error('Unable create map for key [%s] from cache of type %s', type, this.type, err);
cb(err);
});
} else {
return this._map(type);
}
}
/**
* Removes a payload from cache. Supports both callback or promise interface. Will remove the ttl
* of the entry affected.
* @param {string} type
* @param {string|number} id
* @param {Callback} [cb]
* @returns {Promise.<Payload>}
*/
remove(type, id, cb) {
type = typeof type === 'string' ? type : String(type);
id = typeof id === 'string' ? id : String(id);
if (this._timeouts[type]) {
this._timeouts[type][id] && clearTimeout(this._timeouts[type][id]);
delete this._timeouts[type][id];
}
this._log.trace('Removing payload for key [%s:%s] from %s cache (%s)', type, id, this.name, this.type);
if (cb) {
this._remove(type, id).then(result => cb(null, result)).catch(err => {
this._log.error('Unable to remove entry for key [%s:%s] form cache of type %s:', type, id, this.type, err);
cb(err);
});
} else {
return this._remove(type, id);
}
}
/**
* Removes all payload of a given type from cache. Supports both callback and promise interface. Will
* remove the ttl of all entries affected.
* @param {string} type
* @param {Callback} cb
* @returns {*}
*/
clear(type, cb) {
type = typeof type === 'string' ? type : String(type);
if (this._timeouts[type]) {
this._timeouts[type].forEach(clearTimeout);
delete this._timeouts[type];
}
this._log.trace('Clearing cache for type [%s] from %s cache (%s)', type, this.name, this.type);
if (cb) {
this._clear(type).then(result => cb(null, result)).catch(err => {
this._log.error('Unable to clear entries for key [%s] from cache of type %s:', type, this.type, err);
cb(err);
});
} else {
return this._clear(type);
}
}
}
module.exports = Cache;