11use anyhow:: { Context , anyhow} ;
22#[ cfg( feature = "fs" ) ]
33use chrono:: Utc ;
4+ use mithril_aggregator_discovery:: {
5+ AggregatorDiscoverer , HttpConfigAggregatorDiscoverer , MithrilNetwork ,
6+ } ;
47use mithril_common:: messages:: AggregatorCapabilities ;
58use reqwest:: Url ;
69use serde:: { Deserialize , Serialize } ;
@@ -44,7 +47,7 @@ const fn one_week_in_seconds() -> u32 {
4447/// The type of discovery to use to find the aggregator to connect to.
4548pub enum AggregatorDiscoveryType {
4649 /// Automatically discover the aggregator.
47- Automatic ,
50+ Automatic ( MithrilNetwork ) ,
4851 /// Use a specific URL to connect to the aggregator.
4952 Url ( String ) ,
5053}
@@ -175,6 +178,7 @@ impl Client {
175178pub struct ClientBuilder {
176179 aggregator_discovery : AggregatorDiscoveryType ,
177180 aggregator_capabilities : Option < AggregatorCapabilities > ,
181+ aggregator_discoverer : Option < Arc < dyn AggregatorDiscoverer > > ,
178182 genesis_verification_key : Option < GenesisVerificationKey > ,
179183 origin_tag : Option < String > ,
180184 client_type : Option < String > ,
@@ -196,16 +200,19 @@ impl ClientBuilder {
196200 /// Constructs a new `ClientBuilder` that fetches data from the aggregator at the given
197201 /// endpoint and with the given genesis verification key.
198202 pub fn aggregator ( endpoint : & str , genesis_verification_key : & str ) -> ClientBuilder {
199- Self :: new ( AggregatorDiscoveryType :: Url ( endpoint. to_string ( ) ) ) . with_genesis_verification_key (
200- GenesisVerificationKey :: JsonHex ( genesis_verification_key. to_string ( ) ) ,
201- )
203+ Self :: new ( AggregatorDiscoveryType :: Url ( endpoint. to_string ( ) ) )
204+ . with_genesis_verification_key ( GenesisVerificationKey :: JsonHex (
205+ genesis_verification_key. to_string ( ) ,
206+ ) )
207+ . with_aggregator_discoverer ( Arc :: new ( HttpConfigAggregatorDiscoverer :: default ( ) ) )
202208 }
203209
204210 /// Constructs a new `ClientBuilder` without any dependency set.
205211 pub fn new ( aggregator_discovery : AggregatorDiscoveryType ) -> ClientBuilder {
206212 Self {
207213 aggregator_discovery,
208214 aggregator_capabilities : None ,
215+ aggregator_discoverer : None ,
209216 genesis_verification_key : None ,
210217 origin_tag : None ,
211218 client_type : None ,
@@ -241,11 +248,21 @@ impl ClientBuilder {
241248 self
242249 }
243250
251+ /// Sets the aggregator discoverer to use to find the aggregator endpoint when in automatic discovery.
252+ pub fn with_aggregator_discoverer (
253+ mut self ,
254+ discoverer : Arc < dyn AggregatorDiscoverer > ,
255+ ) -> ClientBuilder {
256+ self . aggregator_discoverer = Some ( discoverer) ;
257+
258+ self
259+ }
260+
244261 /// Returns a `Client` that uses the dependencies provided to this `ClientBuilder`.
245262 ///
246263 /// The builder will try to create the missing dependencies using default implementations
247264 /// if possible.
248- pub fn build ( self ) -> MithrilResult < Client > {
265+ pub async fn build ( self ) -> MithrilResult < Client > {
249266 let logger = self
250267 . logger
251268 . clone ( )
@@ -264,7 +281,7 @@ impl ClientBuilder {
264281 let feedback_sender = FeedbackSender :: new ( & self . feedback_receivers ) ;
265282
266283 let aggregator_client = match self . aggregator_client {
267- None => Arc :: new ( self . build_aggregator_client ( logger. clone ( ) ) ?) ,
284+ None => Arc :: new ( self . build_aggregator_client ( logger. clone ( ) ) . await ?) ,
268285 Some ( client) => client,
269286 } ;
270287
@@ -367,15 +384,24 @@ impl ClientBuilder {
367384 } )
368385 }
369386
370- fn build_aggregator_client (
387+ async fn build_aggregator_client (
371388 & self ,
372389 logger : Logger ,
373390 ) -> Result < AggregatorHTTPClient , anyhow:: Error > {
374391 let aggregator_endpoint = match self . aggregator_discovery {
375392 AggregatorDiscoveryType :: Url ( ref url) => url. clone ( ) ,
376- AggregatorDiscoveryType :: Automatic => {
377- todo ! ( "Implement automatic aggregator discovery" )
378- }
393+ AggregatorDiscoveryType :: Automatic ( ref network) => match & self . aggregator_discoverer {
394+ Some ( discoverer) => discoverer
395+ . get_available_aggregators ( network. to_owned ( ) )
396+ . await
397+ . with_context ( || "Discovering aggregator endpoint failed" ) ?
398+ . next ( )
399+ . unwrap ( )
400+ . into ( ) ,
401+ None => {
402+ return Err ( anyhow ! ( "The aggregator discoverer must be provided to build the client with automatic discovery using the 'with_aggregator_discoverer' function" ) . into ( ) ) ;
403+ }
404+ } ,
379405 } ;
380406 let endpoint_url = Url :: parse ( & aggregator_endpoint) . with_context ( || {
381407 format ! ( "Invalid aggregator endpoint, it must be a correctly formed url: '{aggregator_endpoint}'" )
0 commit comments