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
+
77
+ cache_and_return_session (self .providers [0 ], session )
78
+
66
79
67
80
super ().__init__ ()
68
81
69
82
def __str__ (self ) -> str :
70
- return f "RPC connection { self . endpoint_uri } "
83
+ return "RPC connection {0}" . format ( self . providers )
71
84
72
85
@to_dict
73
86
def get_request_kwargs (self ) -> Iterable [Tuple [str , Any ]]:
@@ -83,16 +96,27 @@ def get_request_headers(self) -> Dict[str, str]:
83
96
}
84
97
85
98
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
99
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
100
+ if self .randomize :
101
+ random .shuffle (self .providers )
102
+ for provider in self .providers :
103
+ provider_uri = URI (provider )
104
+ self .logger .debug (
105
+ "Making request HTTP. URI: %s, Method: %s" , provider_uri , method
106
+ )
107
+ try :
108
+ raw_response = make_post_request (
109
+ provider_uri , request_data , ** self .get_request_kwargs ()
110
+ )
111
+ response = self .decode_rpc_response (raw_response )
112
+ self .logger .debug (
113
+ "Getting response HTTP. URI: %s, " "Method: %s, Response: %s" ,
114
+ provider_uri ,
115
+ method ,
116
+ response ,
117
+ )
118
+ return response
119
+ except RequestException :
120
+ pass
121
+ else :
122
+ raise CannotHandleRequest
0 commit comments