|
'use strict'; |
|
|
|
var throttle = require('throttleit'); |
|
|
|
function onRequest(context) { |
|
|
|
context.startedAt = null; |
|
|
|
context.state = context.request.progressState = null; |
|
|
|
context.delayTimer && clearTimeout(context.delayTimer); |
|
context.delayTimer = null; |
|
} |
|
|
|
function onResponse(context, response) { |
|
|
|
context.startedAt = Date.now(); |
|
|
|
|
|
|
|
|
|
context.state = context.request.progressState = { |
|
time: { |
|
elapsed: 0, |
|
remaining: null |
|
}, |
|
speed: null, |
|
percent: null, |
|
size: { |
|
total: Number(response.headers[context.options.lengthHeader]) || null, |
|
transferred: 0 |
|
} |
|
}; |
|
|
|
|
|
context.delayTimer = setTimeout(function () { |
|
context.delayTimer = null; |
|
}, context.options.delay); |
|
} |
|
|
|
function onData(context, data) { |
|
context.state.size.transferred += data.length; |
|
|
|
!context.delayTimer && context.reportState(); |
|
} |
|
|
|
function onEnd(context) { |
|
|
|
if (context.delayTimer) { |
|
clearTimeout(context.delayTimer); |
|
context.delayTimer = null; |
|
} |
|
|
|
context.request.progressState = context.request.progressContext = null; |
|
} |
|
|
|
function reportState(context) { |
|
var state; |
|
|
|
|
|
if (context.delayTimer || !context.request.progressState) { |
|
return; |
|
} |
|
|
|
state = context.state; |
|
state.time.elapsed = (Date.now() - context.startedAt) / 1000; |
|
|
|
|
|
if (state.time.elapsed >= 1) { |
|
state.speed = state.size.transferred / state.time.elapsed; |
|
} |
|
|
|
|
|
if (state.size.total != null) { |
|
state.percent = Math.min(state.size.transferred, state.size.total) / state.size.total; |
|
|
|
if (state.speed != null) { |
|
state.time.remaining = state.percent !== 1 ? (state.size.total / state.speed) - state.time.elapsed : 0; |
|
state.time.remaining = Math.round(state.time.remaining * 1000) / 1000; |
|
} |
|
} |
|
|
|
context.request.emit('progress', state); |
|
} |
|
|
|
|
|
function requestProgress(request, options) { |
|
var context; |
|
|
|
if (request.progressContext) { |
|
return request; |
|
} |
|
|
|
if (request.response) { |
|
throw new Error('Already got response, it\'s too late to track progress'); |
|
} |
|
|
|
|
|
options = options || {}; |
|
options.throttle = options.throttle == null ? 1000 : options.throttle; |
|
options.delay = options.delay || 0; |
|
options.lengthHeader = options.lengthHeader || 'content-length'; |
|
|
|
|
|
context = {}; |
|
context.request = request; |
|
context.options = options; |
|
context.reportState = throttle(reportState.bind(null, context), options.throttle); |
|
|
|
|
|
|
|
|
|
|
|
request |
|
.on('request', onRequest.bind(null, context)) |
|
.on('response', function handleResponse(response) { |
|
response.on('data', onData.bind(null, context)); |
|
|
|
return onResponse(context, response); |
|
}) |
|
.on('end', onEnd.bind(null, context)); |
|
|
|
request.progressContext = context; |
|
|
|
return request; |
|
} |
|
|
|
module.exports = requestProgress; |
|
|