AnyEvent-SparkBot

 view release on metacpan or  search on metacpan

lib/AnyEvent/HTTP/Spark.pm  view on Meta::CPAN

  default=>1,
);

has retryTimeout=>(
  isa=>Int,
	is=>'ro',
	default=>1,
);

has retryAfter=>(
  isa=>Int,
  is=>'ro',
  default=>10,
);

has retries=>(
  isa=>HashRef,
  is=>'ro',
  default=>sub { return {} },
);

=head1 NAME

AnyEvent::HTTP::Spark - Syncrnous/Asyncrnous HTTP Rest Client for Cisco Spark

=head1 SYNOPSIS

  use AnyEvent::HTTP::Spark;
  my $obj=new AnyEvent::HTTP::Spark(token=>$ENV{SPARK_TOKEN});

=head1 DESCRIPTION

Dual Nature Syncrnous/Asyncrnous AnyEvent friendly Spark v1 HTTP Client library.

=head1 Moo Roles Used

This class uses the following Moo Roles

  HTTP::MultiGet::Role
  Log::LogMethods
  Data::Result::Moo
  AnyEvent::SpakBot::SharedRole

=head1 OO Arguments and accessors

Required OO Arguments

  token: required for spark authentication

Optional OO Arguments

  logger: sets the logging object
  agent: AnyEvent::HTTP::MultiGet object

  api_url: https://webexapis.com/v1/
    # sets the web service the requests point to
  retryCount: 1, how many retries to attempt when getting a 429 error

Options set at runtime

  retries: anymous hash, used to trak AnyEvent->timer objects

=cut

# This method runs after the new constructor
sub BUILD {
  my ($self)=@_;
}

# this method runs before the new constructor, and can be used to change the arguments passed to the module
around BUILDARGS => sub {
  my ($org,$class,@args)=@_;
  
  return $class->$org(@args);
};

=head1 OO Web Methods and special Handlers

Each web method has a blocking and a non blocking context.

Any Method with a prefix of que_ can be called in either a blocking or a non blocking context.  Most people will use the blocking interface of the client.

Non Blocking context for use with AnyEvent Loops

  my $cb=sub {
    my ($self,$id,$result,$request,$response)=@_;
    if($result) {
      print Dumper($result->get_data);
    } else {
      ...
    }
  };
  my $id=$self->que_listPeople($cb,$args);
  $self->agent->run_next;

Blocking Context

  my $result=$self->listPeople($args);
  if($result) {
    print Dumper($result->get_data);
  } else {
    die $result;
  }


=head1 People

=head2 Get Me

=over 4

=item * Blocking my $result=$self->getMe() 

Returns a L<Data::Result> Object, when true it contains the data, when false it contains why it failed.

=item * Non-Blocking my $id=$self->que_getMe($cb) 

Example Callback

  $cb=sub {
    my ($self,$id,$result,$request,$response,$hashRef)=@_;

lib/AnyEvent/HTTP/Spark.pm  view on Meta::CPAN

  my $uri=$self->api_url.$url;
  my $json=eval {to_json($data)};
  return $self->new_false("Failed to convert \$data to json, error was $@") if $@;

  my $request=new HTTP::Request(POST=>$uri,$self->default_headers,$json);
  return $self->new_true($request);
}

=item * my $id=$self->queue_builder($cb,$method,$url,$data);

Returns the ID of the object in the request for $method.

=cut

sub queue_builder {
  my ($self,$cb,$method,$url,$data)=@_;

  my $result=$self->$method($url,$data);
  return $self->queue_result($cb,$result) unless $result;
  my $request=$result->get_data;

  my $wrap;
  my $count=$self->retryCount;
  if($self->is_blocking) {
    $wrap=sub {
      my ($self,$id,$result,undef,$response)=@_;

      return $cb->(@_) if $result or !($response->code==429 and $count-- >0);
      my $timeout=looks_like_number($response->header('Retry-After')) ? $response->header('Retry-After') : $self->retryTimeout;
      $self->log_warn("Request: $id recived a 429 response, will retry in $timeout seconds");
      

      if($count>0)  {
        my $next_id=$self->queue_request($request,sub { 
          my ($self,undef,$result,undef,$response)=@_;
	  $wrap->($self,$id,$result,$request,$response);
	});
        $self->add_ids_for_blocking($next_id);
        return $self->agent->run_next;
      }

      sleep $timeout;
      my $code=sub {
        my ($self,undef,$result,undef,$response)=@_;
	$cb->($self,$id,$result,$request,$response);
      };
      
      my $next_id=$self->queue_request($request,$code);
      $self->add_ids_for_blocking($next_id);
      $self->agent->run_next;
    };
  } else {
    $wrap=sub {
      my ($self,$id,$result,undef,$response)=@_;
      return $cb->(@_) if $result || !(($response->code==429 || $response->code==404) &&  $count-- >0);
      my $timeout=looks_like_number($response->header('Retry-After')) ? $response->header('Retry-After') : $self->retryTimeout;
      $self->log_warn("Request: $id recived a 429 response, will retry in $timeout seconds");

      if($count>0)  {
	my $ae;
	$ae=AnyEvent->timer(after=>$timeout,cb=>sub {
          my $next_id=$self->queue_request($request,sub { 
            my ($self,undef,$result,undef,$response)=@_;
	    $wrap->($self,$id,$result,$request,$response);
	  });
          $self->add_ids_for_blocking($next_id);
          $self->agent->run_next;
	  delete $self->retries->{$ae};
	  undef $ae;
	});
	return $self->retries->{$ae}=$ae;
      }
      my $code=sub {
        my ($self,undef,$result,undef,$response)=@_;
	$cb->($self,$id,$result,$request,$response);
      };

      my $ae;
      $ae=AnyEvent->timer(after=>$timeout,cb=>sub {
        my $next_id=$self->queue_request($request,$code);
        $self->add_ids_for_blocking($next_id);
        $self->agent->run_next;
	delete $self->retries->{$ae};
	undef $ae;
      });
      return $self->retries->{$ae}=$ae;

    };
  }



  return $self->queue_request($request,$wrap);
}


=item * my $id=$self->que_post_json($cb,$url,$data);

Queue's a json post and returns the id

=cut

sub que_post_json {
  my ($self,$cb,$url,$data)=@_;
  return $self->queue_builder($cb,'build_post_json',$url,$data);
}

=item * my $result=$self->build_put_json($url,$data);

Returns a Data::Result object; When true it contains an HTTP::Request Object For $url, the body will consist of $data converted to json.  When false it contains why it failed.

=cut

sub build_put_json {
  my ($self,$url,$data)=@_;

  my $uri=$self->api_url.$url;
  my $json=eval {to_json($data)};
  return $self->new_false("Failed to convert \$data to json, error was $@") if $@;

  my $request=new HTTP::Request(PUT=>$uri,$self->default_headers,$json);
  return $self->new_true($request);
}

=item * my $id=$self->que_put_json($cb,$url,$data);

Queue's a json put and returns the id

=cut

sub que_put_json {
  my ($self,$cb,$url,$data)=@_;
  return $self->queue_builder($cb,'build_put_json',$url,$data);
}

=item * my $result=$self->build_post_form($url,$data);

Returns a Data::Result Object, when true it contains the correctly fromatted HTTP::Request Object, when false it contains why it failed.



( run in 0.982 second using v1.01-cache-2.11-cpan-754626df90b )