@@ -29,7 +29,13 @@ pub use ic_transport_types::{
29
29
pub use nonce:: { NonceFactory , NonceGenerator } ;
30
30
use rangemap:: { RangeInclusiveMap , RangeInclusiveSet , StepFns } ;
31
31
use reqwest:: { Body , Client , Request , Response } ;
32
- use route_provider:: RouteProvider ;
32
+ use route_provider:: {
33
+ dynamic_routing:: {
34
+ dynamic_route_provider:: DynamicRouteProviderBuilder , node:: Node ,
35
+ snapshot:: latency_based_routing:: LatencyRoutingSnapshot ,
36
+ } ,
37
+ RouteProvider , UrlUntilReady ,
38
+ } ;
33
39
use time:: OffsetDateTime ;
34
40
use tower_service:: Service ;
35
41
@@ -58,7 +64,7 @@ use std::{
58
64
borrow:: Cow ,
59
65
collections:: HashMap ,
60
66
convert:: TryFrom ,
61
- fmt,
67
+ fmt:: { self , Debug } ,
62
68
future:: { Future , IntoFuture } ,
63
69
pin:: Pin ,
64
70
sync:: { Arc , Mutex , RwLock } ,
@@ -177,32 +183,54 @@ impl Agent {
177
183
178
184
/// Create an instance of an [`Agent`].
179
185
pub fn new ( config : agent_config:: AgentConfig ) -> Result < Agent , AgentError > {
186
+ let client = config. http_service . unwrap_or_else ( || {
187
+ Arc :: new ( Retry429Logic {
188
+ client : config. client . unwrap_or_else ( || {
189
+ #[ cfg( not( target_family = "wasm" ) ) ]
190
+ {
191
+ Client :: builder ( )
192
+ . use_rustls_tls ( )
193
+ . timeout ( Duration :: from_secs ( 360 ) )
194
+ . build ( )
195
+ . expect ( "Could not create HTTP client." )
196
+ }
197
+ #[ cfg( all( target_family = "wasm" , feature = "wasm-bindgen" ) ) ]
198
+ {
199
+ Client :: new ( )
200
+ }
201
+ } ) ,
202
+ } )
203
+ } ) ;
180
204
Ok ( Agent {
181
205
nonce_factory : config. nonce_factory ,
182
206
identity : config. identity ,
183
207
ingress_expiry : config. ingress_expiry ,
184
208
root_key : Arc :: new ( RwLock :: new ( IC_ROOT_KEY . to_vec ( ) ) ) ,
185
- client : config. http_service . unwrap_or_else ( || {
186
- Arc :: new ( Retry429Logic {
187
- client : config. client . unwrap_or_else ( || {
188
- #[ cfg( not( target_family = "wasm" ) ) ]
189
- {
190
- Client :: builder ( )
191
- . use_rustls_tls ( )
192
- . timeout ( Duration :: from_secs ( 360 ) )
193
- . build ( )
194
- . expect ( "Could not create HTTP client." )
195
- }
196
- #[ cfg( all( target_family = "wasm" , feature = "wasm-bindgen" ) ) ]
197
- {
198
- Client :: new ( )
199
- }
200
- } ) ,
201
- } )
202
- } ) ,
203
- route_provider : config
204
- . route_provider
205
- . expect ( "missing `url` or `route_provider` in `AgentBuilder`" ) ,
209
+ client : client. clone ( ) ,
210
+ route_provider : if let Some ( route_provider) = config. route_provider {
211
+ route_provider
212
+ } else if let Some ( url) = config. url {
213
+ if config. background_dynamic_routing {
214
+ assert ! (
215
+ url. scheme( ) == "https" && url. path( ) == "/" && url. port( ) . is_none( ) && url. domain( ) . is_some( ) ,
216
+ "in dynamic routing mode, URL must be in the exact form https://domain with no path, port, IP, or non-HTTPS scheme"
217
+ ) ;
218
+ let seeds = vec ! [ Node :: new( url. domain( ) . unwrap( ) ) . unwrap( ) ] ;
219
+ UrlUntilReady :: new ( url, async move {
220
+ DynamicRouteProviderBuilder :: new (
221
+ LatencyRoutingSnapshot :: new ( ) ,
222
+ seeds,
223
+ client,
224
+ )
225
+ . build ( )
226
+ . await
227
+ } ) as Arc < dyn RouteProvider >
228
+ } else {
229
+ Arc :: new ( url)
230
+ }
231
+ } else {
232
+ panic ! ( "either route_provider or url must be specified" ) ;
233
+ } ,
206
234
subnet_key_cache : Arc :: new ( Mutex :: new ( SubnetCache :: new ( ) ) ) ,
207
235
verify_query_signatures : config. verify_query_signatures ,
208
236
concurrent_requests_semaphore : Arc :: new ( Semaphore :: new ( config. max_concurrent_requests ) ) ,
@@ -1862,7 +1890,7 @@ impl<'agent> IntoFuture for UpdateBuilder<'agent> {
1862
1890
/// HTTP client middleware. Implemented automatically for `reqwest`-compatible by-ref `tower::Service`, such as `reqwest_middleware`.
1863
1891
#[ cfg_attr( target_family = "wasm" , async_trait( ?Send ) ) ]
1864
1892
#[ cfg_attr( not( target_family = "wasm" ) , async_trait) ]
1865
- pub trait HttpService : Send + Sync {
1893
+ pub trait HttpService : Send + Sync + Debug {
1866
1894
/// Perform a HTTP request. Any retry logic should call `req` again, instead of `Request::try_clone`.
1867
1895
async fn call < ' a > (
1868
1896
& ' a self ,
@@ -1876,7 +1904,7 @@ impl<T> HttpService for T
1876
1904
where
1877
1905
for < ' a > & ' a T : Service < Request , Response = Response , Error = reqwest:: Error > ,
1878
1906
for < ' a > <& ' a Self as Service < Request > >:: Future : Send ,
1879
- T : Send + Sync + ?Sized ,
1907
+ T : Send + Sync + Debug + ?Sized ,
1880
1908
{
1881
1909
#[ allow( clippy:: needless_arbitrary_self_type) ]
1882
1910
async fn call < ' a > (
@@ -1907,7 +1935,7 @@ where
1907
1935
impl < T > HttpService for T
1908
1936
where
1909
1937
for < ' a > & ' a T : Service < Request , Response = Response , Error = reqwest:: Error > ,
1910
- T : Send + Sync + ?Sized ,
1938
+ T : Send + Sync + Debug + ?Sized ,
1911
1939
{
1912
1940
#[ allow( clippy:: needless_arbitrary_self_type) ]
1913
1941
async fn call < ' a > (
@@ -1919,6 +1947,7 @@ where
1919
1947
}
1920
1948
}
1921
1949
1950
+ #[ derive( Debug ) ]
1922
1951
struct Retry429Logic {
1923
1952
client : Client ,
1924
1953
}
0 commit comments