| Net-Flickr-API documentation | Contained in the Net-Flickr-API distribution. |
Net::Flickr::API - base API class for Net::Flickr::* libraries
package Net::Flickr::RDF; use base qw (Net::Flickr::API);
Base API class for Net::Flickr::* libraries
Net::Flickr::API is a wrapper for Flickr::API that provides support for throttling API calls (per second), retries if the API is disabled and marshalling of API responses into XML::LibXML or XML::XPath objects.
Options are passed to Net::Flickr::Backup using a Config::Simple object or a valid Config::Simple config file. Options are grouped by "block".
String. required
A valid Flickr API key.
String. required
A valid Flickr Auth API secret key.
String. required
A valid Flickr Auth API token.
String. required
The api_handler defines which XML/XPath handler to use to process API responses.
Use XML::LibXML.
Use XML::XPath.
Boolean.
Default is false.
String.
The default handler is Screen, as in Log::Dispatch::Screen
For example, the following :
reporting_handler_args=name:foobar;min_level=info
Would be converted as :
(name => "foobar", min_level => "info");
The default name argument is "__report". The default min_level argument is "info".
Where $cfg is either a valid Config::Simple object or the path to a file that can be parsed by Config::Simple.
Returns a Net::Flickr::API object.
Valid args are :
A string containing the name of the Flickr API method you are calling.
A hash ref containing the key value pairs you are passing to method
If the method encounters any errors calling the API, receives an API error or can not parse the response it will log an error event, via the log method, and return undef.
Otherwise it will return a XML::LibXML::Document object (if XML::LibXML is installed) or a XML::XPath object.
Return an XML node element containing the Flickr auth token information for the current object.
Returns undef if no token information is present.
Return the Flickr NSID of the user associated with the Flickr auth token information for the current object.
Returns undef if no token information is present.
This is a helper method that simply wraps calls to the Flickr::Upload upload method. All the arguments are the same. For complete documentation please consult:
http://search.cpan.org/dist/Flickr-Upload/Upload.pm#upload
(Note: There's no need to pass an auth_token argument as the wrapper will take care of for you.)
Returns a photo ID (or a ticket ID if the call is asynchronous) on success or false if there was a problem.
Returns a Log::Dispatch object.
1.7
$Date: 2009/08/02 17:16:12 $
Aaron Straup Cope <ascope@cpan.org>
Please report all bugs via http://rt.cpan.org/
Copyright (c) 2005-2008 Aaron Straup Cope. All Rights Reserved.
This is free software. You may redistribute it and/or modify it under the same terms as Perl itself.
| Net-Flickr-API documentation | Contained in the Net-Flickr-API distribution. |
use strict; # $Id: API.pm,v 1.35 2009/08/02 17:16:12 asc Exp $ # -*-perl-*- package Net::Flickr::API; $Net::Flickr::API::VERSION = '1.7';
use Config::Simple; use Flickr::API; use Flickr::Upload; use Readonly; use Data::Dumper; use Log::Dispatch; use Log::Dispatch::Screen; Readonly::Scalar my $PAUSE_SECONDS_OK => 2; Readonly::Scalar my $PAUSE_SECONDS_UNAVAILABLE => 4; Readonly::Scalar my $PAUSE_MAXTRIES => 10; Readonly::Scalar my $PAUSE_ONSTATUS => 503; Readonly::Scalar my $RETRY_MAXTRIES => 10;
sub new { my $pkg = shift; my $cfg = shift; my $self = {'__wait' => time() + $PAUSE_SECONDS_OK, '__paused' => 0, '__retries' => 0,}; bless $self,$pkg; if (! $self->init($cfg)) { undef $self; } return $self; } sub init { my $self = shift; my $cfg = shift; $self->{cfg} = (UNIVERSAL::isa($cfg, "Config::Simple")) ? $cfg : Config::Simple->new($cfg); if ($self->{cfg}->param("flickr.api_handler") !~ /^(?:XPath|LibXML)$/) { warn "Invalid API handler"; return 0; } # my $log_fmt = sub { my %args = @_; my $msg = $args{'message'}; chomp $msg; if ($args{'level'} eq "error") { my ($ln, $sub) = (caller(4))[2,3]; $sub =~ s/.*:://; return sprintf("[%s][%s, ln%d] %s\n", $args{'level'}, $sub, $ln, $msg); } return sprintf("[%s] %s\n", $args{'level'}, $msg); }; my $logger = Log::Dispatch->new(callbacks=>$log_fmt); my $error = Log::Dispatch::Screen->new(name => '__error', min_level => 'error', stderr => 1); $logger->add($error); # # Custom report logging # if ($self->{cfg}->param("reporting.enable")) { my $report_handler = $self->{cfg}->param("reporting.handler") || "Screen"; $report_handler =~ s/:://g; my $report_pkg = "Log::Dispatch::$report_handler"; eval "require $report_pkg"; if ($@) { warn "Failed to load $report_pkg, $@"; return 0; } my %report_args = (); if (my $args = $self->{cfg}->param("reporting.handler_args")) { foreach my $part (split(",", $args)) { my ($key, $value) = split(":", $part); $report_args{$key} = $value; } } $report_args{'name'} ||= "__report"; $report_args{'min_level'} ||= "info"; my $reporter = $report_pkg->new(%report_args); if (! $reporter) { warn "Failed to instantiate $report_pkg, $!"; return 0; } $logger->add($reporter); } $self->{'__logger'} = $logger; # $self->{api} = Flickr::API->new({key => $self->{cfg}->param("flickr.api_key"), secret => $self->{cfg}->param("flickr.api_secret"), handler => $self->{cfg}->param("flickr.api_handler")}); my $pkg = ref($self); my $version = undef; do { my $ref = join("::", $pkg, "VERSION"); no strict "refs"; $version = ${$ref}; }; my $agent_string = sprintf("%s/%s", $pkg, $version); $self->{api}->agent($agent_string); return 1; }
sub api_call { my $self = shift; my $args = shift; # # check to see if we need to take # breather (are we pounding or are # we not?) while (time < $self->{'__wait'}) { my $debug_msg = sprintf("trying not to beat up the Flickr servers, pause for %.2f seconds\n", $PAUSE_SECONDS_OK); $self->log()->debug($debug_msg); sleep($PAUSE_SECONDS_OK); } # send request if (exists($args->{'args'}->{'api_sig'})) { delete $args->{'args'}->{'api_sig'}; } $args->{'args'}->{'auth_token'} = $self->{cfg}->param("flickr.auth_token"); # my $req = Flickr::API::Request->new($args); my $res = undef; $self->log()->debug("calling $args->{method} : " . Dumper($args->{args})); eval { $res = $self->{'api'}->execute_request($req); }; if ($@) { $self->log()->error("Fatal error calling the Flickr API, $@"); $self->{'__wait'} = time + $PAUSE_SECONDS_OK; $self->{'__paused'} = 0; return undef; } # # check for 503 status # if ($res->code() eq $PAUSE_ONSTATUS) { $res = $self->retry_api_call($args, $res); } $self->{'__wait'} = time + $PAUSE_SECONDS_OK; $self->{'__paused'} = 0; return $self->parse_api_call($args, $res); }
sub get_auth { my $self = shift; if (! $self->{'__auth'}) { my $auth = $self->api_call({"method" => "flickr.auth.checkToken"}); if (! $auth) { return undef; } my $nsid = $auth->find("/rsp/auth/user/\@nsid")->string_value(); if (! $nsid) { $self->log()->error("unabled to determine ID for token"); return undef; } $self->{'__auth'} = $auth; } return $self->{'__auth'}; }
sub get_auth_nsid { my $self = shift; if (my $auth = $self->get_auth()){ return $auth->find("/rsp/auth/user/\@nsid")->string_value(); } return undef; } sub parse_api_call { my $self = shift; my $args = shift; my $res = shift; $self->log()->debug($res->decoded_content()); my $xml = $self->_parse_results_xml($res); if (! $xml) { $self->log()->error("failed to parse API response, calling $args->{method}"); $self->log()->error($res->decoded_content()); return undef; } my $stat = $xml->find("/rsp/\@stat")->string_value(); if ($stat eq "fail") { my $code = $xml->findvalue("/rsp/err/\@code"); my $msg = $xml->findvalue("/rsp/err/\@msg"); $self->log()->error(sprintf("[%s] %s (calling $args->{method})\n", $code, $msg)); if ($code==0) { $self->log()->info(sprintf("api disabled attempting %s/%s tries to see if it's come back up", $self->{'__retries'}, $RETRY_MAXTRIES)); return $self->api_disabled($args, $res); } } $self->{'__retries'} = 0; return ($@) ? undef : $xml; } sub _parse_results_xml { my $self = shift; my $res = shift; my $xml = undef; # # Please for Cal to someday accept the patch to add # response handlers to Flickr::API... # if ($self->{cfg}->param("flickr.api_handler") eq "XPath") { eval "require XML::XPath"; if (! $@) { eval { $xml = XML::XPath->new(xml=>$res->decoded_content()); }; } } else { eval "require XML::LibXML"; if (! $@) { eval { my $parser = XML::LibXML->new(); $xml = $parser->parse_string($res->decoded_content()); }; } } # if (! $xml) { $self->log()->error("XML parse error : $@"); return undef; } # return $xml; } sub api_disabled { my $self = shift; my $args = shift; my $res = shift; $self->{'__retries'} ++; if ($self->{'__retries'} > $RETRY_MAXTRIES) { $self->log()->critical(sprintf("API still down after %s tries - exiting", $RETRY_MAXTRIES)); exit; } $res = $self->retry_api_call($args, $res); if (! $res) { $self->log()->critical("Returned false during 'api disabled' retry. That can only be bad - exiting"); exit; } return $res; } sub retry_api_call { my $self = shift; my $args = shift; my $res = shift; # you are in a dark and twisty corridor # where all the errors look the same - # just give up if we hit this ceiling $self->{'__paused'} ++; if ($self->{'__paused'} > $PAUSE_MAXTRIES) { my $errmsg = sprintf("service returned '%d' status %d times; exiting", $PAUSE_ONSTATUS, $PAUSE_MAXTRIES); $self->log()->error($errmsg); return undef; } my $retry_after = $res->header("Retry-After"); my $debug_msg = undef; if ($retry_after ) { $debug_msg = sprintf("service unavailable, requested to retry in %d seconds", $retry_after); } else { $retry_after = $PAUSE_SECONDS_UNAVAILABLE * $self->{'__paused'}; $debug_msg = sprintf("service unavailable, pause for %.2f seconds", $retry_after); } $self->log()->debug($debug_msg); sleep($retry_after); # try, try again return $self->api_call($args); }
sub upload { my $self = shift; my $args = shift; $args->{'auth_token'} = $self->{cfg}->param("flickr.auth_token"); my $ua = Flickr::Upload->new({'key' => $self->{cfg}->param("flickr.api_key"), 'secret' => $self->{cfg}->param("flickr.api_secret")}); my $id = undef; eval { $id = $ua->upload(%$args); }; if ($@){ $self->log()->error("upload failed: $@"); return 0; } return $id; }
sub log { my $self = shift; return $self->{'__logger'}; }
return 1; __END__