filestream-cache
Advanced tools
Comparing version 0.0.2 to 1.0.0
107
index.js
@@ -8,2 +8,3 @@ var fs = require('fs'); | ||
var mkdirp = require('mkdirp'); | ||
var twelveHoursInSeconds = 43200; | ||
@@ -16,4 +17,7 @@ /** | ||
*/ | ||
function StreamCache(rootDirectory) { | ||
function StreamCache(rootDirectory, options) { | ||
this.rootCacheDirectory = rootDirectory; | ||
options = options || {}; | ||
this.defaultTtl = options.defaultTtl || twelveHoursInSeconds; | ||
this.serveStale = options.serveStale || false; | ||
@@ -33,2 +37,31 @@ // TODO: Where's best to handle errors here? | ||
StreamCache.prototype.getMetaData = function(identifier) { | ||
var cachedObjectPath = this._getCachedObjectPath(identifier); | ||
var cache = this; | ||
return this._getReadFileDescriptor(identifier).then(function(fd) { | ||
return cache._getMetaDataUsingFileDescriptor(fd); | ||
}); | ||
}; | ||
StreamCache.prototype._getMetaDataUsingFileDescriptor = function(fd) { | ||
return new Promise(function(resolve, reject) { | ||
fs.fstat(fd, function(err, stat) { | ||
if (err) { | ||
reject(err); | ||
return; | ||
} | ||
var lastModified = (stat.mtime.getTime() / 1000)|0; | ||
var timeNowInSeconds = ((Date.now() / 1000)|0); | ||
resolve({ | ||
age: timeNowInSeconds - lastModified, | ||
firstCreated: (stat.birthtime.getTime() / 1000)|0, | ||
lastModified: lastModified | ||
}); | ||
}); | ||
}); | ||
}; | ||
/** | ||
@@ -52,6 +85,15 @@ * Get a Stream from the cache, if the stream doesn't exist, create it via the | ||
cache._read(identifier, options).then(function(stream) { | ||
if (stream) { | ||
if (!stream) { | ||
var newStream; | ||
try { | ||
newStream = createCallback(); | ||
} catch(err) { | ||
passThroughStream.emit('error', err); | ||
throw err; | ||
} | ||
cache.writeThrough(identifier, newStream).pipe(passThroughStream); | ||
} else { | ||
stream.pipe(passThroughStream); | ||
} else { | ||
cache.writeThrough(identifier, createCallback()).pipe(passThroughStream); | ||
} | ||
@@ -123,27 +165,48 @@ }); | ||
StreamCache.prototype._read = function(identifier, options) { | ||
options = options || {}; | ||
var cachedObjectPath = this._getCachedObjectPath(identifier); | ||
var cache = this; | ||
var newerThan = options.newerThan || 0; | ||
return this._getReadFileDescriptor(identifier).then(function(fd) { | ||
return cache._isStale(fd).then(function(isStale) { | ||
if (isStale) { | ||
return false; | ||
} else { | ||
// First argument of fs.createReadStream is ignored | ||
// because the 'fd' is present | ||
return fs.createReadStream(false, { fd: fd, autoClose: true }); | ||
} | ||
}); | ||
}).catch(function(e) { | ||
return false; | ||
}); | ||
}; | ||
StreamCache.prototype.isStale = function(identifier) { | ||
var cache = this; | ||
return this._getReadFileDescriptor(identifier).then(function(fd) { | ||
return cache._isStale(fd); | ||
}); | ||
}; | ||
StreamCache.prototype._isStale = function(fd) { | ||
var defaultTtl = this.defaultTtl; | ||
return this._getMetaDataUsingFileDescriptor(fd).then(function(metadata) { | ||
return metadata.age > defaultTtl; | ||
}); | ||
}; | ||
StreamCache.prototype._getReadFileDescriptor = function(identifier, options) { | ||
var cachedObjectPath = this._getCachedObjectPath(identifier); | ||
return new Promise(function(resolve, reject) { | ||
fs.open(cachedObjectPath, 'r', function(e, fd) { | ||
if (e) { | ||
resolve(false); | ||
} else { | ||
fs.fstat(fd, function(e, stats) { | ||
if (stats.mtime < newerThan) { | ||
resolve(false); | ||
} else { | ||
// First argument of fs.createReadStream is ignored | ||
// because the 'fd' is present | ||
var readStream = fs.createReadStream(false, { fd: fd }); | ||
readStream.on('end', function() { | ||
// Close fd | ||
fs.close(fd); | ||
}); | ||
resolve(readStream); | ||
} | ||
}); | ||
reject(e); | ||
return; | ||
} | ||
resolve(fd); | ||
}); | ||
@@ -150,0 +213,0 @@ }); |
@@ -17,4 +17,4 @@ { | ||
}, | ||
"version": "0.0.2", | ||
"version": "1.0.0", | ||
"license": "MIT" | ||
} |
@@ -1,3 +0,2 @@ | ||
var StreamCache = require('../index'); | ||
var fs = require('fs'); | ||
var StreamCache = require('../index'); var fs = require('fs'); | ||
var assert = require('assert'); | ||
@@ -9,2 +8,13 @@ var helpers = require('./testhelper'); | ||
describe("#isStale(identifier)", function() { | ||
it("should return true, if the cache object is stale", function(done) { | ||
helpers.testIsStale(-1, true, done); | ||
}); | ||
it("should return false, if the cache object is not stale", function(done) { | ||
helpers.testIsStale(4000, false, done); | ||
}); | ||
}); | ||
describe("#purge(callback)", function() { | ||
@@ -62,2 +72,45 @@ it("should purge any objects from the cache where the Promise returned from the callback resolves as true", function(done) { | ||
describe("#get(identifier, options, callback)", function() { | ||
it("should, if the cached object's age is older than the default ttl, create a new stream and overwrite the cache", function(done) { | ||
var streamContent = 'my test stream content'; | ||
var testBucket = 'get#test-create-stale'; | ||
var cacheKey = 'testkey'; | ||
var testDirectory = helpers.localTestDirectory(testBucket); | ||
var streamCache = new StreamCache(testDirectory, { defaultTtl: -1 }); | ||
var streamCreateCount = 0; | ||
var cachedStream = streamCache.get(cacheKey, {}, function() { | ||
streamCreateCount++; | ||
return helpers.createStream(streamContent + " - first create").end(); | ||
}); | ||
cachedStream.on('data', function() { /* do nothing */ }); | ||
cachedStream.on('error', function(e) { rmrf(testDirectory); done(e); }); | ||
cachedStream.on('end', function() { next(); }); | ||
function next() { | ||
var content = streamContent + " - second create"; | ||
var freshStream = streamCache.get(cacheKey, {}, function() { | ||
streamCreateCount++; | ||
return helpers.createStream(content).end(); | ||
}); | ||
var bufferedContent = ""; | ||
freshStream.on('data', function(data) { | ||
bufferedContent += data.toString(); | ||
}); | ||
freshStream.on('error', function(e) { rmrf(testDirectory); done(e); }); | ||
freshStream.on('end', function() { | ||
rmrf(testDirectory); | ||
assert.equal(streamCreateCount, 2); | ||
assert.equal(bufferedContent, content); | ||
done(); | ||
}); | ||
} | ||
}); | ||
it("should, if the cache key does not exist, create a new stream using the callback and cache it", function(done) { | ||
@@ -64,0 +117,0 @@ var streamContent = 'my test stream content'; |
@@ -8,2 +8,3 @@ 'use strict'; | ||
var StreamCache = require('../index'); | ||
var assert = require('assert'); | ||
@@ -63,2 +64,38 @@ function localTestDirectory(bucket) { | ||
function testIsStale(defaultTtl, isExpectedStale, done) { | ||
var streamContent = 'my test stream content'; | ||
var testBucket = "isStale#true"; | ||
var testDirectory = localTestDirectory(testBucket); | ||
var cacheKey = 'cachekey'; | ||
var streamCache = new StreamCache(testDirectory, { defaultTtl: defaultTtl }); | ||
var cachedStream = streamCache.get(cacheKey, {}, function() { | ||
return createStream(streamContent).end(); | ||
}); | ||
cachedStream.on('error', function(e) { | ||
rmrf(testDirectory); | ||
done(e); | ||
}); | ||
var bufferedData = ''; | ||
cachedStream.on('data', function(data) { | ||
bufferedData += data.toString(); | ||
}); | ||
cachedStream.on('end', function() { | ||
streamCache.isStale(cacheKey).then(function(isStale) { | ||
assert.equal(isExpectedStale, isStale); | ||
rmrf(testDirectory); | ||
done(); | ||
}).catch(function(e) { | ||
rmrf(testDirectory); | ||
done(e); | ||
}); | ||
}); | ||
} | ||
module.exports = { | ||
@@ -68,3 +105,4 @@ localTestDirectory: localTestDirectory, | ||
testPurgeFunction: testPurgeFunction, | ||
testIsStale: testIsStale, | ||
createStream: createStream | ||
}; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
18780
452
1
4
7