Projekt

Obecné

Profil

Stáhnout (3.6 KB) Statistiky
| Větev: | Revize:
1
/*!
2
 * on-finished
3
 * Copyright(c) 2013 Jonathan Ong
4
 * Copyright(c) 2014 Douglas Christopher Wilson
5
 * MIT Licensed
6
 */
7

    
8
'use strict'
9

    
10
/**
11
 * Module exports.
12
 * @public
13
 */
14

    
15
module.exports = onFinished
16
module.exports.isFinished = isFinished
17

    
18
/**
19
 * Module dependencies.
20
 * @private
21
 */
22

    
23
var first = require('ee-first')
24

    
25
/**
26
 * Variables.
27
 * @private
28
 */
29

    
30
/* istanbul ignore next */
31
var defer = typeof setImmediate === 'function'
32
  ? setImmediate
33
  : function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) }
34

    
35
/**
36
 * Invoke callback when the response has finished, useful for
37
 * cleaning up resources afterwards.
38
 *
39
 * @param {object} msg
40
 * @param {function} listener
41
 * @return {object}
42
 * @public
43
 */
44

    
45
function onFinished(msg, listener) {
46
  if (isFinished(msg) !== false) {
47
    defer(listener, null, msg)
48
    return msg
49
  }
50

    
51
  // attach the listener to the message
52
  attachListener(msg, listener)
53

    
54
  return msg
55
}
56

    
57
/**
58
 * Determine if message is already finished.
59
 *
60
 * @param {object} msg
61
 * @return {boolean}
62
 * @public
63
 */
64

    
65
function isFinished(msg) {
66
  var socket = msg.socket
67

    
68
  if (typeof msg.finished === 'boolean') {
69
    // OutgoingMessage
70
    return Boolean(msg.finished || (socket && !socket.writable))
71
  }
72

    
73
  if (typeof msg.complete === 'boolean') {
74
    // IncomingMessage
75
    return Boolean(msg.upgrade || !socket || !socket.readable || (msg.complete && !msg.readable))
76
  }
77

    
78
  // don't know
79
  return undefined
80
}
81

    
82
/**
83
 * Attach a finished listener to the message.
84
 *
85
 * @param {object} msg
86
 * @param {function} callback
87
 * @private
88
 */
89

    
90
function attachFinishedListener(msg, callback) {
91
  var eeMsg
92
  var eeSocket
93
  var finished = false
94

    
95
  function onFinish(error) {
96
    eeMsg.cancel()
97
    eeSocket.cancel()
98

    
99
    finished = true
100
    callback(error)
101
  }
102

    
103
  // finished on first message event
104
  eeMsg = eeSocket = first([[msg, 'end', 'finish']], onFinish)
105

    
106
  function onSocket(socket) {
107
    // remove listener
108
    msg.removeListener('socket', onSocket)
109

    
110
    if (finished) return
111
    if (eeMsg !== eeSocket) return
112

    
113
    // finished on first socket event
114
    eeSocket = first([[socket, 'error', 'close']], onFinish)
115
  }
116

    
117
  if (msg.socket) {
118
    // socket already assigned
119
    onSocket(msg.socket)
120
    return
121
  }
122

    
123
  // wait for socket to be assigned
124
  msg.on('socket', onSocket)
125

    
126
  if (msg.socket === undefined) {
127
    // node.js 0.8 patch
128
    patchAssignSocket(msg, onSocket)
129
  }
130
}
131

    
132
/**
133
 * Attach the listener to the message.
134
 *
135
 * @param {object} msg
136
 * @return {function}
137
 * @private
138
 */
139

    
140
function attachListener(msg, listener) {
141
  var attached = msg.__onFinished
142

    
143
  // create a private single listener with queue
144
  if (!attached || !attached.queue) {
145
    attached = msg.__onFinished = createListener(msg)
146
    attachFinishedListener(msg, attached)
147
  }
148

    
149
  attached.queue.push(listener)
150
}
151

    
152
/**
153
 * Create listener on message.
154
 *
155
 * @param {object} msg
156
 * @return {function}
157
 * @private
158
 */
159

    
160
function createListener(msg) {
161
  function listener(err) {
162
    if (msg.__onFinished === listener) msg.__onFinished = null
163
    if (!listener.queue) return
164

    
165
    var queue = listener.queue
166
    listener.queue = null
167

    
168
    for (var i = 0; i < queue.length; i++) {
169
      queue[i](err, msg)
170
    }
171
  }
172

    
173
  listener.queue = []
174

    
175
  return listener
176
}
177

    
178
/**
179
 * Patch ServerResponse.prototype.assignSocket for node.js 0.8.
180
 *
181
 * @param {ServerResponse} res
182
 * @param {function} callback
183
 * @private
184
 */
185

    
186
function patchAssignSocket(res, callback) {
187
  var assignSocket = res.assignSocket
188

    
189
  if (typeof assignSocket !== 'function') return
190

    
191
  // res.on('socket', callback) is broken in 0.8
192
  res.assignSocket = function _assignSocket(socket) {
193
    assignSocket.call(this, socket)
194
    callback(socket)
195
  }
196
}
(4-4/5)