root / HServer / 00.Server / 00.Program / node_modules / on-finished / index.js
이력 | 보기 | 이력해설 | 다운로드 (3.6 KB)
1 | 39 | HKM | /*!
|
---|---|---|---|
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 | } |