Backblaze-B2

 view release on metacpan or  search on metacpan

lib/Backblaze/B2.pm  view on Meta::CPAN

package Backblaze::B2;
use strict;
use vars qw($VERSION);
$VERSION = '0.02';

=head1 NAME

Backblaze::B2 - interface to the Backblaze B2 API

=head1 SYNOPSIS

=head1 METHODS

=head2 C<< Backblaze::B2->new %options >>

=over 4

=item B<< version >>

Allows you to specify the API version. The current
default is C<< v1 >>, which corresponds to the
Backblaze B2 API version 1 as documented at
L<https://www.backblaze.com/b2/docs/>.

=back

=cut

sub new {
    my( $class, %options ) = @_;
    $options{ version } ||= 'v1';
    $class = "$class\::$options{ version }";
    $class->new( %options );
};

=head1 SETUP

=over 4

=item 0. Have a telephone / mobile phone number you're willing to
share with Backblaze

=item 1. Register at for Backblaze B2 Cloud Storage at 

L<https://secure.backblaze.com/account_settings.htm?showPhone=true>

=item 2. Add the phone number to your account at

L<https://secure.backblaze.com/account_settings.htm?showPhone=true>

=item 3. Enable Two-Factor verification through your phone at

L<https://secure.backblaze.com/account_settings.htm?showPhone=true>

=item 4. Create a JSON file named C<B2.credentials>

This file should live in your
home directory
with the application key and the account key:

    { "accountId":      "...",
      "applicationKey": ".............."
    }

=back

=cut

package Backblaze::B2::v1;
use strict;
use Carp qw(croak);

=head1 NAME

Backblaze::B2::v1 - Backblaze B2 API account

=head1 METHODS

=head2 C<< ->new %options >>

    my $b2 = Backblaze::B2::v1->new(
        api => 'Backblaze::B2::v1::Synchronous', # the default
    );

Creates a new instance. Depending on whether you pass in
C<<Backblaze::B2::v1::Synchronous>> or C<<Backblaze::B2::v1::AnyEvent>>,
you will get a synchronous or asynchronous API.

The synchronous API is what is documented here, as this is the
most likely use case.

    my @buckets = $b2->buckets();
    for( @buckets ) {
        ...
    }

The asynchronous API is identical to the synchronous API in spirit, but
will return L<Promises> . These condvars usually return
two or more parameters upon completion:

    my $results = $b2->buckets();
    $results->then( sub{ 
        my( @buckets ) = @_;
        for( @buckets ) {
            ...
        }
    }

The asynchronous API puts the burden of error handling into your code.

=cut

use vars '$API_BASE';
$API_BASE = 'https://api.backblazeb2.com/b2api/v1/';

sub new {
    my( $class, %options ) = @_;
    
    # Hrr. We need to get at an asynchronous API here and potentially
    # wrap the results to synchronous results in case the user wants them.
    # Turtles all the way down, this means we can't reuse calls into ourselves...

    $options{ api } ||= 'Backblaze::B2::v1::Synchronous';
    if( ! ref $options{ api }) {
        eval "require $options{ api }";
        my $class = delete $options{ api };
        $options{ api } = $class->new(%options);
    };
    
    if( $options{ api }->isAsync ) {
        $options{ bucket_class } ||= 'Backblaze::B2::v1::Bucket';
        $options{ file_class } ||= 'Backblaze::B2::v1::File';
    } else {
        $options{ bucket_class } ||= 'Backblaze::B2::v1::Bucket::Synchronized';
        $options{ file_class } ||= 'Backblaze::B2::v1::File::Synchronized';
    };
    
    bless \%options => $class
}

sub read_credentials {
    my( $self, @args ) = @_;
    $self->api->read_credentials(@args)
}

sub authorize_account {
    my( $self, @args ) = @_;
    $self->api->authorize_account(@args)
}

sub _new_bucket {
    my( $self, %options ) = @_;
    
    $self->{bucket_class}->new(
        %options,
        api => $self->api,
        parent => $self,
        file_class => $self->{file_class}
    )
}

sub await($) {
    my $promise = $_[0];
    my @res;
    if( $promise->is_unfulfilled ) {
        require AnyEvent;
        my $await = AnyEvent->condvar;
        $promise->then(sub{
            $await->send(@_);
        }, sub {
            warn "@_";
        });
        @res = $await->recv;
    } else {
        warn "Have results already";
        @res = @{ $promise->result }
    }
    @res
};

sub payload($) {
    my( $ok, $msg, @results ) = await( $_[0] );
    if(! $ok) { croak $msg };
    return wantarray ? @results : $results[0];
}

=head2 C<< ->buckets >>

    my @buckets = $b2->buckets();

Returns a list of L<Backblaze::B2::Bucket> objects associated with
the B2 account.

=cut

sub buckets {
    my( $self ) = @_;
    my $list = $self->api->asyncApi->list_buckets()->then( sub {
        my( $ok, $msg, $list ) = @_;
        map { $self->_new_bucket( %$_ ) }
            @{ $list->{buckets} }
    });
    



( run in 0.802 second using v1.01-cache-2.11-cpan-39bf76dae61 )