Skip to content

Commit 58c12de

Browse files
jstewmonsindresorhus
authored andcommittedJul 22, 2018
Move upload progress plumbing to its own module (#531)
1 parent 75fd8d3 commit 58c12de

File tree

2 files changed

+71
-69
lines changed

2 files changed

+71
-69
lines changed
 

‎source/progress.js

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
'use strict';
2+
module.exports = {
3+
upload(req, emitter, uploadBodySize) {
4+
const uploadEventFrequency = 150;
5+
let uploaded = 0;
6+
let progressInterval;
7+
8+
emitter.emit('uploadProgress', {
9+
percent: 0,
10+
transferred: 0,
11+
total: uploadBodySize
12+
});
13+
14+
req.once('error', () => {
15+
clearInterval(progressInterval);
16+
});
17+
18+
req.once('response', () => {
19+
clearInterval(progressInterval);
20+
21+
emitter.emit('uploadProgress', {
22+
percent: 1,
23+
transferred: uploaded,
24+
total: uploadBodySize
25+
});
26+
});
27+
28+
req.once('socket', socket => {
29+
const onSocketConnect = () => {
30+
progressInterval = setInterval(() => {
31+
if (socket.destroyed) {
32+
clearInterval(progressInterval);
33+
return;
34+
}
35+
36+
const lastUploaded = uploaded;
37+
const headersSize = req._header ? Buffer.byteLength(req._header) : 0;
38+
uploaded = socket.bytesWritten - headersSize;
39+
40+
// Prevent the known issue of `bytesWritten` being larger than body size
41+
if (uploadBodySize && uploaded > uploadBodySize) {
42+
uploaded = uploadBodySize;
43+
}
44+
45+
// Don't emit events with unchanged progress and
46+
// prevent last event from being emitted, because
47+
// it's emitted when `response` is emitted
48+
if (uploaded === lastUploaded || uploaded === uploadBodySize) {
49+
return;
50+
}
51+
52+
emitter.emit('uploadProgress', {
53+
percent: uploadBodySize ? uploaded / uploadBodySize : 0,
54+
transferred: uploaded,
55+
total: uploadBodySize
56+
});
57+
}, uploadEventFrequency);
58+
};
59+
60+
if (socket.connecting) {
61+
socket.once('connect', onSocketConnect);
62+
} else {
63+
// The socket is being reused from pool,
64+
// so the connect event will not be emitted
65+
onSocketConnect();
66+
}
67+
});
68+
}
69+
};

‎source/request-as-event-emitter.js

+2-69
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const is = require('@sindresorhus/is');
99
const timedOut = require('./timed-out');
1010
const getBodySize = require('./get-body-size');
1111
const getResponse = require('./get-response');
12+
const progress = require('./progress');
1213
const {CacheError, UnsupportedProtocolError, MaxRedirectsError, RequestError} = require('./errors');
1314

1415
const getMethodRedirectCodes = new Set([300, 301, 302, 303, 304, 305, 307, 308]);
@@ -23,7 +24,6 @@ module.exports = (options = {}) => {
2324
let retryTries = 0;
2425
let redirectUrl;
2526
let uploadBodySize;
26-
let uploaded = 0;
2727

2828
const get = options => {
2929
if (options.protocol !== 'http:' && options.protocol !== 'https:') {
@@ -43,20 +43,9 @@ module.exports = (options = {}) => {
4343
fn = electron.net || electron.remote.net;
4444
}
4545

46-
let progressInterval;
47-
4846
const cacheableRequest = new CacheableRequest(fn.request, options.cache);
4947
const cacheReq = cacheableRequest(options, response => {
50-
clearInterval(progressInterval);
51-
52-
emitter.emit('uploadProgress', {
53-
percent: 1,
54-
transferred: uploaded,
55-
total: uploadBodySize
56-
});
57-
5848
const {statusCode} = response;
59-
6049
response.retryCount = retryCount;
6150
response.url = redirectUrl || requestUrl;
6251
response.requestUrl = requestUrl;
@@ -99,7 +88,6 @@ module.exports = (options = {}) => {
9988
emitter.emit('redirect', response, redirectOpts);
10089

10190
get(redirectOpts);
102-
10391
return;
10492
}
10593

@@ -127,8 +115,6 @@ module.exports = (options = {}) => {
127115
});
128116

129117
req.once('error', error => {
130-
clearInterval(progressInterval);
131-
132118
if (aborted) {
133119
return;
134120
}
@@ -141,62 +127,9 @@ module.exports = (options = {}) => {
141127
});
142128
});
143129

144-
emitter.once('request', req => {
145-
emitter.emit('uploadProgress', {
146-
percent: 0,
147-
transferred: 0,
148-
total: uploadBodySize
149-
});
150-
151-
const socket = req.connection;
152-
if (socket) {
153-
const onSocketConnect = () => {
154-
const uploadEventFrequency = 150;
155-
156-
progressInterval = setInterval(() => {
157-
if (socket.destroyed) {
158-
clearInterval(progressInterval);
159-
return;
160-
}
161-
162-
const lastUploaded = uploaded;
163-
const headersSize = req._header ? Buffer.byteLength(req._header) : 0;
164-
uploaded = socket.bytesWritten - headersSize;
165-
166-
// Prevent the known issue of `bytesWritten` being larger than body size
167-
if (uploadBodySize && uploaded > uploadBodySize) {
168-
uploaded = uploadBodySize;
169-
}
170-
171-
// Don't emit events with unchanged progress and
172-
// prevent last event from being emitted, because
173-
// it's emitted when `response` is emitted
174-
if (uploaded === lastUploaded || uploaded === uploadBodySize) {
175-
return;
176-
}
177-
178-
emitter.emit('uploadProgress', {
179-
percent: uploadBodySize ? uploaded / uploadBodySize : 0,
180-
transferred: uploaded,
181-
total: uploadBodySize
182-
});
183-
}, uploadEventFrequency);
184-
};
185-
186-
// Only subscribe to `connect` event if we're actually connecting a new
187-
// socket, otherwise if we're already connected (because this is a
188-
// keep-alive connection) do not bother. This is important since we won't
189-
// get a `connect` event for an already connected socket.
190-
if (socket.connecting) {
191-
socket.once('connect', onSocketConnect);
192-
} else {
193-
onSocketConnect();
194-
}
195-
}
196-
});
130+
progress.upload(req, emitter, uploadBodySize);
197131

198132
if (options.gotTimeout) {
199-
clearInterval(progressInterval);
200133
timedOut(req, options.gotTimeout);
201134
}
202135

0 commit comments

Comments
 (0)
Please sign in to comment.