[Pkg-javascript-commits] [node-finished] 01/02: Imported Upstream version 1.2.2

Leo Iannacone l3on-guest at moszumanska.debian.org
Sat Jul 5 17:43:24 UTC 2014


This is an automated email from the git hooks/post-receive script.

l3on-guest pushed a commit to branch master
in repository node-finished.

commit cb0407b8fb903bb1d71873511150a058af666d73
Author: Leo Iannacone <l3on at ubuntu.com>
Date:   Sat Jul 5 19:09:55 2014 +0200

    Imported Upstream version 1.2.2
---
 .npmignore   |   3 ++
 .travis.yml  |  11 +++++
 HISTORY.md   |  50 ++++++++++++++++++++
 README.md    |  88 ++++++++++++++++++++++++++++++++++
 index.js     |  62 ++++++++++++++++++++++++
 package.json |  24 ++++++++++
 test/test.js | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 390 insertions(+)

diff --git a/.npmignore b/.npmignore
new file mode 100644
index 0000000..cd39b77
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1,3 @@
+coverage/
+test/
+.travis.yml
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..1ff243c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,11 @@
+language: node_js
+node_js:
+  - "0.8"
+  - "0.10"
+  - "0.11"
+matrix:
+  allow_failures:
+    - node_js: "0.11"
+  fast_finish: true
+script: "npm run-script test-travis"
+after_script: "npm install coveralls at 2.10.0 && cat ./coverage/lcov.info | coveralls"
diff --git a/HISTORY.md b/HISTORY.md
new file mode 100644
index 0000000..8937250
--- /dev/null
+++ b/HISTORY.md
@@ -0,0 +1,50 @@
+1.2.2 / 2014-06-10
+==========
+
+  * reduce listeners added to emitters
+    - avoids "event emitter leak" warnings when used multiple times on same request
+
+1.2.1 / 2014-06-08
+==================
+
+  * fix returned value when already finished
+
+1.2.0 / 2014-06-05
+==================
+
+  * call callback when called on already-finished socket
+
+1.1.4 / 2014-05-27
+==================
+
+  * support node.js 0.8
+
+1.1.3 / 2014-04-30
+==================
+
+  * make sure errors passed as instanceof `Error`
+
+1.1.2 / 2014-04-18
+==================
+
+  * default the `socket` to passed-in object
+
+1.1.1 / 2014-01-16
+==================
+
+  * rename module to `finished`
+
+1.1.0 / 2013-12-25
+==================
+
+  * call callback when called on already-errored socket
+
+1.0.1 / 2013-12-20
+==================
+
+  * actually pass the error to the callback
+
+1.0.0 / 2013-12-20
+==================
+
+  * Initial release
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..79facd5
--- /dev/null
+++ b/README.md
@@ -0,0 +1,88 @@
+# finished
+
+[![NPM Version](https://badge.fury.io/js/finished.svg)](http://badge.fury.io/js/finished)
+[![Build Status](https://travis-ci.org/expressjs/finished.svg?branch=master)](https://travis-ci.org/expressjs/finished)
+[![Coverage Status](https://img.shields.io/coveralls/expressjs/finished.svg?branch=master)](https://coveralls.io/r/expressjs/finished)
+
+Execute a callback when a request closes, finishes, or errors.
+
+#### Install
+
+```sh
+$ npm install finished
+```
+
+#### Uses
+
+This is useful for cleaning up streams. For example, you want to destroy any file streams you create on socket errors otherwise you will leak file descriptors.
+
+This is required to fix what many perceive as issues with node's streams. Relevant:
+
+- [node#6041](https://github.com/joyent/node/issues/6041)
+- [koa#184](https://github.com/koajs/koa/issues/184)
+- [koa#165](https://github.com/koajs/koa/issues/165)
+
+## API
+
+### finished(response, callback)
+
+```js
+var onFinished = require('finished')
+
+onFinished(res, function (err) {
+  // do something maybe
+})
+```
+
+### Examples
+
+The following code ensures that file descriptors are always closed once the response finishes.
+
+#### Node / Connect / Express
+
+```js
+var onFinished = require('finished')
+
+function (req, res, next) {
+  var stream = fs.createReadStream('thingie.json')
+  stream.pipe(res)
+  onFinished(res, function (err) {
+    stream.destroy()
+  })
+}
+```
+
+#### Koa
+
+```js
+function* () {
+  var stream = this.body = fs.createReadStream('thingie.json')
+  onFinished(this, function (err) {
+    stream.destroy()
+  })
+}
+```
+
+## License
+
+The MIT License (MIT)
+
+Copyright (c) 2013 Jonathan Ong me at jongleberry.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..90709d4
--- /dev/null
+++ b/index.js
@@ -0,0 +1,62 @@
+/*!
+ * finished
+ * Copyright(c) 2014 Jonathan Ong
+ * MIT Licensed
+ */
+
+/**
+* Module dependencies.
+*/
+
+var first = require('ee-first')
+
+/**
+* Variables.
+*/
+
+/* istanbul ignore next */
+var defer = typeof setImmediate === 'function'
+  ? setImmediate
+  : function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) }
+
+/**
+ * Invoke callback when the response has finished, useful for
+ * cleaning up resources afterwards.
+ *
+ * @param {object} thingie
+ * @param {function} callback
+ * @return {object}
+ * @api public
+ */
+
+module.exports = function finished(thingie, callback) {
+  var socket = thingie.socket || thingie
+  var res = thingie.res || thingie
+
+  if (res.finished || !socket.writable) {
+    defer(callback)
+    return thingie
+  }
+
+  var listener = res.__onFinished
+
+  // create a private single listener with queue
+  if (!listener || !listener.queue) {
+    listener = res.__onFinished = function onFinished(err) {
+      if (res.__onFinished === listener) res.__onFinished = null
+      var queue = listener.queue || []
+      while (queue.length) queue.shift()(err)
+    }
+    listener.queue = []
+
+    // finished on first event
+    first([
+      [socket, 'error', 'close'],
+      [res, 'finish'],
+    ], listener)
+  }
+
+  listener.queue.push(callback)
+
+  return thingie
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..ab0d433
--- /dev/null
+++ b/package.json
@@ -0,0 +1,24 @@
+{
+  "name": "finished",
+  "description": "Execute a callback when a request closes, finishes, or errors",
+  "version": "1.2.2",
+  "author": "Jonathan Ong <me at jongleberry.com> (http://jongleberry.com)",
+  "license": "MIT",
+  "repository": "expressjs/finished",
+  "dependencies": {
+    "ee-first": "1.0.3"
+  },
+  "devDependencies": {
+    "istanbul": "0.2.10",
+    "mocha": "~1.20.1",
+    "should": "~4.0.1"
+  },
+  "engine": {
+    "node": ">= 0.8.0"
+  },
+  "scripts": {
+    "test": "mocha --reporter spec test/",
+    "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot test/",
+    "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec test/"
+  }
+}
diff --git a/test/test.js b/test/test.js
new file mode 100644
index 0000000..61f794c
--- /dev/null
+++ b/test/test.js
@@ -0,0 +1,152 @@
+
+var EventEmitter = require('events').EventEmitter
+var should = require('should')
+var assert = require('assert')
+var http = require('http')
+
+var onFinished = require('..')
+
+function createThingie() {
+  var ee = new EventEmitter
+  ee.socket = new EventEmitter
+  ee.socket.writable = true
+  return ee
+}
+
+describe('on socket error', function () {
+  it('should execute the callback on socket error', function () {
+    var thingie = createThingie()
+    var called = false
+    onFinished(thingie, function (err) {
+      called = true
+      err.message.should.equal('boom')
+    })
+    thingie.socket.emit('error', new Error('boom'))
+    called.should.be.true
+  })
+
+  it('should not execute the callback if response is finished', function (done) {
+    var thingie = createThingie()
+    onFinished(thingie, function (err) {
+      assert.ifError(err)
+      done()
+    })
+    thingie.emit('finish')
+    thingie.socket.emit(new Error('boom'))
+  })
+})
+
+describe('when the socket is not writable', function () {
+  it('should execute the callback immediately', function (done) {
+    var thingie = createThingie()
+    thingie.socket.writable = false
+    onFinished(thingie, function (err) {
+      done()
+    })
+  })
+})
+
+describe('when the socket closes', function () {
+  it('should execute the callback', function (done) {
+    var thingie = createThingie()
+    onFinished(thingie, done)
+    thingie.socket.emit('close')
+  })
+})
+
+describe('when an emitter emits a non-error', function () {
+  it('should ignore the error', function (done) {
+    var thingie = createThingie()
+    onFinished(thingie, done)
+    thingie.socket.emit('close', false)
+  })
+})
+
+describe('http', function () {
+  describe('when the request finishes', function () {
+    it('should execute the callback', function (done) {
+      var server = http.createServer(function (req, res) {
+        onFinished(res, done)
+        setTimeout(res.end.bind(res), 0)
+      })
+      server.listen(function () {
+        var port = this.address().port
+        http.get('http://127.0.0.1:' + port, function (res) {
+          res.resume()
+          res.on('close', server.close.bind(server))
+        })
+      })
+    })
+
+    it('should execute the callback when called after finish', function (done) {
+      var server = http.createServer(function (req, res) {
+        onFinished(res, function () {
+          onFinished(res, done)
+        })
+        setTimeout(res.end.bind(res), 0)
+      })
+      server.listen(function () {
+        var port = this.address().port
+        http.get('http://127.0.0.1:' + port, function (res) {
+          res.resume()
+          res.on('close', server.close.bind(server))
+        })
+      })
+    })
+  })
+
+  describe('when the request aborts', function () {
+    it('should execute the callback', function (done) {
+      var client
+      var server = http.createServer(function (req, res) {
+        onFinished(res, done)
+        setTimeout(client.abort.bind(client), 0)
+      })
+      server.listen(function () {
+        var port = this.address().port
+        client = http.get('http://127.0.0.1:' + port)
+        client.on('error', function () {})
+      })
+    })
+  })
+})
+
+describe('event emitter leaks', function () {
+  describe('when adding a lot of listeners on the same request', function () {
+    it('should not warn and add at most 1 listener per emitter per event', function () {
+      // we just have to make sure tests pass without a bunch of logs
+      var thingie = createThingie()
+      var called = false
+
+      onFinished(thingie, function (err) {
+        called = true
+        err.message.should.equal('boom')
+      })
+
+      for (var i = 0; i < 1000; i++) {
+        onFinished(thingie, noop)
+      }
+
+      assert.equal(1, thingie.socket.listeners('error').length)
+      assert.equal(1, thingie.socket.listeners('close').length)
+      assert.equal(1, thingie.listeners('finish').length)
+
+      thingie.socket.emit('error', new Error('boom'))
+      called.should.be.true
+    })
+  })
+
+  it('should clean up after itself', function (done) {
+    var thingie = createThingie()
+    onFinished(thingie, function () {
+      assert(!thingie.socket.listeners('error').length)
+      assert(!thingie.socket.listeners('close').length)
+      assert(!thingie.listeners('finish').length)
+      done()
+    })
+
+    thingie.socket.emit('error')
+  })
+})
+
+function noop() {}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-finished.git



More information about the Pkg-javascript-commits mailing list