1
+ from eth_typing import (
2
+ URI ,
3
+ )
4
+ from eth_utils import (
5
+ to_dict ,
6
+ )
1
7
import logging
8
+ import random
9
+ from requests import (
10
+ RequestException ,
11
+ )
2
12
from typing import (
3
13
Any ,
4
14
Dict ,
8
18
Union ,
9
19
)
10
20
11
- from eth_typing import (
12
- URI ,
13
- )
14
- from eth_utils import (
15
- to_dict ,
16
- )
17
-
18
21
from web3 ._utils .http import (
19
22
construct_user_agent ,
20
23
)
26
29
from web3 .datastructures import (
27
30
NamedElementOnion ,
28
31
)
32
+ from web3 .exceptions import (
33
+ CannotHandleRequest ,
34
+ )
29
35
from web3 .middleware import (
30
36
http_retry_request_middleware ,
31
37
)
38
+ from web3 .providers import (
39
+ BaseProvider ,
40
+ )
32
41
from web3 .types import (
33
42
Middleware ,
34
43
RPCEndpoint ,
42
51
43
52
class HTTPProvider (JSONBaseProvider ):
44
53
logger = logging .getLogger ("web3.providers.HTTPProvider" )
45
- endpoint_uri = None
54
+ providers = None
46
55
_request_args = None
47
56
_request_kwargs = None
48
57
# type ignored b/c conflict with _middlewares attr on BaseProvider
49
58
_middlewares : Tuple [Middleware , ...] = NamedElementOnion ([(http_retry_request_middleware , "http_retry_request" )]) # type: ignore # noqa: E501
50
59
51
60
def __init__ (
52
61
self ,
53
- endpoint_uri : Optional [Union [URI , str ]] = None ,
62
+ providers : Union [list , str ],
63
+ randomize : Optional [bool ] = False ,
54
64
request_kwargs : Optional [Any ] = None ,
55
65
session : Optional [Any ] = None ,
56
66
) -> None :
57
- if endpoint_uri is None :
58
- self .endpoint_uri = get_default_http_endpoint ()
59
- else :
60
- self .endpoint_uri = URI (endpoint_uri )
61
-
67
+ if isinstance (providers , str ):
68
+ providers = [
69
+ providers ,
70
+ ]
71
+ self .randomize = randomize
72
+ self .providers = providers
62
73
self ._request_kwargs = request_kwargs or {}
63
74
64
75
if session :
65
- cache_and_return_session (self .endpoint_uri , session )
76
+ cache_and_return_session (self .providers [ 0 ] , session )
66
77
67
78
super ().__init__ ()
68
79
69
80
def __str__ (self ) -> str :
70
- return f "RPC connection { self . endpoint_uri } "
81
+ return "RPC connection {0}" . format ( self . providers )
71
82
72
83
@to_dict
73
84
def get_request_kwargs (self ) -> Iterable [Tuple [str , Any ]]:
@@ -83,16 +94,27 @@ def get_request_headers(self) -> Dict[str, str]:
83
94
}
84
95
85
96
def make_request (self , method : RPCEndpoint , params : Any ) -> RPCResponse :
86
- self .logger .debug (
87
- f"Making request HTTP. URI: { self .endpoint_uri } , Method: { method } "
88
- )
89
97
request_data = self .encode_rpc_request (method , params )
90
- raw_response = make_post_request (
91
- self .endpoint_uri , request_data , ** self .get_request_kwargs ()
92
- )
93
- response = self .decode_rpc_response (raw_response )
94
- self .logger .debug (
95
- f"Getting response HTTP. URI: { self .endpoint_uri } , "
96
- f"Method: { method } , Response: { response } "
97
- )
98
- return response
98
+ if self .randomize :
99
+ random .shuffle (self .providers )
100
+ for provider in self .providers :
101
+ provider_uri = URI (provider )
102
+ self .logger .debug (
103
+ "Making request HTTP. URI: %s, Method: %s" , provider_uri , method
104
+ )
105
+ try :
106
+ raw_response = make_post_request (
107
+ provider_uri , request_data , ** self .get_request_kwargs ()
108
+ )
109
+ response = self .decode_rpc_response (raw_response )
110
+ self .logger .debug (
111
+ "Getting response HTTP. URI: %s, " "Method: %s, Response: %s" ,
112
+ provider_uri ,
113
+ method ,
114
+ response ,
115
+ )
116
+ return response
117
+ except RequestException :
118
+ pass
119
+ else :
120
+ raise CannotHandleRequest
0 commit comments