@@ -37,6 +37,7 @@ use crate::{
37
37
} ;
38
38
use base64:: write:: EncoderWriter as Base64Encoder ;
39
39
use bytes:: BytesMut ;
40
+ use regex:: Regex ;
40
41
use serde:: Serialize ;
41
42
use serde_json:: Value ;
42
43
use std:: {
@@ -101,6 +102,10 @@ impl fmt::Display for BuildError {
101
102
102
103
/// Default address to Elasticsearch running on `http://localhost:9200`
103
104
pub 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
+ }
104
109
105
110
/// Builds a HTTP transport to make API calls to Elasticsearch
106
111
pub struct TransportBuilder {
@@ -389,7 +394,7 @@ impl Transport {
389
394
Ok ( transport)
390
395
}
391
396
392
- pub fn request_builder < B , Q > (
397
+ fn request_builder < B , Q > (
393
398
& self ,
394
399
connection : & Connection ,
395
400
method : Method ,
@@ -464,6 +469,28 @@ impl Transport {
464
469
Ok ( request_builder)
465
470
}
466
471
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
+
467
494
/// Creates an asynchronous request that can be awaited
468
495
pub async fn send < B , Q > (
469
496
& self ,
@@ -486,7 +513,7 @@ impl Transport {
486
513
let node_request = self . request_builder (
487
514
& connection,
488
515
Method :: Get ,
489
- "_nodes/_all/ http" ,
516
+ "_nodes/http?filter_path=nodes.*. http" ,
490
517
headers. clone ( ) ,
491
518
None :: < & Q > ,
492
519
None :: < B > ,
@@ -499,12 +526,17 @@ impl Transport {
499
526
. unwrap ( )
500
527
. iter ( )
501
528
. 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 ( ) ;
508
540
Connection :: new ( url)
509
541
} )
510
542
. collect ( ) ;
@@ -708,10 +740,10 @@ impl ConnectionPool for CloudConnectionPool {
708
740
709
741
/// A Connection Pool that manages a static connection of nodes
710
742
#[ derive( Debug , Clone ) ]
711
- pub struct MultiNodeConnectionPool < LoadBalancing = RoundRobin > {
743
+ pub struct MultiNodeConnectionPool < ConnSelector = RoundRobin > {
712
744
inner : Arc < RwLock < MultiNodeConnectionPoolInner > > ,
713
745
reseed_frequency : Option < Duration > ,
714
- load_balancing_strategy : LoadBalancing ,
746
+ load_balancing_strategy : ConnSelector ,
715
747
reseeding : Arc < AtomicBool > ,
716
748
}
717
749
@@ -721,9 +753,9 @@ pub struct MultiNodeConnectionPoolInner {
721
753
connections : Vec < Connection > ,
722
754
}
723
755
724
- impl < LoadBalancing > ConnectionPool for MultiNodeConnectionPool < LoadBalancing >
756
+ impl < ConnSelector > ConnectionPool for MultiNodeConnectionPool < ConnSelector >
725
757
where
726
- LoadBalancing : LoadBalancingStrategy + Clone ,
758
+ ConnSelector : ConnectionSelector + Clone ,
727
759
{
728
760
fn next ( & self ) -> Connection {
729
761
let inner = self . inner . read ( ) . expect ( "lock poisoned" ) ;
@@ -787,9 +819,9 @@ impl MultiNodeConnectionPool<RoundRobin> {
787
819
}
788
820
789
821
/** The strategy selects an address from a given collection. */
790
- pub trait LoadBalancingStrategy : Send + Sync + Debug {
822
+ pub trait ConnectionSelector : Send + Sync + Debug {
791
823
/** 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 > ;
793
825
}
794
826
795
827
/** A round-robin strategy cycles through nodes sequentially. */
@@ -806,8 +838,8 @@ impl Default for RoundRobin {
806
838
}
807
839
}
808
840
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 > {
811
843
if connections. is_empty ( ) {
812
844
Err ( crate :: error:: lib ( "Connection list empty" ) )
813
845
} else {
@@ -823,7 +855,7 @@ pub mod tests {
823
855
use crate :: auth:: ClientCertificate ;
824
856
use crate :: http:: transport:: {
825
857
CloudId , Connection , ConnectionPool , MultiNodeConnectionPool , SingleNodeConnectionPool ,
826
- TransportBuilder ,
858
+ Transport , TransportBuilder ,
827
859
} ;
828
860
use std:: {
829
861
sync:: atomic:: Ordering ,
@@ -853,6 +885,24 @@ pub mod tests {
853
885
assert ! ( res. is_err( ) ) ;
854
886
}
855
887
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
+
856
906
#[ test]
857
907
fn can_parse_cloud_id ( ) {
858
908
let base64 = base64:: encode ( "cloud-endpoint.example$3dadf823f05388497ea684236d918a1a$3f26e1609cf54a0f80137a80de560da4" ) ;
0 commit comments