@@ -29,7 +29,28 @@ const DOH_ENDPOINT: &'static str = "https://dns.google/dns-query?dns=";
2929/// 
3030/// Note that using this may reveal our IP address to the recipient and information about who we're 
3131/// paying to Google (via `dns.google`). 
32- pub  struct  HTTPHrnResolver ; 
32+ #[ derive( Debug ,  Clone ) ]  
33+ pub  struct  HTTPHrnResolver  { 
34+ 	client :  reqwest:: Client , 
35+ } 
36+ 
37+ impl  HTTPHrnResolver  { 
38+ 	/// Create a new `HTTPHrnResolver` with a default `reqwest::Client`. 
39+ pub  fn  new ( )  -> Self  { 
40+ 		HTTPHrnResolver :: default ( ) 
41+ 	} 
42+ 
43+ 	/// Create a new `HTTPHrnResolver` with a custom `reqwest::Client`. 
44+ pub  fn  with_client ( client :  reqwest:: Client )  -> Self  { 
45+ 		HTTPHrnResolver  {  client } 
46+ 	} 
47+ } 
48+ 
49+ impl  Default  for  HTTPHrnResolver  { 
50+ 	fn  default ( )  -> Self  { 
51+ 		HTTPHrnResolver  {  client :  reqwest:: Client :: new ( )  } 
52+ 	} 
53+ } 
3354
3455const  B64_CHAR :  [ u8 ;  64 ]  = [ 
3556	b'A' ,  b'B' ,  b'C' ,  b'D' ,  b'E' ,  b'F' ,  b'G' ,  b'H' ,  b'I' ,  b'J' ,  b'K' ,  b'L' ,  b'M' ,  b'N' ,  b'O' ,  b'P' , 
@@ -107,11 +128,10 @@ impl HTTPHrnResolver {
107128		let  mut  pending_queries = vec ! [ initial_query] ; 
108129
109130		while  let  Some ( query)  = pending_queries. pop ( )  { 
110- 			let  client = reqwest:: Client :: new ( ) ; 
111- 
112131			let  request_url = query_to_url ( query) ; 
113- 			let  req = client. get ( request_url) . header ( "accept" ,  "application/dns-message" ) . build ( ) ; 
114- 			let  resp = client. execute ( req. map_err ( |_| DNS_ERR ) ?) . await . map_err ( |_| DNS_ERR ) ?; 
132+ 			let  req =
133+ 				self . client . get ( request_url) . header ( "accept" ,  "application/dns-message" ) . build ( ) ; 
134+ 			let  resp = self . client . execute ( req. map_err ( |_| DNS_ERR ) ?) . await . map_err ( |_| DNS_ERR ) ?; 
115135			let  body = resp. bytes ( ) . await . map_err ( |_| DNS_ERR ) ?; 
116136
117137			let  mut  answer = QueryBuf :: new_zeroed ( 0 ) ; 
@@ -136,8 +156,15 @@ impl HTTPHrnResolver {
136156
137157	async  fn  resolve_lnurl_impl ( & self ,  lnurl_url :  & str )  -> Result < HrnResolution ,  & ' static  str >  { 
138158		let  err = "Failed to fetch LN-Address initial well-known endpoint" ; 
139- 		let  init:  LNURLInitResponse  =
140- 			reqwest:: get ( lnurl_url) . await . map_err ( |_| err) ?. json ( ) . await . map_err ( |_| err) ?; 
159+ 		let  init:  LNURLInitResponse  = self 
160+ 			. client 
161+ 			. get ( lnurl_url) 
162+ 			. send ( ) 
163+ 			. await 
164+ 			. map_err ( |_| err) ?
165+ 			. json ( ) 
166+ 			. await 
167+ 			. map_err ( |_| err) ?; 
141168
142169		if  init. tag  != "payRequest"  { 
143170			return  Err ( "LNURL initial init_response had an incorrect tag value" ) ; 
@@ -198,8 +225,15 @@ impl HrnResolver for HTTPHrnResolver {
198225			}  else  { 
199226				write ! ( & mut  callback,  "?amount={}" ,  amt. milli_sats( ) ) . expect ( "Write to String" ) ; 
200227			} 
201- 			let  callback_response:  LNURLCallbackResponse  =
202- 				reqwest:: get ( callback) . await . map_err ( |_| err) ?. json ( ) . await . map_err ( |_| err) ?; 
228+ 			let  callback_response:  LNURLCallbackResponse  = self 
229+ 				. client 
230+ 				. get ( callback) 
231+ 				. send ( ) 
232+ 				. await 
233+ 				. map_err ( |_| err) ?
234+ 				. json ( ) 
235+ 				. await 
236+ 				. map_err ( |_| err) ?; 
203237
204238			if  !callback_response. routes . is_empty ( )  { 
205239				return  Err ( "LNURL callback response contained a non-empty routes array" ) ; 
@@ -257,7 +291,7 @@ mod tests {
257291
258292	#[ tokio:: test]  
259293	async  fn  test_dns_via_http_hrn_resolver ( )  { 
260- 		let  resolver = HTTPHrnResolver ; 
294+ 		let  resolver = HTTPHrnResolver :: default ( ) ; 
261295		let  instructions = PaymentInstructions :: parse ( 
262296263297			bitcoin:: Network :: Bitcoin , 
@@ -303,10 +337,11 @@ mod tests {
303337
304338	#[ tokio:: test]  
305339	async  fn  test_http_hrn_resolver ( )  { 
340+ 		let  resolver = HTTPHrnResolver :: default ( ) ; 
306341		let  instructions = PaymentInstructions :: parse ( 
307342308343			bitcoin:: Network :: Bitcoin , 
309- 			& HTTPHrnResolver , 
344+ 			& resolver , 
310345			true , 
311346		) 
312347		. await 
@@ -323,7 +358,7 @@ mod tests {
323358			assert_eq ! ( hrn. user( ) ,  "lnurltest" ) ; 
324359			assert_eq ! ( hrn. domain( ) ,  "bitcoin.ninja" ) ; 
325360
326- 			instr. set_amount ( Amount :: from_sats ( 100_000 ) . unwrap ( ) ,  & HTTPHrnResolver ) . await . unwrap ( ) 
361+ 			instr. set_amount ( Amount :: from_sats ( 100_000 ) . unwrap ( ) ,  & resolver ) . await . unwrap ( ) 
327362		}  else  { 
328363			panic ! ( ) ; 
329364		} ; 
@@ -348,11 +383,12 @@ mod tests {
348383
349384	#[ tokio:: test]  
350385	async  fn  test_http_lnurl_resolver ( )  { 
386+ 		let  resolver = HTTPHrnResolver :: default ( ) ; 
351387		let  instructions = PaymentInstructions :: parse ( 
352388			// lnurl encoding for [email protected]   353389			"lnurl1dp68gurn8ghj7cnfw33k76tw9ehxjmn2vyhjuam9d3kz66mwdamkutmvde6hymrs9akxuatjd36x2um5ahcq39" , 
354390			Network :: Bitcoin , 
355- 			& HTTPHrnResolver , 
391+ 			& resolver , 
356392			true , 
357393		) 
358394		. await 
@@ -365,7 +401,7 @@ mod tests {
365401			assert_eq ! ( instr. pop_callback( ) ,  None ) ; 
366402			assert ! ( instr. bip_353_dnssec_proof( ) . is_none( ) ) ; 
367403
368- 			instr. set_amount ( Amount :: from_sats ( 100_000 ) . unwrap ( ) ,  & HTTPHrnResolver ) . await . unwrap ( ) 
404+ 			instr. set_amount ( Amount :: from_sats ( 100_000 ) . unwrap ( ) ,  & resolver ) . await . unwrap ( ) 
369405		}  else  { 
370406			panic ! ( ) ; 
371407		} ; 
0 commit comments