3
3
const fs = require ( 'fs' ) ;
4
4
const { promisify } = require ( 'util' ) ;
5
5
const Joi = require ( '@hapi/joi' ) ;
6
+ const https = require ( 'https' ) ;
6
7
const net = require ( 'net' ) ;
7
- const requestProm = require ( 'request-promise-native' ) ;
8
+ const util = require ( 'util' ) ;
9
+ const axios = require ( 'axios' ) . default ;
8
10
const { isBoolean, isEmpty, negate, noop, once, partial, pick, zip } = require ( 'lodash/fp' ) ;
9
11
const { NEVER , combineLatest, from, merge, throwError, timer } = require ( 'rxjs' ) ;
10
12
const { distinctUntilChanged, map, mergeMap, scan, startWith, take, takeWhile } = require ( 'rxjs/operators' ) ;
@@ -15,62 +17,34 @@ const fstat = promisify(fs.stat);
15
17
const PREFIX_RE = / ^ ( ( h t t p s ? - g e t | h t t p s ? | t c p | s o c k e t | f i l e ) : ) ( .+ ) $ / ;
16
18
const HOST_PORT_RE = / ^ ( ( [ ^ : ] * ) : ) ? ( \d + ) $ / ;
17
19
const HTTP_GET_RE = / ^ h t t p s ? - g e t : / ;
20
+ const HTTP_UNIX_RE = / ^ h t t p : \/ \/ u n i x : ( [ ^ : ] + ) : ( [ ^ : ] + ) $ / ;
18
21
const TIMEOUT_ERR_MSG = 'Timeout' ;
19
22
20
23
const WAIT_ON_SCHEMA = Joi . object ( {
21
- resources : Joi . array ( )
22
- . items ( Joi . string ( ) . required ( ) )
23
- . required ( ) ,
24
- delay : Joi . number ( )
25
- . integer ( )
26
- . min ( 0 )
27
- . default ( 0 ) ,
28
- httpTimeout : Joi . number ( )
29
- . integer ( )
30
- . min ( 0 ) ,
31
- interval : Joi . number ( )
32
- . integer ( )
33
- . min ( 0 )
34
- . default ( 250 ) ,
24
+ resources : Joi . array ( ) . items ( Joi . string ( ) . required ( ) ) . required ( ) ,
25
+ delay : Joi . number ( ) . integer ( ) . min ( 0 ) . default ( 0 ) ,
26
+ httpTimeout : Joi . number ( ) . integer ( ) . min ( 0 ) ,
27
+ interval : Joi . number ( ) . integer ( ) . min ( 0 ) . default ( 250 ) ,
35
28
log : Joi . boolean ( ) . default ( false ) ,
36
29
reverse : Joi . boolean ( ) . default ( false ) ,
37
- simultaneous : Joi . number ( )
38
- . integer ( )
39
- . min ( 1 )
40
- . default ( Infinity ) ,
41
- timeout : Joi . number ( )
42
- . integer ( )
43
- . min ( 0 )
44
- . default ( Infinity ) ,
30
+ simultaneous : Joi . number ( ) . integer ( ) . min ( 1 ) . default ( Infinity ) ,
31
+ timeout : Joi . number ( ) . integer ( ) . min ( 0 ) . default ( Infinity ) ,
45
32
verbose : Joi . boolean ( ) . default ( false ) ,
46
- window : Joi . number ( )
47
- . integer ( )
48
- . min ( 0 )
49
- . default ( 750 ) ,
50
- tcpTimeout : Joi . number ( )
51
- . integer ( )
52
- . min ( 0 )
53
- . default ( 300 ) ,
54
-
55
- // http options3
33
+ window : Joi . number ( ) . integer ( ) . min ( 0 ) . default ( 750 ) ,
34
+ tcpTimeout : Joi . number ( ) . integer ( ) . min ( 0 ) . default ( 300 ) ,
35
+
36
+ // http/https options
56
37
ca : [ Joi . string ( ) , Joi . binary ( ) ] ,
57
38
cert : [ Joi . string ( ) , Joi . binary ( ) ] ,
58
- key : [ Joi . string ( ) , Joi . binary ( ) ] ,
39
+ key : [ Joi . string ( ) , Joi . binary ( ) , Joi . object ( ) ] ,
59
40
passphrase : Joi . string ( ) ,
60
41
auth : Joi . object ( {
61
- user : Joi . string ( ) ,
62
42
username : Joi . string ( ) ,
63
43
password : Joi . string ( ) ,
64
- pass : Joi . string ( )
65
- } ) ,
66
- httpSignature : Joi . object ( {
67
- keyId : Joi . string ( ) . required ( ) ,
68
- key : Joi . string ( ) . required ( )
69
44
} ) ,
70
- strictSSL : Joi . boolean ( ) ,
71
- followAllRedirects : Joi . boolean ( ) ,
72
- followRedirect : Joi . boolean ( ) ,
73
- headers : Joi . object ( )
45
+ strictSSL : Joi . boolean ( ) . default ( false ) ,
46
+ followRedirect : Joi . boolean ( ) . default ( true ) , // HTTP 3XX responses
47
+ headers : Joi . object ( ) ,
74
48
} ) ;
75
49
76
50
/**
@@ -86,6 +60,9 @@ const WAIT_ON_SCHEMA = Joi.object({
86
60
- https-get: - HTTPS GET returns 2XX response. ex: https://my/bar
87
61
- tcp:my.server.com:3000 verifies a service is listening on port
88
62
- socket:/path/sock verifies a service is listening on (UDS) socket
63
+ For http over socket, use http://unix:SOCK_PATH:URL_PATH
64
+ like http://unix:/path/to/sock:/foo/bar or
65
+ http-get://unix:/path/to/sock:/foo/bar
89
66
90
67
@param opts object configuring waitOn
91
68
@param opts.resources array of string resources to wait for. prefix determines the type of resource with the default type of `file:`
@@ -107,8 +84,8 @@ function waitOn(opts, cb) {
107
84
return waitOnImpl ( opts , cb ) ;
108
85
} else {
109
86
// promise API
110
- return new Promise ( function ( resolve , reject ) {
111
- waitOnImpl ( opts , function ( err ) {
87
+ return new Promise ( function ( resolve , reject ) {
88
+ waitOnImpl ( opts , function ( err ) {
112
89
if ( err ) {
113
90
reject ( err ) ;
114
91
} else {
@@ -129,7 +106,7 @@ function waitOnImpl(opts, cbFunc) {
129
106
...validResult . value , // use defaults
130
107
// window needs to be at least interval
131
108
...( validResult . value . window < validResult . value . interval ? { window : validResult . value . interval } : { } ) ,
132
- ...( validResult . value . verbose ? { log : true } : { } ) // if debug logging then normal log is also enabled
109
+ ...( validResult . value . verbose ? { log : true } : { } ) , // if debug logging then normal log is also enabled
133
110
} ;
134
111
135
112
const { resources, log : shouldLog , timeout, verbose, reverse } = validatedOpts ;
@@ -167,14 +144,14 @@ function waitOnImpl(opts, cbFunc) {
167
144
const resourcesCompleted$ = combineLatest ( resources . map ( createResourceWithDeps$ ) ) ;
168
145
169
146
merge ( timeoutError$ , resourcesCompleted$ )
170
- . pipe ( takeWhile ( resourceStates => resourceStates . some ( x => ! x ) ) )
147
+ . pipe ( takeWhile ( ( resourceStates ) => resourceStates . some ( ( x ) => ! x ) ) )
171
148
. subscribe ( {
172
- next : resourceStates => {
149
+ next : ( resourceStates ) => {
173
150
lastResourcesState = resourceStates ;
174
151
logWaitingForWDeps ( resourceStates ) ;
175
152
} ,
176
153
error : cleanup ,
177
- complete : cleanup
154
+ complete : cleanup ,
178
155
} ) ;
179
156
}
180
157
@@ -214,7 +191,7 @@ function createFileResource$(
214
191
) {
215
192
const filePath = extractPath ( resource ) ;
216
193
const checkOperator = reverse
217
- ? map ( size => size === - 1 ) // check that file does not exist
194
+ ? map ( ( size ) => size === - 1 ) // check that file does not exist
218
195
: scan (
219
196
// check that file exists and the size is stable
220
197
( acc , x ) => {
@@ -244,7 +221,7 @@ function createFileResource$(
244
221
return from ( getFileSize ( filePath ) ) ;
245
222
} , simultaneous ) ,
246
223
checkOperator ,
247
- map ( x => ( isNotABoolean ( x ) ? false : x ) ) ,
224
+ map ( ( x ) => ( isNotABoolean ( x ) ? false : x ) ) ,
248
225
startWith ( false ) ,
249
226
distinctUntilChanged ( ) ,
250
227
take ( 2 )
@@ -277,35 +254,39 @@ async function getFileSize(filePath) {
277
254
}
278
255
279
256
function createHTTP$ ( { validatedOpts, output } , resource ) {
280
- const { delay, interval, reverse, simultaneous } = validatedOpts ;
281
- const method = HTTP_GET_RE . test ( resource ) ? 'GET' : 'HEAD' ;
282
- const uri = resource . replace ( '-get:' , ':' ) ;
257
+ const {
258
+ delay,
259
+ followRedirect,
260
+ httpTimeout : timeout ,
261
+ interval,
262
+ reverse,
263
+ simultaneous,
264
+ strictSSL : rejectUnauthorized ,
265
+ } = validatedOpts ;
266
+ const method = HTTP_GET_RE . test ( resource ) ? 'get' : 'head' ;
267
+ const url = resource . replace ( '-get:' , ':' ) ;
268
+ const matchHttpUnixSocket = HTTP_UNIX_RE . exec ( url ) ; // http://unix:/sock:/url
269
+ const urlSocketOptions = matchHttpUnixSocket
270
+ ? { socketPath : matchHttpUnixSocket [ 1 ] , url : matchHttpUnixSocket [ 2 ] }
271
+ : { url } ;
272
+ const socketPathDesc = urlSocketOptions . socketPath ? `socketPath:${ urlSocketOptions . socketPath } ` : '' ;
283
273
const httpOptions = {
284
- ...pick (
285
- [
286
- 'auth' ,
287
- 'httpSignature' ,
288
- 'followRedirect' ,
289
- 'followAllRedirects' ,
290
- 'strictSSL' ,
291
- 'headers' ,
292
- 'cert' ,
293
- 'key' ,
294
- 'passphrase' ,
295
- 'ca'
296
- ] ,
297
- validatedOpts
298
- ) ,
299
- ...( validatedOpts . httpTimeout ? { timeout : validatedOpts . httpTimeout } : { } ) ,
300
- uri,
274
+ ...pick ( [ 'auth' , 'headers' ] , validatedOpts ) ,
275
+ httpsAgent : new https . Agent ( {
276
+ rejectUnauthorized,
277
+ ...pick ( [ 'ca' , 'cert' , 'key' , 'passphrase' ] , validatedOpts ) ,
278
+ } ) ,
279
+ ...( followRedirect ? { } : { maxRedirects : 0 } ) , // defaults to 5 (enabled)
280
+ ...( timeout && { timeout } ) ,
281
+ ...urlSocketOptions ,
301
282
method,
302
- resolveWithFullResponse : true ,
303
- simple : true // statusCodes other than 2xx will reject
283
+ // by default it provides full response object
284
+ // validStatus is 2xx unless followRedirect is true (default)
304
285
} ;
305
286
const checkFn = reverse ? negateAsync ( httpCallSucceeds ) : httpCallSucceeds ;
306
287
return timer ( delay , interval ) . pipe (
307
288
mergeMap ( ( ) => {
308
- output ( `making HTTP ${ method } request to ${ uri } ...` ) ;
289
+ output ( `making HTTP(S) ${ method } request to ${ socketPathDesc } url: ${ urlSocketOptions . url } ...` ) ;
309
290
return from ( checkFn ( output , httpOptions ) ) ;
310
291
} , simultaneous ) ,
311
292
startWith ( false ) ,
@@ -316,11 +297,15 @@ function createHTTP$({ validatedOpts, output }, resource) {
316
297
317
298
async function httpCallSucceeds ( output , httpOptions ) {
318
299
try {
319
- const result = await requestProm ( httpOptions ) ;
320
- output ( ` HTTP result for ${ httpOptions . uri } : ${ JSON . stringify ( result ) } ` ) ;
300
+ const result = await axios ( httpOptions ) ;
301
+ output (
302
+ ` HTTP(S) result for ${ httpOptions . url } : ${ util . inspect (
303
+ pick ( [ 'status' , 'statusText' , 'headers' , 'data' ] , result )
304
+ ) } `
305
+ ) ;
321
306
return true ;
322
307
} catch ( err ) {
323
- output ( ` HTTP error for ${ httpOptions . uri } ${ err . toString ( ) } ` ) ;
308
+ output ( ` HTTP(S) error for ${ httpOptions . url } ${ err . toString ( ) } ` ) ;
324
309
return false ;
325
310
}
326
311
}
@@ -342,10 +327,10 @@ function createTCP$({ validatedOpts: { delay, interval, tcpTimeout, reverse, sim
342
327
async function tcpExists ( output , tcpPath , tcpTimeout ) {
343
328
const [ , , /* full, hostWithColon */ hostMatched , port ] = HOST_PORT_RE . exec ( tcpPath ) ;
344
329
const host = hostMatched || 'localhost' ;
345
- return new Promise ( resolve => {
330
+ return new Promise ( ( resolve ) => {
346
331
const conn = net
347
332
. connect ( port , host )
348
- . on ( 'error' , err => {
333
+ . on ( 'error' , ( err ) => {
349
334
output ( ` error connecting to TCP host:${ host } port:${ port } ${ err . toString ( ) } ` ) ;
350
335
resolve ( false ) ;
351
336
} )
@@ -378,10 +363,10 @@ function createSocket$({ validatedOpts: { delay, interval, reverse, simultaneous
378
363
}
379
364
380
365
async function socketExists ( output , socketPath ) {
381
- return new Promise ( resolve => {
366
+ return new Promise ( ( resolve ) => {
382
367
const conn = net
383
368
. connect ( socketPath )
384
- . on ( 'error' , err => {
369
+ . on ( 'error' , ( err ) => {
385
370
output ( ` error connecting to socket socket:${ socketPath } ${ err . toString ( ) } ` ) ;
386
371
resolve ( false ) ;
387
372
} )
@@ -394,7 +379,7 @@ async function socketExists(output, socketPath) {
394
379
}
395
380
396
381
function negateAsync ( asyncFn ) {
397
- return async function ( ...args ) {
382
+ return async function ( ...args ) {
398
383
return ! ( await asyncFn ( ...args ) ) ;
399
384
} ;
400
385
}
0 commit comments