arnaucube
arnaucube/socketioMEANseedPublic Self-hosted repository
socketioMEANseed/server/node_modules/on-finished/index.js
server/node_modules/on-finished/index.jsRaw
  1/*!
  2 * on-finished
  3 * Copyright(c) 2013 Jonathan Ong
  4 * Copyright(c) 2014 Douglas Christopher Wilson
  5 * MIT Licensed
  6 */
  7
  8/**
  9 * Module exports.
 10 */
 11
 12module.exports = onFinished;
 13module.exports.isFinished = isFinished;
 14
 15/**
 16* Module dependencies.
 17*/
 18
 19var first = require('ee-first')
 20
 21/**
 22* Variables.
 23*/
 24
 25/* istanbul ignore next */
 26var defer = typeof setImmediate === 'function'
 27  ? setImmediate
 28  : function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) }
 29
 30/**
 31 * Invoke callback when the response has finished, useful for
 32 * cleaning up resources afterwards.
 33 *
 34 * @param {object} msg
 35 * @param {function} listener
 36 * @return {object}
 37 * @api public
 38 */
 39
 40function onFinished(msg, listener) {
 41  if (isFinished(msg) !== false) {
 42    defer(listener)
 43    return msg
 44  }
 45
 46  // attach the listener to the message
 47  attachListener(msg, listener)
 48
 49  return msg
 50}
 51
 52/**
 53 * Determine if message is already finished.
 54 *
 55 * @param {object} msg
 56 * @return {boolean}
 57 * @api public
 58 */
 59
 60function isFinished(msg) {
 61  var socket = msg.socket
 62
 63  if (typeof msg.finished === 'boolean') {
 64    // OutgoingMessage
 65    return Boolean(msg.finished || (socket && !socket.writable))
 66  }
 67
 68  if (typeof msg.complete === 'boolean') {
 69    // IncomingMessage
 70    return Boolean(!socket || msg.complete || !socket.readable)
 71  }
 72
 73  // don't know
 74  return undefined
 75}
 76
 77/**
 78 * Attach a finished listener to the message.
 79 *
 80 * @param {object} msg
 81 * @param {function} callback
 82 * @private
 83 */
 84
 85function attachFinishedListener(msg, callback) {
 86  var eeMsg
 87  var eeSocket
 88  var finished = false
 89
 90  function onFinish(error) {
 91    eeMsg.cancel()
 92    eeSocket.cancel()
 93
 94    finished = true
 95    callback(error)
 96  }
 97
 98  // finished on first message event
 99  eeMsg = eeSocket = first([[msg, 'end', 'finish']], onFinish)
100
101  function onSocket(socket) {
102    // remove listener
103    msg.removeListener('socket', onSocket)
104
105    if (finished) return
106    if (eeMsg !== eeSocket) return
107
108    // finished on first socket event
109    eeSocket = first([[socket, 'error', 'close']], onFinish)
110  }
111
112  if (msg.socket) {
113    // socket already assigned
114    onSocket(msg.socket)
115    return
116  }
117
118  // wait for socket to be assigned
119  msg.on('socket', onSocket)
120
121  if (msg.socket === undefined) {
122    // node.js 0.8 patch
123    patchAssignSocket(msg, onSocket)
124  }
125}
126
127/**
128 * Attach the listener to the message.
129 *
130 * @param {object} msg
131 * @return {function}
132 * @api private
133 */
134
135function attachListener(msg, listener) {
136  var attached = msg.__onFinished
137
138  // create a private single listener with queue
139  if (!attached || !attached.queue) {
140    attached = msg.__onFinished = createListener(msg)
141    attachFinishedListener(msg, attached)
142  }
143
144  attached.queue.push(listener)
145}
146
147/**
148 * Create listener on message.
149 *
150 * @param {object} msg
151 * @return {function}
152 * @api private
153 */
154
155function createListener(msg) {
156  function listener(err) {
157    if (msg.__onFinished === listener) msg.__onFinished = null
158    if (!listener.queue) return
159
160    var queue = listener.queue
161    listener.queue = null
162
163    for (var i = 0; i < queue.length; i++) {
164      queue[i](err)
165    }
166  }
167
168  listener.queue = []
169
170  return listener
171}
172
173/**
174 * Patch ServerResponse.prototype.assignSocket for node.js 0.8.
175 *
176 * @param {ServerResponse} res
177 * @param {function} callback
178 * @private
179 */
180
181function patchAssignSocket(res, callback) {
182  var assignSocket = res.assignSocket
183
184  if (typeof assignSocket !== 'function') return
185
186  // res.on('socket', callback) is broken in 0.8
187  res.assignSocket = function _assignSocket(socket) {
188    assignSocket.call(this, socket)
189    callback(socket)
190  }
191}