Skip to content

Commit ac9f9c9

Browse files
committed
change binary download distribution
1 parent 034d04c commit ac9f9c9

File tree

4 files changed

+126
-19
lines changed

4 files changed

+126
-19
lines changed

lib/Local.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,9 +254,9 @@ function Local(){
254254
conf.useCaCertificate = this.useCaCertificate;
255255
}
256256
if(!callback) {
257-
return this.binary.binaryPath(conf);
257+
return this.binary.binaryPath(conf, this.key);
258258
}
259-
this.binary.binaryPath(conf, callback);
259+
this.binary.binaryPath(conf, this.key, callback);
260260
} else {
261261
console.log('BINARY PATH IS DEFINED');
262262
if(!callback) {

lib/LocalBinary.js

Lines changed: 64 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,44 @@ const packageName = 'browserstack-local-nodejs';
1414
function LocalBinary(){
1515
this.hostOS = process.platform;
1616
this.is64bits = process.arch == 'x64';
17+
this.baseRetries = 10;
18+
this.sourceURL = null;
19+
this.downloadErrorMessage = null;
20+
21+
this.getSourceUrl = function(conf, retries) {
22+
/* Request for an endpoint from Rails no more than twice with 5 retries each */
23+
if (![5, 10].includes(retries) && this.sourceURL) return this.sourceURL;
24+
25+
let cmd, opts;
26+
cmd = 'node';
27+
opts = [path.join(__dirname, 'fetchDownloadSourceUrl.js'), this.key];
28+
if(conf.proxyHost && conf.proxyPort) {
29+
opts.push(conf.proxyHost, conf.proxyPort);
30+
if (conf.useCaCertificate) {
31+
opts.push(conf.useCaCertificate);
32+
}
33+
} else if (conf.useCaCertificate) {
34+
opts.push(undefined, undefined, conf.useCaCertificate);
35+
}
1736

18-
this.getDownloadPath = function () {
19-
let sourceURL = 'https://www.browserstack.com/local-testing/downloads/binaries/';
37+
if (retries == 5) {
38+
opts.push(true, this.binaryDownloadError);
39+
}
40+
41+
const userAgent = [packageName, version].join('/');
42+
const env = Object.assign({ 'USER_AGENT': userAgent }, process.env);
43+
const obj = childProcess.spawnSync(cmd, opts, { env: env });
44+
if(obj.stdout.length > 0) {
45+
this.sourceURL = obj.stdout;
46+
return this.sourceURL;
47+
} else if(obj.stderr.length > 0) {
48+
let output = Buffer.from(JSON.parse(JSON.stringify(obj.stderr)).data).toString();
49+
throw(output);
50+
}
51+
}
52+
53+
this.getDownloadPath = function (conf, retries) {
54+
let sourceURL = this.getSourceUrl(conf, retries) + '/';
2055

2156
if(this.hostOS.match(/darwin|mac os/i)){
2257
return sourceURL + 'BrowserStackLocal-darwin-x64';
@@ -43,9 +78,10 @@ function LocalBinary(){
4378
}
4479
};
4580

46-
this.httpPath = this.getDownloadPath();
47-
48-
81+
this.binaryDownloadError = function(errorMessagePrefix, errorObject) {
82+
console.error(errorMessagePrefix, errorObject);
83+
this.downloadErrorMessage = errorMessagePrefix + " : " + errorObject ? errorObject.getMessage() : "null";
84+
}
4985

5086
this.retryBinaryDownload = function(conf, destParentDir, callback, retries, binaryPath) {
5187
var that = this;
@@ -66,6 +102,12 @@ function LocalBinary(){
66102
};
67103

68104
this.downloadSync = function(conf, destParentDir, retries) {
105+
try {
106+
this.httpPath = this.getDownloadPath(conf, retries);
107+
} catch (e) {
108+
return console.error(`Unable to fetch the source url to download the binary with error: ${e}`);
109+
}
110+
69111
console.log('Downloading in sync');
70112
var that = this;
71113
if(!this.checkPath(destParentDir))
@@ -96,21 +138,27 @@ function LocalBinary(){
96138
fs.chmodSync(binaryPath, '0755');
97139
return binaryPath;
98140
}else{
99-
console.log('failed to download');
141+
that.binaryDownloadError('failed to download');
100142
return that.retryBinaryDownload(conf, destParentDir, null, retries, binaryPath);
101143
}
102144
} else if(obj.stderr.length > 0) {
103145
output = Buffer.from(JSON.parse(JSON.stringify(obj.stderr)).data).toString();
104-
console.error(output);
146+
that.binaryDownloadError(output);
105147
return that.retryBinaryDownload(conf, destParentDir, null, retries, binaryPath);
106148
}
107149
} catch(err) {
108-
console.error('Download failed with error', err);
150+
that.binaryDownloadError('Download failed with error', err);
109151
return that.retryBinaryDownload(conf, destParentDir, null, retries, binaryPath);
110152
}
111153
};
112154

113155
this.download = function(conf, destParentDir, callback, retries){
156+
try {
157+
this.httpPath = this.getDownloadPath(conf, retries);
158+
} catch (e) {
159+
return console.error(`Unable to fetch the source url to download the binary with error: ${e}`);
160+
}
161+
114162
var that = this;
115163
if(!this.checkPath(destParentDir))
116164
fs.mkdirSync(destParentDir);
@@ -152,11 +200,11 @@ function LocalBinary(){
152200
}
153201

154202
response.on('error', function(err) {
155-
console.error('Got Error in binary download response', err);
203+
that.binaryDownloadError('Got Error in binary download response', err);
156204
that.retryBinaryDownload(conf, destParentDir, callback, retries, binaryPath);
157205
});
158206
fileStream.on('error', function (err) {
159-
console.error('Got Error while downloading binary file', err);
207+
that.binaryDownloadError('Got Error while downloading binary file', err);
160208
that.retryBinaryDownload(conf, destParentDir, callback, retries, binaryPath);
161209
});
162210
fileStream.on('close', function () {
@@ -165,12 +213,13 @@ function LocalBinary(){
165213
});
166214
});
167215
}).on('error', function(err) {
168-
console.error('Got Error in binary downloading request', err);
216+
that.binaryDownloadError('Got Error in binary downloading request', err);
169217
that.retryBinaryDownload(conf, destParentDir, callback, retries, binaryPath);
170218
});
171219
};
172220

173-
this.binaryPath = function(conf, callback){
221+
this.binaryPath = function(conf, key, callback){
222+
this.key = key;
174223
var destParentDir = this.getAvailableDirs();
175224
var destBinaryName = (this.windows) ? 'BrowserStackLocal.exe' : 'BrowserStackLocal';
176225
var binaryPath = path.join(destParentDir, destBinaryName);
@@ -180,10 +229,11 @@ function LocalBinary(){
180229
}
181230
callback(binaryPath);
182231
} else {
232+
let retries = this.baseRetries;
183233
if(!callback) {
184-
return this.downloadSync(conf, destParentDir, 5);
234+
return this.downloadSync(conf, destParentDir, retries);
185235
}
186-
this.download(conf, destParentDir, callback, 5);
236+
this.download(conf, destParentDir, callback, retries);
187237
}
188238
};
189239

lib/fetchDownloadSourceUrl.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
const https = require('https'),
2+
fs = require('fs'),
3+
HttpsProxyAgent = require('https-proxy-agent');
4+
5+
const authToken = process.argv[2], proxyHost = process.argv[3], proxyPort = process.argv[4], useCaCertificate = process.argv[5], downloadFallback = process.argv[6], downloadErrorMessage = process.argv[7];
6+
7+
let body = '', data = {"auth_token": authToken};
8+
const options = {
9+
hostname: 'k8s-devlocal.bsstag.com',
10+
port: 443,
11+
path: '/binary/api/v1/endpoint',
12+
method: 'POST',
13+
headers: {
14+
'Content-Type': 'application/json',
15+
'user-agent': process.env.USER_AGENT
16+
}
17+
};
18+
if (downloadFallback) {
19+
options.headers['X-Local-Fallback-Cloudflare'] = true;
20+
data["error_message"] = downloadErrorMessage;
21+
}
22+
23+
if(proxyHost && proxyPort) {
24+
options.agent = new HttpsProxyAgent({
25+
host: proxyHost,
26+
port: proxyPort
27+
});
28+
}
29+
if (useCaCertificate) {
30+
try {
31+
options.ca = fs.readFileSync(useCaCertificate);
32+
} catch(err) {
33+
console.log('failed to read cert file', err);
34+
}
35+
}
36+
37+
const req = https.request(options, res => {
38+
res.on('data', d => {
39+
body += d;
40+
});
41+
res.on('end', () => {
42+
try {
43+
const url = JSON.parse(body).data.endpoint;
44+
console.log(url);
45+
} catch (e) {
46+
console.error(e);
47+
}
48+
});
49+
res.on('error', (err) => {
50+
console.error(err);
51+
})
52+
});
53+
req.on('error', e => {
54+
console.error(e);
55+
});
56+
req.write(JSON.stringify(data));
57+
req.end();

test/local.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ describe('LocalBinary', function () {
280280
// ensure that we have a valid binary downloaded
281281

282282
// removeIfInvalid();
283-
(new LocalBinary()).binaryPath({}, function(binaryPath) {
283+
(new LocalBinary()).binaryPath({}, 'abc', function(binaryPath) {
284284
defaultBinaryPath = binaryPath;
285285
tempfs.mkdir({
286286
recursive: true
@@ -313,7 +313,7 @@ describe('LocalBinary', function () {
313313
fs.writeFile(defaultBinaryPath, 'Random String', function() {
314314
fs.chmod(defaultBinaryPath, '0755', function() {
315315
localBinary.binaryPath({
316-
}, function(binaryPath) {
316+
}, 'abc', function(binaryPath) {
317317
expect(downloadStub.called).to.be.true;
318318
done();
319319
});
@@ -331,7 +331,7 @@ describe('LocalBinary', function () {
331331
});
332332

333333
localBinary.binaryPath({
334-
}, function(binaryPath) {
334+
}, 'abc', function(binaryPath) {
335335
expect(downloadStub.called).to.be.true;
336336
done();
337337
});

0 commit comments

Comments
 (0)