@@ -37,6 +37,7 @@ use crate::{
3737} ;
3838use base64:: write:: EncoderWriter as Base64Encoder ;
3939use bytes:: BytesMut ;
40+ use regex:: Regex ;
4041use serde:: Serialize ;
4142use serde_json:: Value ;
4243use std:: {
@@ -101,6 +102,10 @@ impl fmt::Display for BuildError {
101102
102103/// Default address to Elasticsearch running on `http://localhost:9200`
103104pub static DEFAULT_ADDRESS : & str = "http://localhost:9200" ;
105+ lazy_static ! {
106+ static ref ADDRESS_REGEX : Regex =
107+ Regex :: new( r"((?P<fqdn>[^/]+)/)?(?P<ip>[^:]+|\[[\da-fA-F:\.]+\]):(?P<port>\d+)$" ) . unwrap( ) ;
108+ }
104109
105110/// Builds a HTTP transport to make API calls to Elasticsearch
106111pub struct TransportBuilder {
@@ -389,7 +394,7 @@ impl Transport {
389394 Ok ( transport)
390395 }
391396
392- pub fn request_builder < B , Q > (
397+ fn request_builder < B , Q > (
393398 & self ,
394399 connection : & Connection ,
395400 method : Method ,
@@ -464,6 +469,28 @@ impl Transport {
464469 Ok ( request_builder)
465470 }
466471
472+ fn parse_to_url ( address : & str , scheme : & str ) -> Result < Url , Error > {
473+ if address. is_empty ( ) {
474+ return Err ( crate :: error:: lib ( "Bound Address is empty" ) ) ;
475+ }
476+
477+ let matches = ADDRESS_REGEX
478+ . captures ( address)
479+ . ok_or_else ( || crate :: lib ( format ! ( "error parsing address into url: {}" , address) ) ) ?;
480+
481+ let host = matches
482+ . name ( "fqdn" )
483+ . or_else ( || Some ( matches. name ( "ip" ) . unwrap ( ) ) )
484+ . unwrap ( )
485+ . as_str ( )
486+ . trim ( ) ;
487+ let port = matches. name ( "port" ) . unwrap ( ) . as_str ( ) . trim ( ) ;
488+
489+ Ok ( Url :: parse (
490+ format ! ( "{}://{}:{}" , scheme, host, port) . as_str ( ) ,
491+ ) ?)
492+ }
493+
467494 /// Creates an asynchronous request that can be awaited
468495 pub async fn send < B , Q > (
469496 & self ,
@@ -486,7 +513,7 @@ impl Transport {
486513 let node_request = self . request_builder (
487514 & connection,
488515 Method :: Get ,
489- "_nodes/_all/ http" ,
516+ "_nodes/http?filter_path=nodes.*. http" ,
490517 headers. clone ( ) ,
491518 None :: < & Q > ,
492519 None :: < B > ,
@@ -499,12 +526,17 @@ impl Transport {
499526 . unwrap ( )
500527 . iter ( )
501528 . map ( |h| {
502- let url = format ! (
503- "{}://{}" ,
504- scheme,
505- h. 1 [ "http" ] [ "publish_address" ] . as_str( ) . unwrap( )
506- ) ;
507- let url = Url :: parse ( & url) . unwrap ( ) ;
529+ let address = h. 1 [ "http" ] [ "publish_address" ]
530+ . as_str ( )
531+ . or_else ( || {
532+ Some (
533+ h. 1 [ "http" ] [ "bound_address" ] . as_array ( ) . unwrap ( ) [ 0 ]
534+ . as_str ( )
535+ . unwrap ( ) ,
536+ )
537+ } )
538+ . unwrap ( ) ;
539+ let url = Self :: parse_to_url ( address, scheme) . unwrap ( ) ;
508540 Connection :: new ( url)
509541 } )
510542 . collect ( ) ;
@@ -708,10 +740,10 @@ impl ConnectionPool for CloudConnectionPool {
708740
709741/// A Connection Pool that manages a static connection of nodes
710742#[ derive( Debug , Clone ) ]
711- pub struct MultiNodeConnectionPool < LoadBalancing = RoundRobin > {
743+ pub struct MultiNodeConnectionPool < ConnSelector = RoundRobin > {
712744 inner : Arc < RwLock < MultiNodeConnectionPoolInner > > ,
713745 reseed_frequency : Option < Duration > ,
714- load_balancing_strategy : LoadBalancing ,
746+ load_balancing_strategy : ConnSelector ,
715747 reseeding : Arc < AtomicBool > ,
716748}
717749
@@ -721,9 +753,9 @@ pub struct MultiNodeConnectionPoolInner {
721753 connections : Vec < Connection > ,
722754}
723755
724- impl < LoadBalancing > ConnectionPool for MultiNodeConnectionPool < LoadBalancing >
756+ impl < ConnSelector > ConnectionPool for MultiNodeConnectionPool < ConnSelector >
725757where
726- LoadBalancing : LoadBalancingStrategy + Clone ,
758+ ConnSelector : ConnectionSelector + Clone ,
727759{
728760 fn next ( & self ) -> Connection {
729761 let inner = self . inner . read ( ) . expect ( "lock poisoned" ) ;
@@ -787,9 +819,9 @@ impl MultiNodeConnectionPool<RoundRobin> {
787819}
788820
789821/** The strategy selects an address from a given collection. */
790- pub trait LoadBalancingStrategy : Send + Sync + Debug {
822+ pub trait ConnectionSelector : Send + Sync + Debug {
791823 /** Try get the next connection. */
792- fn try_next < ' a > ( & self , connections : & ' a [ Connection ] ) -> Result < Connection , Error > ;
824+ fn try_next ( & self , connections : & [ Connection ] ) -> Result < Connection , Error > ;
793825}
794826
795827/** A round-robin strategy cycles through nodes sequentially. */
@@ -806,8 +838,8 @@ impl Default for RoundRobin {
806838 }
807839}
808840
809- impl LoadBalancingStrategy for RoundRobin {
810- fn try_next < ' a > ( & self , connections : & ' a [ Connection ] ) -> Result < Connection , Error > {
841+ impl ConnectionSelector for RoundRobin {
842+ fn try_next ( & self , connections : & [ Connection ] ) -> Result < Connection , Error > {
811843 if connections. is_empty ( ) {
812844 Err ( crate :: error:: lib ( "Connection list empty" ) )
813845 } else {
@@ -823,7 +855,7 @@ pub mod tests {
823855 use crate :: auth:: ClientCertificate ;
824856 use crate :: http:: transport:: {
825857 CloudId , Connection , ConnectionPool , MultiNodeConnectionPool , SingleNodeConnectionPool ,
826- TransportBuilder ,
858+ Transport , TransportBuilder ,
827859 } ;
828860 use std:: {
829861 sync:: atomic:: Ordering ,
@@ -853,6 +885,24 @@ pub mod tests {
853885 assert ! ( res. is_err( ) ) ;
854886 }
855887
888+ #[ test]
889+ fn test_url_parsing_where_hostname_and_ip_present ( ) {
890+ let url = Transport :: parse_to_url ( "localhost/127.0.0.1:9200" , "http" ) . unwrap ( ) ;
891+ assert_eq ! ( url. into_string( ) , "http://localhost:9200/" ) ;
892+ }
893+
894+ #[ test]
895+ fn test_url_parsing_where_only_ip_present ( ) {
896+ let url = Transport :: parse_to_url ( "127.0.0.1:9200" , "http" ) . unwrap ( ) ;
897+ assert_eq ! ( url. into_string( ) , "http://127.0.0.1:9200/" ) ;
898+ }
899+
900+ #[ test]
901+ fn test_url_parsing_where_only_hostname_present ( ) {
902+ let url = Transport :: parse_to_url ( "localhost:9200" , "http" ) . unwrap ( ) ;
903+ assert_eq ! ( url. into_string( ) , "http://localhost:9200/" ) ;
904+ }
905+
856906 #[ test]
857907 fn can_parse_cloud_id ( ) {
858908 let base64 = base64:: encode ( "cloud-endpoint.example$3dadf823f05388497ea684236d918a1a$3f26e1609cf54a0f80137a80de560da4" ) ;
0 commit comments