@@ -3,6 +3,7 @@ var https = require('https'),
3
3
fs = require ( 'fs' ) ,
4
4
path = require ( 'path' ) ,
5
5
os = require ( 'os' ) ,
6
+ util = require ( 'util' ) ,
6
7
childProcess = require ( 'child_process' ) ,
7
8
zlib = require ( 'zlib' ) ,
8
9
HttpsProxyAgent = require ( 'https-proxy-agent' ) ,
@@ -14,9 +15,55 @@ const packageName = 'browserstack-local-nodejs';
14
15
function LocalBinary ( ) {
15
16
this . hostOS = process . platform ;
16
17
this . is64bits = process . arch == 'x64' ;
18
+ this . baseRetries = 9 ;
19
+ this . sourceURL = null ;
20
+ this . downloadErrorMessage = null ;
21
+
22
+ this . getSourceUrl = function ( conf , retries ) {
23
+ /* Request for an endpoint to download the local binary from Rails no more than twice with 5 retries each */
24
+ if ( ! [ 4 , 9 ] . includes ( retries ) && this . sourceURL != null ) {
25
+ return this . sourceURL ;
26
+ }
27
+
28
+ if ( process . env . BINARY_DOWNLOAD_SOURCE_URL !== undefined && process . env . BINARY_DOWNLOAD_FALLBACK_ENABLED == 'true' && this . parentRetries != 4 ) {
29
+ /* This is triggered from Local.js if there's an error executing the downloaded binary */
30
+ return process . env . BINARY_DOWNLOAD_SOURCE_URL ;
31
+ }
32
+
33
+ let cmd , opts ;
34
+ cmd = 'node' ;
35
+ opts = [ path . join ( __dirname , 'fetchDownloadSourceUrl.js' ) , this . key ] ;
36
+
37
+ if ( retries == 4 || ( process . env . BINARY_DOWNLOAD_FALLBACK_ENABLED == 'true' && this . parentRetries == 4 ) ) {
38
+ opts . push ( true , this . downloadErrorMessage || process . env . BINARY_DOWNLOAD_ERROR_MESSAGE ) ;
39
+ } else {
40
+ opts . push ( false , null ) ;
41
+ }
42
+
43
+ if ( conf . proxyHost && conf . proxyPort ) {
44
+ opts . push ( conf . proxyHost , conf . proxyPort ) ;
45
+ if ( conf . useCaCertificate ) {
46
+ opts . push ( conf . useCaCertificate ) ;
47
+ }
48
+ } else if ( conf . useCaCertificate ) {
49
+ opts . push ( undefined , undefined , conf . useCaCertificate ) ;
50
+ }
51
+
52
+ const userAgent = [ packageName , version ] . join ( '/' ) ;
53
+ const env = Object . assign ( { 'USER_AGENT' : userAgent } , process . env ) ;
54
+ const obj = childProcess . spawnSync ( cmd , opts , { env : env } ) ;
55
+ if ( obj . stdout . length > 0 ) {
56
+ this . sourceURL = obj . stdout . toString ( ) . replace ( / \n + $ / , '' ) ;
57
+ process . env . BINARY_DOWNLOAD_SOURCE_URL = this . sourceURL ;
58
+ return this . sourceURL ;
59
+ } else if ( obj . stderr . length > 0 ) {
60
+ let output = Buffer . from ( JSON . parse ( JSON . stringify ( obj . stderr ) ) . data ) . toString ( ) ;
61
+ throw ( output ) ;
62
+ }
63
+ } ;
17
64
18
- this . getDownloadPath = function ( ) {
19
- let sourceURL = 'https://www.browserstack.com/local-testing/downloads/binaries /';
65
+ this . getDownloadPath = function ( conf , retries ) {
66
+ let sourceURL = this . getSourceUrl ( conf , retries ) + ' /';
20
67
21
68
if ( this . hostOS . match ( / d a r w i n | m a c o s / i) ) {
22
69
return sourceURL + 'BrowserStackLocal-darwin-x64' ;
@@ -43,9 +90,10 @@ function LocalBinary(){
43
90
}
44
91
} ;
45
92
46
- this . httpPath = this . getDownloadPath ( ) ;
47
-
48
-
93
+ this . binaryDownloadError = function ( errorMessagePrefix , errorMessage ) {
94
+ console . error ( errorMessagePrefix , errorMessage ) ;
95
+ this . downloadErrorMessage = errorMessagePrefix + ' : ' + errorMessage ;
96
+ } ;
49
97
50
98
this . retryBinaryDownload = function ( conf , destParentDir , callback , retries , binaryPath ) {
51
99
var that = this ;
@@ -66,6 +114,12 @@ function LocalBinary(){
66
114
} ;
67
115
68
116
this . downloadSync = function ( conf , destParentDir , retries ) {
117
+ try {
118
+ this . httpPath = this . getDownloadPath ( conf , retries ) ;
119
+ } catch ( e ) {
120
+ return console . error ( `Unable to fetch the source url to download the binary with error: ${ e } ` ) ;
121
+ }
122
+
69
123
console . log ( 'Downloading in sync' ) ;
70
124
var that = this ;
71
125
if ( ! this . checkPath ( destParentDir ) )
@@ -96,21 +150,27 @@ function LocalBinary(){
96
150
fs . chmodSync ( binaryPath , '0755' ) ;
97
151
return binaryPath ;
98
152
} else {
99
- console . log ( 'failed to download' ) ;
153
+ that . binaryDownloadError ( 'failed to download' ) ;
100
154
return that . retryBinaryDownload ( conf , destParentDir , null , retries , binaryPath ) ;
101
155
}
102
156
} else if ( obj . stderr . length > 0 ) {
103
157
output = Buffer . from ( JSON . parse ( JSON . stringify ( obj . stderr ) ) . data ) . toString ( ) ;
104
- console . error ( output ) ;
158
+ that . binaryDownloadError ( output ) ;
105
159
return that . retryBinaryDownload ( conf , destParentDir , null , retries , binaryPath ) ;
106
160
}
107
161
} catch ( err ) {
108
- console . error ( 'Download failed with error' , err ) ;
162
+ that . binaryDownloadError ( 'Download failed with error' , util . format ( err ) ) ;
109
163
return that . retryBinaryDownload ( conf , destParentDir , null , retries , binaryPath ) ;
110
164
}
111
165
} ;
112
166
113
167
this . download = function ( conf , destParentDir , callback , retries ) {
168
+ try {
169
+ this . httpPath = this . getDownloadPath ( conf , retries ) ;
170
+ } catch ( e ) {
171
+ return console . error ( `Unable to fetch the source url to download the binary with error: ${ e } ` ) ;
172
+ }
173
+
114
174
var that = this ;
115
175
if ( ! this . checkPath ( destParentDir ) )
116
176
fs . mkdirSync ( destParentDir ) ;
@@ -152,11 +212,11 @@ function LocalBinary(){
152
212
}
153
213
154
214
response . on ( 'error' , function ( err ) {
155
- console . error ( 'Got Error in binary download response' , err ) ;
215
+ that . binaryDownloadError ( 'Got Error in binary download response' , util . format ( err ) ) ;
156
216
that . retryBinaryDownload ( conf , destParentDir , callback , retries , binaryPath ) ;
157
217
} ) ;
158
218
fileStream . on ( 'error' , function ( err ) {
159
- console . error ( 'Got Error while downloading binary file' , err ) ;
219
+ that . binaryDownloadError ( 'Got Error while downloading binary file' , util . format ( err ) ) ;
160
220
that . retryBinaryDownload ( conf , destParentDir , callback , retries , binaryPath ) ;
161
221
} ) ;
162
222
fileStream . on ( 'close' , function ( ) {
@@ -165,12 +225,14 @@ function LocalBinary(){
165
225
} ) ;
166
226
} ) ;
167
227
} ) . on ( 'error' , function ( err ) {
168
- console . error ( 'Got Error in binary downloading request' , err ) ;
228
+ that . binaryDownloadError ( 'Got Error in binary downloading request' , util . format ( err ) ) ;
169
229
that . retryBinaryDownload ( conf , destParentDir , callback , retries , binaryPath ) ;
170
230
} ) ;
171
231
} ;
172
232
173
- this . binaryPath = function ( conf , callback ) {
233
+ this . binaryPath = function ( conf , key , parentRetries , callback ) {
234
+ this . key = key ;
235
+ this . parentRetries = parentRetries ;
174
236
var destParentDir = this . getAvailableDirs ( ) ;
175
237
var destBinaryName = ( this . windows ) ? 'BrowserStackLocal.exe' : 'BrowserStackLocal' ;
176
238
var binaryPath = path . join ( destParentDir , destBinaryName ) ;
@@ -180,10 +242,11 @@ function LocalBinary(){
180
242
}
181
243
callback ( binaryPath ) ;
182
244
} else {
245
+ let retries = this . baseRetries ;
183
246
if ( ! callback ) {
184
- return this . downloadSync ( conf , destParentDir , 5 ) ;
247
+ return this . downloadSync ( conf , destParentDir , retries ) ;
185
248
}
186
- this . download ( conf , destParentDir , callback , 5 ) ;
249
+ this . download ( conf , destParentDir , callback , retries ) ;
187
250
}
188
251
} ;
189
252
0 commit comments