File Coverage

blib/lib/OpenSearch/Base.pm
Criterion Covered Total %
statement 30 135 22.2
branch 0 10 0.0
condition 0 11 0.0
subroutine 10 26 38.4
pod 0 5 0.0
total 40 187 21.3


line stmt bran cond sub pod time code
1             package OpenSearch::Base;
2 4     4   38 use strict;
  4         13  
  4         183  
3 4     4   24 use warnings;
  4         9  
  4         271  
4 4     4   28 use Moo;
  4         7  
  4         55  
5 4     4   2140 use Types::Standard qw(Str Bool Int ArrayRef InstanceOf);
  4         10  
  4         36  
6 4     4   14508 use Mojo::UserAgent;
  4         2795979  
  4         45  
7 4     4   222 use Mojo::URL;
  4         11  
  4         23  
8 4     4   121 use Data::Dumper;
  4         9  
  4         324  
9 4     4   2129 use OpenSearch::Response;
  4         18  
  4         1543  
10 4     4   43 use feature qw(signatures say);
  4         8  
  4         552  
11 4     4   22 no warnings qw(experimental::signatures);
  4         7  
  4         6021  
12              
13             with 'OpenSearch::Helper';
14              
15             has 'user' => ( is => 'rw', isa => Str, required => 0 ); # Not really required since we can use Cert-Auth
16             has 'pass' => ( is => 'rw', isa => Str, required => 0 ); # Not really required since we can use Cert-Auth
17             has 'ca_cert' => ( is => 'rw', isa => Str, required => 0 ); # Dunno if that will work right now...
18             has 'client_cert' => ( is => 'rw', isa => Str, required => 0 ); # Dunno if that will work right now...
19             has 'client_key' => ( is => 'rw', isa => Str, required => 0 ); # Dunno if that will work right now...
20             has 'hosts' => ( is => 'rw', isa => ArrayRef [Str], required => 1 );
21             has 'secure' => ( is => 'rw', isa => Str, required => 1 );
22             has 'allow_insecure' => ( is => 'rw', isa => Str, required => 0, default => sub { 0; } );
23             has 'async' => ( is => 'rw', isa => Bool, required => 0, default => sub { 0; } );
24             has 'max_connections' => ( is => 'rw', isa => Int, required => 0, default => sub { 5; } );
25              
26             # Clean attributes after each request. This is a bit of a hack. We should probably use a
27             # new instance of the class for each request.
28             has 'clear_attrs' => ( is => 'rw', isa => Bool, required => 0, default => sub { 0; } );
29              
30             # If one host is down, we put it here. Dont know yet how to test if a host is back up again
31             has 'disabled_hosts' => ( is => 'rw', isa => ArrayRef [Str], default => sub { []; } );
32              
33             # We pre-create a number of Mojo::UserAgent Objects (dont know if that works)
34             has 'pool_count' => ( is => 'rw', isa => Int, default => sub { 1; } );
35              
36             # Without this the ua will get out of scope to early and result in a Premature connection close...
37             has 'ua_pool' => ( is => 'rw', isa => ArrayRef [ InstanceOf ['Mojo::UserAgent'] ], lazy => 1, default => sub { []; } );
38              
39 0     0 0   sub BUILD( $self, @rest ) {
  0            
  0            
  0            
40              
41 0           while ( scalar( @{ $self->ua_pool } ) <= $self->pool_count ) {
  0            
42 0           my $ua = Mojo::UserAgent->new->insecure( $self->allow_insecure )->max_connections( $self->max_connections );
43              
44 0 0 0       if ( $self->client_cert && $self->client_key ) {
45 0           $ua->cert( $self->client_cert )->key( $self->client_key )->ca_cert( $self->ca_cert );
46             }
47              
48 0           push( @{ $self->ua_pool }, $ua );
  0            
49             }
50              
51             }
52              
53 0     0 0   sub ua($self) {
  0            
  0            
54 0           my $pool = int( rand( $self->pool_count ) );
55 0           return ( $self->ua_pool->[$pool] );
56             }
57              
58 0     0 0   sub url( $self, $suffixes = [], $params = {} ) {
  0            
  0            
  0            
  0            
59 0           my $random_host = $self->hosts->[ int( rand( scalar( @{ $self->hosts } ) ) ) ];
  0            
60 0           my ( $host, $port ) = split( ':', $random_host );
61 0   0       $port = $port // 9200;
62              
63             my $url = Mojo::URL->new->scheme( $self->secure ? 'https' : 'http' )->host($host)->port($port)
64 0 0         ->path( join( '/', @{$suffixes} ) )->query($params);
  0            
65              
66             # Just quick n dirty. There probably is a better way.
67             # Maybe we requires AWS auth in the future?
68 0 0 0       if ( !$self->client_cert && !$self->client_key ) {
69 0           $url->userinfo( join( ':', $self->user, $self->pass ) );
70             }
71              
72 0           return ($url);
73             }
74              
75 0     0     sub _http_method( $self, $method, $instance, $path = [] ) {
  0            
  0            
  0            
  0            
  0            
76 0           my $parsed = $self->_generate_params($instance);
77 0           return ( $self->do_request( $method, $self->url( $path, $parsed->{url} ), $parsed->{body} ) );
78             }
79              
80 0     0 0   sub do_request( $self, $method, $url, $body ) {
  0            
  0            
  0            
  0            
  0            
81 0           my ( $promise, $res );
82              
83 0           $promise =
84             $self->ua->$method( $url =>
85             ( ( ref($body) eq 'HASH' || ref($body) eq 'ARRAY' ) ? 'json' : ( { 'Content-Type' => 'application/json' } ) ) =>
86 0     0     $body )->then( sub($tx) {
  0            
87 0           return ( $self->response($tx) );
88 0     0     } )->catch( sub($error) {
  0            
  0            
89 0           return ($error);
90 0 0 0       } );
91              
92 0 0         return ($promise) if $self->async;
93              
94 0     0     $promise->then( sub { $res = shift; } )->wait;
  0            
95              
96 0           return ($res);
97             }
98              
99 0     0     sub _delete( $self, $instance, $path = [] ) {
  0            
  0            
  0            
  0            
100 0           return $self->_http_method( 'delete_p', $instance, $path );
101             }
102              
103 0     0     sub _get( $self, $instance, $path = [] ) {
  0            
  0            
  0            
  0            
104 0           return $self->_http_method( 'get_p', $instance, $path );
105             }
106              
107 0     0     sub _head( $self, $instance, $path = [] ) {
  0            
  0            
  0            
  0            
108 0           return $self->_http_method( 'head_p', $instance, $path );
109             }
110              
111 0     0     sub _options( $self, $instance, $path = [] ) {
  0            
  0            
  0            
  0            
112 0           return $self->_http_method( 'options_p', $instance, $path );
113             }
114              
115 0     0     sub _patch( $self, $instance, $path = [] ) {
  0            
  0            
  0            
  0            
116 0           return $self->_http_method( 'patch_p', $instance, $path );
117             }
118              
119 0     0     sub _post( $self, $instance, $path = [] ) {
  0            
  0            
  0            
  0            
120 0           return $self->_http_method( 'post_p', $instance, $path );
121             }
122              
123 0     0     sub _put( $self, $instance, $path = [] ) {
  0            
  0            
  0            
  0            
124 0           return $self->_http_method( 'put_p', $instance, $path );
125             }
126              
127 0     0 0   sub response( $self, $tx ) {
  0            
  0            
  0            
128 0           return ( OpenSearch::Response->new( _response => $tx->result ) );
129             }
130              
131             #
132             1;