Version 1
[yaffs-website] / node_modules / request-progress / index.js
diff --git a/node_modules/request-progress/index.js b/node_modules/request-progress/index.js
new file mode 100644 (file)
index 0000000..c258b63
--- /dev/null
@@ -0,0 +1,125 @@
+'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,
+        percentage: 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 percentage & remaining only if we know the total size
+    if (state.size.total != null) {
+        state.percentage = Math.min(state.size.transferred, state.size.total) / state.size.total;
+
+        if (state.speed != null) {
+            state.time.remaining = state.percentage !== 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', onResponse.bind(null, context))
+    .on('data', onData.bind(null, context))
+    .on('end', onEnd.bind(null, context));
+
+    request.progressContext = context;
+
+    return request;
+}
+
+module.exports = requestProgress;