Cache2FileCache to File module for Node.js
It stores cache data in files that can expire. Stored data can be in any format
Buffer supports (utf8 [default], ascii , binary ).
Install
npm install cache2file
Usage
var Cache2File = require('cache2file'),
// Path to store the cache files
cachePath = './cache',
// Timeout in milliseconds
timeout = 60000,
// Generate a new cache
cache = new Cache2File(cachePath, timeout);
cache.set('cacheKey', doIntensiveStuff());
// ... some time later
cache.get('cacheKey', function (err, data) {
if (!err) {
// We have the data, do whatever we want.
}
else {
// Cache timed out, or removed, so store it again.
data = doIntensiveStuff();
cache.set('cacheKey', data);
}
processData(data);
});
// Remove cached data.
cache.remove('cacheKey');
Cache2File uses it's own function Cache2File.generateKey to generate a hash
for the filename to store data in. It can be replaced with your own filename
generating algorithm if you wish. Hashing was generally required to only have
ascii characters in filenames and no / characters, as there is no restriction
for the characters in the key .
key 's string value should be less then 200 characters so the filesystem can
handle the filename.
To remove multiple cache files, use
cache.removeAll(callback, keyCached, expired)
Where if keyCached is set to true , remove those whose key was touched in the
lifetime of the cache object. If it is false (default) all cache files in the
cache directory will be removed (those that has the extension .cache ).<br>
If expired is set to true (default is false ) it will only remove expired
cache files.<br>
These filters can be combined.
TODO
Handle cache read / write concurrency. | |
| lib/cache2file.js |
fileOverview: Cache2File
module. Stores cache data in files that can expire.
Stored data can be in any format Buffer supports
(utf8 [default], ascii , binary ). author: Peter
(Poetro) Galiba <poetro at poetro dot hu> version: 0
.2.1 requires: fs requires: path requires: funk
|
var fs = require('fs'),
path = require('path'),
Funk = require('funk');
|
Manage key - value caching into files.
- class: Cache2File
property: String path Path to the cache directory. property: Number timeout Timeout of cache files in milliseconds. property: Object keyCache Hash table for mapping generated file identifier to cache key.
|
|
Manage key - value caching into files.
- constructor: Cache2File
|
function Cache2File(path, timeout) {
if (!(this instanceof Cache2File)) return new Cache2File(path, timeout);
this.path = path || './cache';
this.timeout = timeout || e5;
this.keyCache = {};
}
|
Function placeholder.
|
function noop() {}
|
Remove the files specified cache files.
If expired is true, only the expired cache files will be unlinked.
param: Array files List of files to delete. param: Boolean expired Only delete the files, if it has expired. param: Function callback The callback function will be called, when all files are processed.
It will be called with passing in an object keyed by the file's name,
if any errors occured, or null otherwise.
|
function removeFiles(files, expired, callback, timeout) {
var funk = new Funk;
if (expired) {
funk.set('files', []);
}
else {
funk.set('errors', {});
}
files.forEach(function (cacheFile) {
if (expired) {
fs.stat(cacheFile, funk.add(function (err, stats) {
if (!err && Date.now() - Date.parse(stats.ctime) > timeout) {
this.files.push(cacheFile);
}
}));
}
else {
fs.unlink(cacheFile, funk.add(function (err) {
if (err) {
this.errors[cacheFile] = err;
}
}));
}
});
funk.parallel(function () {
if (expired) {
removeFiles(this.files, false, callback, timeout);
}
else {
callback(Object.keys(this.errors).length ? this.errors : null);
}
});
}
|
Generate a hash from the key that will serve as the base for the generated file.
|
Cache2File.generateKey = function (key) {
return (new Buffer(key.toString())).toString('base64')
.slice(0, -2).replace(/\+/g, '-').replace(/\//g, '_');
};
Cache2File.prototype = {
|
Generate a hash key / return one from the already generated key cache, if exists.
|
generateKey: function (key) {
if (!(key in this.keyCache)) {
this.keyCache[key] = Cache2File.generateKey(key);
}
return this.keyCache[key];
},
|
Get a value for the specified key.
param: String key The key for the value to fetch. param: Function callback The function to call with the fetched data with.
The callback has 2 arguments: err , data ,
where data is the content if no errors occured and the cache hasn't expired. param: String [encoding] The encoding to fetch the information in is optional.
|
get: function (key, callback, encoding_) {
var encoding = typeof encoding_ === 'string' ? encoding_ : null,
cacheFile = path.join(this.path, this.generateKey(key) + '.cache'),
timeout = this.timeout;
callback = (typeof callback === 'function' ? callback : noop);
fs.stat(cacheFile, function (err, stats) {
var date, expired = true;
if (!err) {
if (Date.now() - Date.parse(stats.ctime) < timeout) {
expired = false;
}
}
if (expired) {
callback(true, null);
} else {
fs.readFile(cacheFile, encoding, function (err, data) {
callback(err, data && data.toString());
});
}
});
},
|
Get a value for the specified key.
param: String key The key for the value to fetch. param: String | Buffer data Data to write to the cache. param: String [encoding] The encoding to fetch the information in is optional. param: Function [callback] The function to call with when the setting finished is optional.
The callback has an err argument and stores the errors if any occured.
|
set: function (key, data, encoding_, callback) {
var encoding = typeof encoding_ === 'string' ? encoding_ : null,
cacheFile = path.join(this.path, this.generateKey(key) + '.cache');
if (typeof data !== 'string' && !(data instanceof Buffer)) {
data = data.toString();
}
callback = arguments[arguments.length - 1];
callback = (typeof callback === 'function' ? callback : noop);
fs.writeFile(cacheFile, data, encoding, callback);
},
|
Remove a cache file.
|
remove: function (key, callback) {
var cacheFile = path.join(this.path, this.generateKey(key) + '.cache');
callback = (typeof callback === 'function' ? callback : noop);
fs.unlink(cacheFile, callback);
},
|
Remove all (or a subset of) cache files.
The parameters keyCached and expired can be combined in any ways,
they filter the set of removed files.
param: Function [callback] The callback function will be called, when all files are processed.
It will be called with passing in an object keyed by the file's name,
if any errors occured, or null otherwise. param: Boolean [keyCached] Only remove the files, whose key is already cached
(aka used in this Cache2File object already). Optional, default is false. param: Boolean [expired] Only remove those that files are already expired. Optional, default is false.
|
removeAll: function (callback, keyCached, expired) {
var timeout = this.timeout,
cache = this;
callback = (typeof callback === 'function' ? callback : noop);
if (keyCached) {
removeFiles(Object.keys(this.keyCache).map(function (key) {
return this[key];
}, this.keyCache), expired, callback, timeout);
}
else {
fs.readdir(this.path, function (err, files) {
var fileTest;
if (!err) {
fileTest = /\.cache$/;
removeFiles(
files.filter(function (file) {
return fileTest.test(file);
}).map(function (file) {
return path.join(cache.path, file);
}),
expired,
callback,
timeout);
}
else {
callback([err]);
}
});
}
}
};
|
|
module.exports = Cache2File;
|