v1.0.0
This commit is contained in:
parent
83f40cbb8c
commit
6ab74cf093
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
||||||
# https://git-scm.com/docs/gitignore
|
# https://git-scm.com/docs/gitignore
|
||||||
# https://help.github.com/articles/ignoring-files
|
# https://help.github.com/articles/ignoring-files
|
||||||
# Example .gitignore files: https://github.com/github/gitignore
|
# Example .gitignore files: https://github.com/github/gitignore
|
||||||
|
/node_modules/
|
||||||
|
|
89
README.md
Normal file
89
README.md
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
# stream-length
|
||||||
|
|
||||||
|
Attempts to determine the total content length of a Stream or Buffer.
|
||||||
|
|
||||||
|
Supports both Promises and nodebacks.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[WTFPL](http://www.wtfpl.net/txt/copying/) or [CC0](https://creativecommons.org/publicdomain/zero/1.0/), whichever you prefer.
|
||||||
|
|
||||||
|
## Donate
|
||||||
|
|
||||||
|
My income consists entirely of donations for my projects. If this module is useful to you, consider [making a donation](http://cryto.net/~joepie91/donate.html)!
|
||||||
|
|
||||||
|
You can donate using Bitcoin, PayPal, Gratipay, Flattr, cash-in-mail, SEPA transfers, and pretty much anything else.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Pull requests welcome. Please make sure your modifications are in line with the overall code style, and ensure that you're editing the `.coffee` files, not the `.js` files.
|
||||||
|
|
||||||
|
Build tool of choice is `gulp`; simply run `gulp` while developing, and it will watch for changes.
|
||||||
|
|
||||||
|
Be aware that by making a pull request, you agree to release your modifications under the licenses stated above.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Using Promises:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var streamLength = require("stream-length");
|
||||||
|
|
||||||
|
Promise.try(function(){
|
||||||
|
return streamLength(fs.createReadStream("README.md"));
|
||||||
|
})
|
||||||
|
.then(function(result){
|
||||||
|
console.log("The length of README.md is " + result);
|
||||||
|
})
|
||||||
|
.catch(function(err){
|
||||||
|
console.log("Could not determine length. Error: " + err.toString());
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Using nodebacks:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var streamLength = require("stream-length");
|
||||||
|
|
||||||
|
streamLength(fs.createReadStream("README.md"), {}, function(err, result){
|
||||||
|
if(err)
|
||||||
|
{
|
||||||
|
console.log("Could not determine length. Error: " + err.toString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
console.log("The length of README.md is " + result);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Custom lengthRetrievers:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
Promise.try(function(){
|
||||||
|
return streamLength(fs.createReadStream("README.md"), [
|
||||||
|
function(stream, callback){
|
||||||
|
doSomethingWith(stream, function(err, len){
|
||||||
|
callback(err ? err : len);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
.then(function(result){
|
||||||
|
console.log("The length of README.md is " + result);
|
||||||
|
})
|
||||||
|
.catch(function(err){
|
||||||
|
console.log("Could not determine length. Error: " + err.toString());
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
### streamLength(stream, [options, [callback]])
|
||||||
|
|
||||||
|
Determines the length of `stream`, which can be a supported type of Stream or a Buffer. Optionally you can specify `options`:
|
||||||
|
|
||||||
|
* __lengthRetrievers__: An array of (potentially asynchronous) functions for establishing stream lengths. You can specify one or more of these if you wish to extend `stream-length`s list of supported Stream types. Each retriever function is called with a signature of `(stream, callback)` where `stream` is the stream in question, and `callback` can be called with the result. If an Error occurs, simply pass the Error to the callback instead of the value.
|
||||||
|
|
||||||
|
If you define a `callback`, it will be treated as a nodeback and called when the function completes. If you don't, the function will return a Promise that resolves when the function completes.
|
1
index.coffee
Normal file
1
index.coffee
Normal file
|
@ -0,0 +1 @@
|
||||||
|
module.exports = require "./lib/stream-length"
|
75
lib/stream-length.coffee
Normal file
75
lib/stream-length.coffee
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
Promise = require "bluebird"
|
||||||
|
fs = Promise.promisifyAll(require "fs")
|
||||||
|
|
||||||
|
nodeifyWrapper = (callback, func) ->
|
||||||
|
func().nodeify(callback)
|
||||||
|
|
||||||
|
createRetrieverPromise = (stream, retriever) ->
|
||||||
|
new Promise (resolve, reject) ->
|
||||||
|
retriever stream, (result) ->
|
||||||
|
if result?
|
||||||
|
if result instanceof Error
|
||||||
|
console.log "REJECTING...", result
|
||||||
|
reject result
|
||||||
|
else
|
||||||
|
resolve result
|
||||||
|
else
|
||||||
|
reject new Error("Could not find a length using this lengthRetriever.")
|
||||||
|
|
||||||
|
retrieveBuffer = (stream, callback) ->
|
||||||
|
if stream instanceof Buffer
|
||||||
|
callback stream.length
|
||||||
|
else
|
||||||
|
callback null
|
||||||
|
|
||||||
|
retrieveFilesystemStream = (stream, callback) ->
|
||||||
|
if stream.hasOwnProperty "fd"
|
||||||
|
# FIXME: https://github.com/joyent/node/issues/7819
|
||||||
|
if stream.end != undefined and stream.end != Infinity and stream.start != undefined
|
||||||
|
# A stream start and end were defined, we can calculate the size just from that information.
|
||||||
|
callback(stream.end + 1 - (stream.start ? 0))
|
||||||
|
else
|
||||||
|
# We have the start offset at most, stat the file and work off the filesize.
|
||||||
|
Promise.try ->
|
||||||
|
fs.statAsync stream.path
|
||||||
|
.then (stat) ->
|
||||||
|
callback(stat.size - (stream.start ? 0))
|
||||||
|
.catch (err) ->
|
||||||
|
callback err
|
||||||
|
else
|
||||||
|
callback null
|
||||||
|
|
||||||
|
retrieveCoreHttpStream = (stream, callback) ->
|
||||||
|
if stream.hasOwnProperty("httpVersion") and stream.headers["content-length"]?
|
||||||
|
callback parseInt(stream.headers["content-length"])
|
||||||
|
else
|
||||||
|
callback null
|
||||||
|
|
||||||
|
retrieveRequestHttpStream = (stream, callback) ->
|
||||||
|
if stream.hasOwnProperty "httpModule"
|
||||||
|
stream.on "response", (response) ->
|
||||||
|
if response.headers["content-length"]?
|
||||||
|
callback parseInt(response.headers["content-length"])
|
||||||
|
else
|
||||||
|
callback null
|
||||||
|
else
|
||||||
|
callback null
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = (stream, options = {}, callback) ->
|
||||||
|
nodeifyWrapper callback, ->
|
||||||
|
retrieverPromises = []
|
||||||
|
|
||||||
|
if options.lengthRetrievers?
|
||||||
|
# First, the custom length retrievers, if any.
|
||||||
|
for retriever in options.lengthRetrievers
|
||||||
|
retrieverPromises.push createRetrieverPromise(stream, retriever)
|
||||||
|
|
||||||
|
# Then, the standard ones.
|
||||||
|
for retriever in [retrieveBuffer, retrieveFilesystemStream, retrieveCoreHttpStream, retrieveRequestHttpStream]
|
||||||
|
retrieverPromises.push createRetrieverPromise(stream, retriever)
|
||||||
|
|
||||||
|
Promise.any retrieverPromises
|
||||||
|
|
||||||
|
|
||||||
|
|
26
package.json
Normal file
26
package.json
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"name": "node-stream-length",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "For a given Buffer or Stream, this module will attempt to determine the total length of the stream contents. It currently supports Buffers, `fs` streams, `http` responses, and `request` objects, and allows for specifying custom stream types.",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git://github.com/joepie91/node-stream-length"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"stream",
|
||||||
|
"length",
|
||||||
|
"content-length"
|
||||||
|
],
|
||||||
|
"author": "Sven Slootweg",
|
||||||
|
"license": "WTFPL",
|
||||||
|
"dependencies": {
|
||||||
|
"bluebird": "^2.6.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"request": "^2.51.0"
|
||||||
|
}
|
||||||
|
}
|
59
test-any.coffee
Normal file
59
test-any.coffee
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
# This is a test case for petkaantonov/bluebird#432, encountered during development of this module.
|
||||||
|
|
||||||
|
Promise = require "bluebird"
|
||||||
|
|
||||||
|
successPromise = (val) ->
|
||||||
|
new Promise (resolve, reject) ->
|
||||||
|
process.nextTick -> resolve(val)
|
||||||
|
|
||||||
|
failurePromise = (val) ->
|
||||||
|
new Promise (resolve, reject) ->
|
||||||
|
process.nextTick -> reject(val)
|
||||||
|
|
||||||
|
|
||||||
|
successSyncPromise = (val) ->
|
||||||
|
new Promise (resolve, reject) ->
|
||||||
|
resolve(val)
|
||||||
|
|
||||||
|
failureSyncPromise = (val) ->
|
||||||
|
new Promise (resolve, reject) ->
|
||||||
|
reject(val)
|
||||||
|
|
||||||
|
failureSyncPromiseTwo = (val) ->
|
||||||
|
Promise.reject(val)
|
||||||
|
|
||||||
|
|
||||||
|
Promise.any [
|
||||||
|
successSyncPromise()
|
||||||
|
successPromise()
|
||||||
|
failureSyncPromise("fail a").catch (err) -> console.log err
|
||||||
|
]
|
||||||
|
.then -> console.log "success a"
|
||||||
|
|
||||||
|
Promise.any [
|
||||||
|
successSyncPromise()
|
||||||
|
successPromise()
|
||||||
|
failurePromise("fail b").catch (err) -> console.log err
|
||||||
|
]
|
||||||
|
.then -> console.log "success b"
|
||||||
|
|
||||||
|
Promise.any [
|
||||||
|
successPromise()
|
||||||
|
successPromise()
|
||||||
|
failurePromise("fail c").catch (err) -> console.log err
|
||||||
|
]
|
||||||
|
.then -> console.log "success c"
|
||||||
|
|
||||||
|
Promise.any [
|
||||||
|
successSyncPromise()
|
||||||
|
successSyncPromise()
|
||||||
|
failureSyncPromise("fail d").catch (err) -> console.log err
|
||||||
|
]
|
||||||
|
.then -> console.log "success d"
|
||||||
|
|
||||||
|
Promise.any [
|
||||||
|
successSyncPromise()
|
||||||
|
successSyncPromise()
|
||||||
|
failureSyncPromiseTwo("fail e").catch (err) -> console.log err
|
||||||
|
]
|
||||||
|
.then -> console.log "success e"
|
57
test.coffee
Normal file
57
test.coffee
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
streamLength = require "./"
|
||||||
|
fs = require "fs"
|
||||||
|
request = require "request"
|
||||||
|
http = require "http"
|
||||||
|
Promise = require "bluebird"
|
||||||
|
|
||||||
|
Promise.try ->
|
||||||
|
console.log "Length of fs:README.md..."
|
||||||
|
streamLength fs.createReadStream("README.md")
|
||||||
|
.then (length) ->
|
||||||
|
console.log "Length", length
|
||||||
|
.catch (err) ->
|
||||||
|
console.log "No-Length", err
|
||||||
|
|
||||||
|
.then ->
|
||||||
|
console.log "Length of Buffer..."
|
||||||
|
streamLength new Buffer("testing buffer content length retrieval...")
|
||||||
|
.then (length) ->
|
||||||
|
console.log "Length", length
|
||||||
|
.catch (err) ->
|
||||||
|
console.log "No-Length", err
|
||||||
|
|
||||||
|
.then ->
|
||||||
|
console.log "Length of http:Google"
|
||||||
|
new Promise (resolve, reject) ->
|
||||||
|
http.get "http://www.google.com/images/srpr/logo11w.png", (res) ->
|
||||||
|
resolve res
|
||||||
|
.on "error", (err) ->
|
||||||
|
reject err
|
||||||
|
.then (res) ->
|
||||||
|
res.resume() # Drain the stream
|
||||||
|
streamLength res
|
||||||
|
.then (length) ->
|
||||||
|
console.log "Length", length
|
||||||
|
.catch (err) ->
|
||||||
|
console.log "No-Length", err
|
||||||
|
|
||||||
|
.then ->
|
||||||
|
console.log "Length of request:Google..."
|
||||||
|
streamLength request "http://www.google.com/images/srpr/logo11w.png", (err, res, body) ->
|
||||||
|
# Ignore...
|
||||||
|
.then (length) ->
|
||||||
|
console.log "Length", length
|
||||||
|
.catch (err) ->
|
||||||
|
console.log "No-Length", err
|
||||||
|
|
||||||
|
.then ->
|
||||||
|
console.log "Length of request:Google:fail..."
|
||||||
|
streamLength request "http://www.google.com/", (err, res, body) ->
|
||||||
|
# Ignore...
|
||||||
|
.then (length) ->
|
||||||
|
console.log "Length", length
|
||||||
|
.catch (err) ->
|
||||||
|
console.log "No-Length", err
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue