AnyEvent-APNS

 view release on metacpan or  search on metacpan

inc/Module/Install/TestBase.pm  view on Meta::CPAN

    $self->include('Test::Base::Filter');
    $self->include('Spiffy');
    $self->include('Test::More');
    $self->include('Test::Builder');
    $self->include('Test::Builder::Module');
    $self->requires('Filter::Util::Call');
}

1;

=encoding utf8

#line 70

inc/Test/Base.pm  view on Meta::CPAN

}

{
    %$reserved_section_names = map {
        ($_, 1);
    } keys(%Test::Base::Block::), qw( new DESTROY );
}

__DATA__

=encoding utf8

#line 1374

inc/Test/TCP.pm  view on Meta::CPAN


sub DESTROY {
    my $self = shift;
    local $@;
    $self->stop();
}

1;
__END__

=encoding utf8

#line 406

inc/Test/Time.pm  view on Meta::CPAN

	}
};

sub unimport {
	$in_effect = 0;
}

1;
__END__

=encoding utf8

#line 90

lib/AnyEvent/APNS.pm  view on Meta::CPAN

package AnyEvent::APNS;
use utf8;
use Any::Moose;

use AnyEvent 4.80;
use AnyEvent::Handle;
use AnyEvent::Socket;
use AnyEvent::TLS;

require bytes;
use Carp qw(croak);
use Encode;

lib/AnyEvent/APNS.pm  view on Meta::CPAN

    isa       => 'AnyEvent::Handle',
    predicate => 'connected',
    clearer   => 'clear_handler',
);

has json_driver => (
    is      => 'rw',
    isa     => 'Object',
    lazy    => 1,
    default => sub {
        JSON::Any->new( utf8 => 1 );
    },
);

has on_error => (
    is      => 'rw',
    isa     => 'CodeRef',
    default => sub { sub { warn @_ } },
);

has on_eof => (

lib/AnyEvent/APNS.pm  view on Meta::CPAN

    isa     => 'Int',
    default => sub { 0; }
);

no Any::Moose;

sub send {
    my $self = shift;
    my ($token, $payload, $expiry) = @_;

    my $json = encode_utf8( $self->json_driver->encode($payload) );

    # http://developer.apple.com/library/ios/#DOCUMENTATION/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingWIthAPS/CommunicatingWIthAPS.html
    # Expiry—A fixed UNIX epoch date expressed in seconds (UTC) that identifies when the notification is no longer valid and can be discarded. The expiry value should be in network order (big endian). If the expiry value is positive, APNs tries to ...
    # default to 24 hours
    $expiry  = defined $expiry ? $expiry : time() + 3600 * 24;

    # Identifier—An arbitrary value that identifies this notification. This same identifier is returned in a error-response packet if APNs cannot interpret a notification.
    my $next_identifier = $self->_increment_identifier;

    my $h = $self->handler;

lib/AnyEvent/APNS.pm  view on Meta::CPAN

    # Apple Push Notification Service refuses string values as badge number
    if ($payload->{aps}{badge} && looks_like_number($payload->{aps}{badge})) {
        $payload->{aps}{badge} += 0;
    }

    # The maximum size allowed for a notification payload is 256 bytes;
    # Apple Push Notification Service refuses any notification that exceeds this limit.
    if ( (my $exceeded = bytes::length($json) - 256) > 0 ) {
        if (ref $payload->{aps}{alert} eq 'HASH') {
            $payload->{aps}{alert}{body} =
                $self->_trim_utf8($payload->{aps}{alert}{body}, $exceeded);
        }
        else {
            $payload->{aps}{alert} = $self->_trim_utf8($payload->{aps}{alert}, $exceeded);
        }

        $json = encode_utf8( $self->json_driver->encode($payload) );
    }

    $h->push_write( pack('n', bytes::length($json)) ); # payload length
    $h->push_write( $json );                           # payload

    return $next_identifier;
}

sub _trim_utf8 {
    my ($self, $string, $trim_length) = @_;

    my $string_bytes = encode_utf8($string);
    my $trimmed = '';

    my $start_length = bytes::length($string_bytes) - $trim_length;
    return $trimmed if $start_length <= 0;

    for my $len ( reverse $start_length - 6 .. $start_length ) {
        local $@;
        eval {
            $trimmed = decode_utf8(substr($string_bytes, 0, $len), Encode::FB_CROAK);
        };
        last if $trimmed;
    }

    return $trimmed;
}

sub connect {
    my $self = shift;

lib/AnyEvent/APNS.pm  view on Meta::CPAN

        $next_identifier = 0;
    }
    $self->last_identifier( $next_identifier );
}

__PACKAGE__->meta->make_immutable;

__END__

=for stopwords
apns SDK TODO iPhone multi-byte utf8

=head1 NAME

AnyEvent::APNS - Simple wrapper for Apple Push Notifications Service (APNS) provider

=head1 SYNOPSIS

    use AnyEvent::APNS;

    my $cv = AnyEvent->condvar;

lib/AnyEvent/APNS.pm  view on Meta::CPAN

    my $identifier = $apns->send( $device_token => {
        aps => {
            alert => 'Message received from Bob',
        },
    });

C<$device_token> should be a binary 32bytes device token provided by iPhone SDK (3.0 or above)

C<\%payload> should be a hashref suitable to apple document: L<http://developer.apple.com/iPhone/library/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/ApplePushService/ApplePushService.html>

Note: If you involve multi-byte strings in C<\%payload>, it should be utf8 decoded strings not utf8 bytes.

Store C<$identifier> with your C<$device_token> to react to C<on_error_response>.

=head2 $apns->handler

Return L<AnyEvent::Handle> object which is used to current established connection. It returns undef before connection completed.

=head1 TODO

=over 4

t/02_trim.t  view on Meta::CPAN

BEGIN { $ENV{PERL_DL_NONLAZY} = 0; } # XXX

use utf8;
use Test::Base;
use Test::TCP;
use Test::Time; # to fix expiry

plan tests => 16;

use AnyEvent::APNS;
use AnyEvent::Socket;

my $port = empty_port;

t/03_validate.t  view on Meta::CPAN

use utf8;
use Test::Base;

use AnyEvent::APNS;

use Test::Exception;
use Test::TCP;

plan tests => 4;

my $port = empty_port;

xt/live.t  view on Meta::CPAN

use utf8;
use Test::Base;

plan 'no_plan';

use Path::Class qw/file/;
use AnyEvent::APNS;


my $cer = "$ENV{HOME}/dev/apns/test.cer";
my $key = "$ENV{HOME}/dev/apns/test.key";



( run in 1.263 second using v1.01-cache-2.11-cpan-49f99fa48dc )