3 var throttle = require('throttleit');
5 function onRequest(context) {
7 context.startedAt = null;
9 context.state = context.request.progressState = null;
11 context.delayTimer && clearTimeout(context.delayTimer);
12 context.delayTimer = null;
15 function onResponse(context, response) {
16 // Mark start timestamp
17 context.startedAt = Date.now();
20 // Also expose the state throught the request
21 // See https://github.com/IndigoUnited/node-request-progress/pull/2/files
22 context.state = context.request.progressState = {
30 total: Number(response.headers[context.options.lengthHeader]) || null,
35 // Delay the progress report
36 context.delayTimer = setTimeout(function () {
37 context.delayTimer = null;
38 }, context.options.delay);
41 function onData(context, data) {
42 context.state.size.transferred += data.length;
44 !context.delayTimer && context.reportState();
47 function onEnd(context) {
48 /* istanbul ignore if */
49 if (context.delayTimer) {
50 clearTimeout(context.delayTimer);
51 context.delayTimer = null;
54 context.request.progressState = context.request.progressContext = null;
57 function reportState(context) {
60 // Do nothing if still within the initial delay or if already finished
61 if (context.delayTimer || !context.request.progressState) {
65 state = context.state;
66 state.time.elapsed = (Date.now() - context.startedAt) / 1000;
68 // Calculate speed only if 1s has passed
69 if (state.time.elapsed >= 1) {
70 state.speed = state.size.transferred / state.time.elapsed;
73 // Calculate percentage & remaining only if we know the total size
74 if (state.size.total != null) {
75 state.percentage = Math.min(state.size.transferred, state.size.total) / state.size.total;
77 if (state.speed != null) {
78 state.time.remaining = state.percentage !== 1 ? (state.size.total / state.speed) - state.time.elapsed : 0;
79 state.time.remaining = Math.round(state.time.remaining * 1000) / 1000; // Round to 4 decimals
83 context.request.emit('progress', state);
87 function requestProgress(request, options) {
90 if (request.progressContext) {
94 if (request.response) {
95 throw new Error('Already got response, it\'s too late to track progress');
99 options = options || {};
100 options.throttle = options.throttle == null ? 1000 : options.throttle;
101 options.delay = options.delay || 0;
102 options.lengthHeader = options.lengthHeader || 'content-length';
106 context.request = request;
107 context.options = options;
108 context.reportState = throttle(reportState.bind(null, context), options.throttle);
109 // context.startedAt = null;
110 // context.state = null;
111 // context.delayTimer = null;
115 .on('request', onRequest.bind(null, context))
116 .on('response', onResponse.bind(null, context))
117 .on('data', onData.bind(null, context))
118 .on('end', onEnd.bind(null, context));
120 request.progressContext = context;
125 module.exports = requestProgress;