Net::APNS::Notification - Notify client in Apple Push Notification Service for perl.


Net-APNS documentation Contained in the Net-APNS distribution.

Index


Code Index:

NAME

Top

Net::APNS::Notification - Notify client in Apple Push Notification Service for perl.

DESCRIPTION

Top

Net::APNS::Notification is Apple Push Notification Service - push client. Push message to iPhone.

AUTHOR

Top

haoyayoi <st.hao.yayoi@gmail.com>

METHOD

Top

write()

Push messages.

SEE ALSO

Top

Net::APNS

LICENSE

Top

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.


Net-APNS documentation Contained in the Net-APNS distribution.

package Net::APNS::Notification;

use Any::Moose;
use Net::SSLeay qw/die_now die_if_ssl_error/;
use Socket;
use Encode qw(decode encode);
use JSON::XS;
our $VERSION = '0.02';

has message => (
    is      => 'rw',
    isa     => 'Str',
    default => '',
);

has badge => (
    is      => 'rw',
    isa     => 'Int',
    default => 0,
);

has devicetoken => (
    is       => 'rw',
    isa      => 'Str',
    trigger  => sub {
        if (@_ >= 2) {
            my $dt = $_[1];
            $dt =~ s/\s//g;
            $_[0]->{devicetoken} = $dt;
        }
    }
);

has cert => (
    is       => 'rw',
    isa      => 'Str',
    required => 1,
);

has key => (
    is       => 'rw',
    isa      => 'Str',
    required => 1,
);

has passwd => (
    is  => 'rw',
);

sub type_pem { &Net::SSLeay::FILETYPE_PEM }

sub _apple_serv_params {
    my $self = $_[0];
    return sockaddr_in( $self->port, inet_aton( $self->host ) );
}

sub host {
    my $self = $_[0];
    return 'gateway.' .
           $self->sandbox ? 'sandbox.' : '' .
           'push.apple.com';
}

has port => (
    is       => 'rw',
    isa      => 'Int',
    default  => 2195,
);

has sandbox => (
    is      => 'rw',
    isa     => 'Bool',
    default => 0,
);

sub _message_encode {
    my $self = shift;
    return encode( 'unicode', decode( 'utf8', $self->message ) );
}

sub _pack_payload {
    my $self = shift;
    my $jsonxs = JSON::XS->new->utf8(1)->encode({
        aps => {
            alert => $self->_message_encode,
            badge => $self->badge,
        }
    });
    $jsonxs =~ s/("badge":)"([^"]+)"/$1$2/;
    return
        chr(0)
      . pack( 'n',  32 )
      . pack( 'H*', $self->devicetoken )
      . pack( 'n',  length($jsonxs) )
      . $jsonxs;
}

sub write {
    my ( $self, $args ) = @_;
    if ( $args->{devicetoken} ) { $self->devicetoken( $args->{devicetoken} ); }
    if ( $args->{message} )     { $self->message( $args->{message} ); }
    if ( $args->{badge} )       { $self->badge( $args->{badge} ); }
    $Net::SSLeay::trace       = 4;
    $Net::SSLeay::ssl_version = 10;

    Net::SSLeay::load_error_strings();
    Net::SSLeay::SSLeay_add_ssl_algorithms();
    Net::SSLeay::randomize();

    my $socket;
    socket( $socket, PF_INET, SOCK_STREAM, getprotobyname('tcp') )
      or die "socket: $!";
    connect( $socket, $self->_apple_serv_params ) or die "Connect: $!";

    my $ctx = Net::SSLeay::CTX_new() or die_now("Failed to create SSL_CTX $!.");
    Net::SSLeay::CTX_set_options( $ctx, &Net::SSLeay::OP_ALL );
    die_if_ssl_error("ssl ctx set options");

    Net::SSLeay::CTX_set_default_passwd_cb( $ctx, sub { $self->passwd } );
    Net::SSLeay::CTX_use_RSAPrivateKey_file( $ctx, $self->key, $self->type_pem );
    die_if_ssl_error("private key");
    
    Net::SSLeay::CTX_use_certificate_file( $ctx, $self->cert, $self->type_pem );
    die_if_ssl_error("certificate");

    my $ssl = Net::SSLeay::new($ctx);
    Net::SSLeay::set_fd( $ssl, fileno($socket) );
    Net::SSLeay::connect($ssl) or die_now("Failed SSL connect ($!)");
    Net::SSLeay::write( $ssl, $self->_pack_payload );
    CORE::shutdown( $socket, 1 );
    Net::SSLeay::free($ssl);
    Net::SSLeay::CTX_free($ctx);
    close($socket);
}

__PACKAGE__->meta->make_immutable;

__END__