progress.js 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. 'use strict';
  2. const {Transform} = require('stream');
  3. module.exports = {
  4. download(response, emitter, downloadBodySize) {
  5. let downloaded = 0;
  6. return new Transform({
  7. transform(chunk, encoding, callback) {
  8. downloaded += chunk.length;
  9. const percent = downloadBodySize ? downloaded / downloadBodySize : 0;
  10. // Let `flush()` be responsible for emitting the last event
  11. if (percent < 1) {
  12. emitter.emit('downloadProgress', {
  13. percent,
  14. transferred: downloaded,
  15. total: downloadBodySize
  16. });
  17. }
  18. callback(null, chunk);
  19. },
  20. flush(callback) {
  21. emitter.emit('downloadProgress', {
  22. percent: 1,
  23. transferred: downloaded,
  24. total: downloadBodySize
  25. });
  26. callback();
  27. }
  28. });
  29. },
  30. upload(request, emitter, uploadBodySize) {
  31. const uploadEventFrequency = 150;
  32. let uploaded = 0;
  33. let progressInterval;
  34. emitter.emit('uploadProgress', {
  35. percent: 0,
  36. transferred: 0,
  37. total: uploadBodySize
  38. });
  39. request.once('error', () => {
  40. clearInterval(progressInterval);
  41. });
  42. request.once('response', () => {
  43. clearInterval(progressInterval);
  44. emitter.emit('uploadProgress', {
  45. percent: 1,
  46. transferred: uploaded,
  47. total: uploadBodySize
  48. });
  49. });
  50. request.once('socket', socket => {
  51. const onSocketConnect = () => {
  52. progressInterval = setInterval(() => {
  53. const lastUploaded = uploaded;
  54. /* istanbul ignore next: see #490 (occurs randomly!) */
  55. const headersSize = request._header ? Buffer.byteLength(request._header) : 0;
  56. uploaded = socket.bytesWritten - headersSize;
  57. // Don't emit events with unchanged progress and
  58. // prevent last event from being emitted, because
  59. // it's emitted when `response` is emitted
  60. if (uploaded === lastUploaded || uploaded === uploadBodySize) {
  61. return;
  62. }
  63. emitter.emit('uploadProgress', {
  64. percent: uploadBodySize ? uploaded / uploadBodySize : 0,
  65. transferred: uploaded,
  66. total: uploadBodySize
  67. });
  68. }, uploadEventFrequency);
  69. };
  70. /* istanbul ignore next: hard to test */
  71. if (socket.connecting) {
  72. socket.once('connect', onSocketConnect);
  73. } else if (socket.writable) {
  74. // The socket is being reused from pool,
  75. // so the connect event will not be emitted
  76. onSocketConnect();
  77. }
  78. });
  79. }
  80. };