File size: 3,560 Bytes
bc20498 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
'use strict';
var throttle = require('throttleit');
function onRequest(context) {
// Reset dynamic stuff
context.startedAt = null;
context.state = context.request.progressState = null;
context.delayTimer && clearTimeout(context.delayTimer);
context.delayTimer = null;
}
function onResponse(context, response) {
// Mark start timestamp
context.startedAt = Date.now();
// Create state
// Also expose the state throught the request
// See https://github.com/IndigoUnited/node-request-progress/pull/2/files
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
}
};
// Delay the progress report
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) {
/* istanbul ignore if */
if (context.delayTimer) {
clearTimeout(context.delayTimer);
context.delayTimer = null;
}
context.request.progressState = context.request.progressContext = null;
}
function reportState(context) {
var state;
// Do nothing if still within the initial delay or if already finished
if (context.delayTimer || !context.request.progressState) {
return;
}
state = context.state;
state.time.elapsed = (Date.now() - context.startedAt) / 1000;
// Calculate speed only if 1s has passed
if (state.time.elapsed >= 1) {
state.speed = state.size.transferred / state.time.elapsed;
}
// Calculate percent & remaining only if we know the total size
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; // Round to 4 decimals
}
}
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');
}
// Parse options
options = options || {};
options.throttle = options.throttle == null ? 1000 : options.throttle;
options.delay = options.delay || 0;
options.lengthHeader = options.lengthHeader || 'content-length';
// Create context
context = {};
context.request = request;
context.options = options;
context.reportState = throttle(reportState.bind(null, context), options.throttle);
// context.startedAt = null;
// context.state = null;
// context.delayTimer = null;
// Attach listeners
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;
|