package Net::Async::Graphite::HTTPClient;

our $VERSION = '0.0_1';

=head1 NAME

Net::Async::Graphite::HTTPClient - Handle HTTP for Net::Async::Graphite

=head1 SYNOPSIS

    with 'Net::Async::Graphite::HTTPClient';

=head1 DESCRIPTION

Don't use this module directly, use L<Net::Async::Graphite> and create
objects using its C<new> method in the normal way. Those objects will
include the functionality documented here.

This role brings the capacity to communicate with an HTTP server.

It's mixed in by L<Net::Async::Graphite::API> and uses a
L<Net::Async::HTTP> object to do its work.

=head1 BUGS

C<_http> is added to L<IO::Async>'s loop but there's no mechanism to
remove it. For now C<_http> exists until the application exits but if
that ever changes this will be the source of memory leaks at best.

=cut

use v5.14;
use strictures 2;
use Moo::Role;
use Carp;

use Net::Async::HTTP;
use namespace::clean;

=head1 ROLE

This role requires the L<IO::Async> functionality defined in
L<Net::Async::Graphite::Async> (essentially just a C<_loop> attribute
to hold the L<IO::Async::Loop> object).

=cut

with 'Net::Async::Graphite::Async';

=head1 ATTRIBUTES

=over

=item max_connections (read-only)

The maximum number of simultaneous HTTP connections to allow. See
C<max_connections_per_host> in L<Net::Async::HTTP>.

Default: 0; no limit.

=cut

has max_connections => is => ro => default => 0;

=item username (read-only, predicable)

=item password (read-only, predicable)

The username and password to authenticate with.

In addition to the predicates C<has_username> and C<has_password>
there is C<has_auth> which returns true if there is a username I<and>
a password.

=cut

has [qw(username password)] => is => ro => predicate => 1;

sub has_auth { $_[0]->has_username and $_[0]->has_password }

=item _http (read-only)

The L<Net::Async::HTTP> object which performs the HTTP queries.

=cut

has _http => is => lazy => init_arg => undef, builder => sub {
  my $self = shift;
  my $http = Net::Async::HTTP->new(
    user_agent               => blessed($self) .'/0.0',
    max_connections_per_host => $self->max_connections,
   );
  $self->_loop->add($http);
  $http;
};

=back

=head1 PRIVATE METHODS

=over

=item _download ($uri)

Return (a L<Future> which completes with) an L<HTTP::Response> object
when the HTTP request has finished.

=cut

sub _download {
  my $self = shift;
  my ($uri) = @_;
  #$self->_debugf("Downloading from uri <%s>.", $uri);
  $self->_http->do_request(
    uri      => "$uri",
    # timeout=> ?,
    on_error => sub {
      #$self->_errorf('Error conducting HTTP transaction to %s?%s: %s',
      #               $self->endpoint, $uri, $_[0]);
      # Future has already been fail()ed elsewhere.
    },
    ($self->has_auth
       ? (user => $self->username, pass => $self->password)
       : ()));
}

1;

=back

=head1 SEE ALSO

L<Net::Async::Graphite>

L<Net::Async::Graphite::Async>

L<Net::Async::HTTP>

L<Future>

L<Moo>

=head1 AUTHOR

Matthew King <matthew.king@cloudbeds.com>

=cut
