@@ -35,6 +35,9 @@ use crate::io::utils::check_namespace_key_validity;
3535// would hit a blocking case
3636const INTERNAL_RUNTIME_WORKERS : usize = 2 ;
3737
38+ const HTTP_TIMEOUT : std:: time:: Duration = std:: time:: Duration :: from_secs ( 30 ) ;
39+ const HTTP_RETRIES : u32 = 10 ;
40+
3841/// A [`KVStoreSync`] implementation that writes to and reads from a [VSS](https://github.com/lightningdevkit/vss-server/blob/main/README.md) backend.
3942pub struct VssStore {
4043 inner : Arc < VssStoreInner > ,
@@ -284,10 +287,11 @@ impl VssStoreInner {
284287 let ( data_encryption_key, obfuscation_master_key) =
285288 derive_data_encryption_and_obfuscation_keys ( & vss_seed) ;
286289 let key_obfuscator = KeyObfuscator :: new ( obfuscation_master_key) ;
287- let client = VssClient :: new_with_headers ( base_url, header_provider ) . map_err ( |e | {
288- let msg = format ! ( "Failed to setup VssClient: {}" , e ) ;
290+ let reqwest_client = build_client ( & base_url) . map_err ( |_ | {
291+ let msg = format ! ( "Failed to setup HTTP client: invalid URL" ) ;
289292 Error :: new ( ErrorKind :: Other , msg)
290293 } ) ?;
294+ let client = VssClient :: from_client_and_headers ( base_url, reqwest_client, header_provider) ;
291295 let locks = Mutex :: new ( HashMap :: new ( ) ) ;
292296 Ok ( Self { client, store_id, data_encryption_key, key_obfuscator, locks } )
293297 }
@@ -524,6 +528,32 @@ impl VssStoreInner {
524528 }
525529}
526530
531+ fn build_client ( base_url : & str ) -> Result < reqwest:: Client , ( ) > {
532+ let url = reqwest:: Url :: parse ( base_url) . map_err ( |_| ( ) ) ?;
533+ let host_str = url. host_str ( ) . ok_or ( ( ) ) ?. to_string ( ) ;
534+ let retry = reqwest:: retry:: for_host ( host_str)
535+ . max_retries_per_request ( HTTP_RETRIES )
536+ . classify_fn ( |req_rep| match req_rep. status ( ) {
537+ // VSS uses INTERNAL_SERVER_ERROR when sending back error repsonses. These are
538+ // currently still covered by our `RetryPolicy`, so we tell `reqwest` not to retry them.
539+ Some ( reqwest:: StatusCode :: INTERNAL_SERVER_ERROR ) => req_rep. success ( ) ,
540+ Some ( reqwest:: StatusCode :: BAD_REQUEST ) => req_rep. success ( ) ,
541+ Some ( reqwest:: StatusCode :: UNAUTHORIZED ) => req_rep. success ( ) ,
542+ Some ( reqwest:: StatusCode :: NOT_FOUND ) => req_rep. success ( ) ,
543+ Some ( reqwest:: StatusCode :: CONFLICT ) => req_rep. success ( ) ,
544+ Some ( reqwest:: StatusCode :: OK ) => req_rep. success ( ) ,
545+ _ => req_rep. retryable ( ) ,
546+ } ) ;
547+ let client = reqwest:: Client :: builder ( )
548+ . timeout ( HTTP_TIMEOUT )
549+ . connect_timeout ( HTTP_TIMEOUT )
550+ . read_timeout ( HTTP_TIMEOUT )
551+ . retry ( retry)
552+ . build ( )
553+ . unwrap ( ) ;
554+ Ok ( client)
555+ }
556+
527557fn derive_data_encryption_and_obfuscation_keys ( vss_seed : & [ u8 ; 32 ] ) -> ( [ u8 ; 32 ] , [ u8 ; 32 ] ) {
528558 let hkdf = |initial_key_material : & [ u8 ] , salt : & [ u8 ] | -> [ u8 ; 32 ] {
529559 let mut engine = HmacEngine :: < sha256:: Hash > :: new ( salt) ;
0 commit comments