Code Monkey home page Code Monkey logo

apns4erl's Introduction

Apns4erl v2 Build Statuscodecov

This lib is intended to allow you to write an APNs provider for Apple Push Notificaion services (APNs) over HTTP2 in Erlang.

Copyright (c) 2017 Erlang Solutions Ltd. [email protected], released under the Apache 2 license

You can find the v1 here?

Note: Apns4erl v2 is still under development. Currently it supports push notifications with certificate and authentication token.

Contact Us

If you find any bugs or have a problem while using Apns4erl, please open an issue in this repo (or a pull request :)).

Requirements

  • You must have installed an updated Openssl version or, at least, be sure it supports TLS 1.2+. New APNs server only supports connections over TLS 1.2+.
  • Erlang R19+

Important Links

How to use it?

First we have to fill our config data. There are two ways for do this, one is filling a config file. This is an example you can find at test/test.config:

{
  apns,
  [ {apple_host,       "api.development.push.apple.com"}
  , {apple_port,       443}
  , {certfile,         "priv/apns-dev-cert.pem"}
  , {keyfile,          "priv/apns-dev-key-noenc.pem"}
  , {token_keyfile,    "priv/APNsAuthKey_KEYID12345.p8"}
  , {timeout,          10000}

  %% APNs Headers

  , {apns_id,          undefined}
  , {apns_expiration,  0}
  , {apns_priority,    10}
  , {apns_topic,       "com.example.myapp"}
  , {apns_collapse_id, undefined}
  , {apns_push_type,   "alert"}

  %% Feedback
  , {feedback_host,    "feedback.push.apple.com"}
  , {feedback_port,    2195}
  ]
  ]
}

The other way is send all that info as a parameter to apns:connect/1 function encapsulated in a apns_connection:connection() structure:

#{ name       := name()
 , apple_host := host()
 , apple_port := inet:port_number()
 , certfile   => path()
 , keyfile    => path()
 , timeout    => integer()
 , type       := type()
 }.

APNs allows two connection types, one is using Provider Certificates. The first certificate option is to supply cert paths in certfile and keyfile. Alternatively, you can supply a cert binary in certdata and a keydata()-type tuple (see: https://github.com/inaka/apns4erl/blob/master/src/apns_connection.erl#L64) in keydata. Certs are the Provider Certificates and the keys are the Private Key both provided by Apple. We need them in .pem format, here is an example of how to convert them, check the certificates section.

The other way to connect against APNs is using Provider Authentication Tokens, for this choice you must fill the field token_keyfile. This is a path to the Authentication Key provided by Apple. This is in .p8 format and it doesn't need conversion.

This key will be needed in order to generate a token which will be used every time we try to push a notification. In connection's time it is not needed.

Run

apns4erl can be included as a dependency and started from yourapp.app.src. You also can run it on the shell for testing.

> rebar3 compile
> erl -pa _build/default/lib/*/ebin -config test/test.config

Don't forget your config file if you want to use apns:connect/2.

1> apns:start().
ok

Create connections

After running apns4erl app we can start creating connections. As we mentioned before there are two types of connections. Both are created using the functions apns:connect/1 and apns:connect/2.

  • apns:connect/1: This function accepts as a parameter an apns_connection:connection() structure.

    #{ name       := name()
     , apple_host := host()
     , apple_port := inet:port_number()
     , certdata   => binary()
     , certfile   => path()
     , keydata    => keydata()
     , keyfile    => path()
     , timeout    => integer()
     , type       := type()
     }.

    where the type field indicates if is certdata, cert, or token.

  • apns:connect/2: The first argument is the type and the second one is the connection's name. In order to use it successfully we have to fill the config file before, as explained in how to use it? section.

Example:

1> apns:connect(cert, my_first_connection).
{ok,<0.87.0>}
2> apns:connect(#{name => another_cert, apple_host => "api.push.apple.com", apple_port => 443,
certfile => "priv/cert.pem", keyfile => "priv/key.pem", type => cert}).
3> apns:connect(token, my_second_connection).
{ok,<0.95.0>}

Note cert and token define the type we want.

apns:connect/2 returns the connection pid.

Create Connections without name

In some scenarios we don't want to assign names to the connections instead we want working just with the pid (working with a pool of connections for example). If that is the case we use the same apns:connect/1 and apns:connect/2 functions but instead of a connection name we put undefined:

1> apns:connect(cert, undefined).
{ok,<0.127.0>}
2> apns:connect(#{name => undefined, apple_host => "api.push.apple.com", apple_port => 443,
certfile => "priv/cert2.pem", keyfile => "priv/key2-noenc.pem", type => cert}).
{ok,<0.130.0>}
3> apns:connect(token, my_second_connection).
{ok,<0.132.0>}

Push Notifications over Provider Certificate connections

In order to send Notifications over Provider Certificate connection we will use apns:push_notification/3,4.

We will need the connection, a notification, the device ID and some http2 headers. The connection is the atom we used when we executed apns:connect/2 for setting a name or its pid, the device ID is provided by Apple, the notification is a map with the data we want to send, that map will be encoded to json later and the http2 headers can be explicitly sent as a parameter using apns:push_notification/4 or can be defined at the config file, in that case we would use apns:push_notification/3.

This is the headers format:

-type headers()   :: #{ apns_id          => binary()
                      , apns_expiration  => binary()
                      , apns_priority    => binary()
                      , apns_topic       => binary()
                      , apns_collapse_id => binary()
                      , apns_push_type   => binary()
                      , apns_auth_token  => binary()
                      }.

All of them are defined by Apple here

Lets send a Notification.

1> {ok, Pid} = apns:connect(cert, my_first_connection).
{ok,<0.85.0>}
2> DeviceId = <<"a0dc63fb059cb9c13b03e5c974af3dd33d67fed4147da8c5ada0626439e18935">>.
<<"a0dc63fb059cb9c13b03e5c974af3dd33d67fed4147da8c5ada0626439e18935">>
3> Notification = #{aps => #{alert => <<"you have a message">>}}.
#{aps => #{alert => <<"you have a message">>}}
4> apns:push_notification(my_first_connection, DeviceId, Notification).
{200,
 [{<<"apns-id">>,<<"EFDE0D9D-F60C-30F4-3FF1-86F3B90BE434">>}],
 no_body}
5> apns:push_notification(Pid, DeviceId, Notification).
{200,
 [{<<"apns-id">>,<<"EFDE0D9D-F60C-30F4-3FF1-86F3B90BE654">>}],
 no_body}

The result is the response itself, its format is:

-type response()  :: { integer()          % HTTP2 Code
                     , [term()]           % Response Headers
                     , [term()] | no_body % Response Body
                     } | timeout.

And that's all.

Push Notifications over Provider Authentication Tokens connections

This is the other way APNs allows us to send notifications. In this case we don't need a certificate but we will need a p8 file with the private key we will use to sign the token. Lets assume we've got the file APNsAuthKey_KEYID12345.p8 from Apple. We then have to fill the config file key token_keyfile with the path to that file.

We will need a kid value, this is the key identifier. In our case is the last 10 chars of the file name (KEYID123456). We will need also the iss value, this is the Team Id, that can be checked on your Apple's Developer account, in our case it will be THEATEAM. And that's it.

You can find more info here

In order to push a notification we will use apns:push_notification_token/4,5. We will need the same attributes we used sending a notification over Provider Certificate connections plus a signed token. This token has a 1 hour life, so that means we can generate one token and use it many times till it expires. Lets try.

Create the token:

6> TeamId = <<"THEATEAM">>.
<<"THEATEAM">>
7> KeyID = <<"KEYID123456">>.
<<"KEYID123456">>
8> Token = apns:generate_token(TeamId, KeyID).
<<"eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IktFWUlEMTIzNDU2In0.eyJpc3MiOiJUSEVBVEVBTSIsImlhdCI6MTQ4NjE0OTMzNH0.MEQC"...>>

Now push the notification:

12> DeviceId = <<"a0dc63fb059cb9c13b03e5c974af3dd33d67fed4147da8c5ada0626439e18935">>.
<<"a0dc63fb059cb9c13b03e5c974af3dd33d67fed4147da8c5ada0626439e18935">>
13> Notification = #{aps => #{alert => <<"you have a message">>}}.
#{aps => #{alert => <<"you have a message">>}}
14> apns:push_notification_token(my_second_connection, Token, DeviceId, Notification).
{200,
 [{<<"apns-id">>,<<"EBC03BF9-A784-FDED-34F7-5A8D859DA977">>}],
 no_body}

We can use this token for an entire hour, after that we will receive something like this:

16> apns:push_notification_token(my_second_connection, Token, DeviceId, Notification).
{403,
 [{<<"apns-id">>,<<"03FF9497-8A6B-FFD6-B32B-160ACEDE35F0">>}],
 [{<<"reason">>,<<"ExpiredProviderToken">>}]}

Pushing notifications

NOTE in order to push notifications, in both ways, we must call apns:push_notification/3,4 and apns:push_notification_token/4,5 from the same process which created the connection. If we try to do it from a different one we will get an error {error, not_connection_owner}.

Reconnection

If network goes down or something unexpected happens the gun connection with APNs will go down. In that case apns4erl will send a message {reconnecting, ServerPid} to the client process, that means apns4erl lost the connection and it is trying to reconnect. Once the connection has been recover a {connection_up, ServerPid} message will be send.

We implemented an Exponential Backoff strategy. We can set the ceiling time adding the backoff_ceiling variable on the config file. By default it is set to 10 (seconds).

Close connections

Apple recommends us to keep our connections open and avoid opening and closing very often. You can check the Best Practices for Managing Connections section.

But when closing a connection makes sense apns4erl gives us the function apns:close_connection/1 where the parameter is the connection's name or the connection's pid. After using it the name will be available for new connections again (if it was different than undefined).

Feedback

apns4erl also allows us to get feedback from APNs service. It does it thru the binary API.

In order to get feedback we would need a Provider Certificate. apns4erl provides us two functions, apns:get_feedback/0 and apns:get_feedback/1 which require some Feedback's information like url, port, timeout... We can set that info in our config file and use apns:get_feedback/0. We can also send all that configuration as a parameter to apns:get_feedback/1 where the config structure must looks like this:

#{ host     := string()
 , port     := pos_integer()
 , certfile := string()
 , keyfile  => string()
 , timeout  := pos_integer()
 }.

The response for both functions will be a list of feedback()

-type feedback() :: {calendar:datetime(), string()}.

Where the first element in the tuple is the date when the device uninstalled the app and the second element is the Device Id.

Changelog Generation

If you want to generate a new release of this project, you'll need to update the CHANGELOG.md file. We generally do it using github_changelog_generator. This project needs a special option passed to it, tho: --exclude-tags-regex '1*'. Otherwise, it will fail since version 2 releases started from a clean HEAD and therefore have nothing in common with the ones for version 1.

apns4erl's People

Contributors

andreabenini avatar cabol avatar danielfinke avatar dcy avatar dgtony avatar dsrosario avatar elbrujohalcon avatar essen avatar euen avatar ferigis avatar getong avatar harenson avatar igaray avatar lazedo avatar paulo-ferraz-oliveira avatar sztheory avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

apns4erl's Issues

Post 1.0.0 Tagged Release

The only tagged release, 1.0.0, doesn't support R16 and is missing a lot of new commits. Specifying HEAD as the dependency's version has caused me problems in the past, so I'd love to see a new release get tagged. Thanks!

Multiple connections to feedback service

Correct me if I am wrong, but if I wanted to create multiple connections to the APN services, I would simply call connect function with a different connection name atom. Would I not end up connecting to the feedback server in each gen_server worker which is probably redundant?

Thanks, O.

Support latest APNs notification format

Build error on R16B03-01 and R15B03

Thanks for the great library! We've been running it in production for three or four years with great success.

It looks like the change (bd9048e) to use queue:queue() as a type rather than plain queue() might have broken the build on releases older than R17:

ERLC   apns.erl apns_queue.erl apns_sup.erl apns_connection.erl
src/apns_queue.erl:32: referring to built-in type queue as a remote type; please take out the module name
src/apns_queue.erl:111: referring to built-in type queue as a remote type; please take out the module name
make: *** [ebin/apns.app] Error 1

It looks like the OTP team knew this would be a backwards-incompatible change and introduced a compiler option to suppress the warning, which might be more appropriate than switching to the new type (at least until R18 is released): http://erlang.org/pipermail/erlang-questions/2014-March/078081.html

If support for older releases (R14, 15, and 16, as defined in the rebar.config) is still desired, is it possible to use a preprocessor guard around the new types? We don't use types in our Erlang app, so I'm unsure here.

Here are the build results from three OTP versions: https://travis-ci.org/eleostech/apns4erl/builds/67406167

ssl_closed after some messages

hi,
After sending messages we get usual

Sending msg <<"½U÷N">> (expires on 1474400981)

but the message is not delivered to a device.

After some of those, connection to apple push server is closed.
We dont have feedback from apple, because connection to feedback server is also closed.
In both cases its sl_closed. What may be the reason of that?

It seems that it happens when we send some non-standard characters (emojis, ellipsis).
There are no crashes or side errors.
Any advice?

thanks

Handling 'DOWN' connection when sending message using send_message

I observe following code in test_suite:

apns:send_message(
  ?TEST_CONNECTION, ?DEVICE_TOKEN,
  Now ++ " - Test Alert", random:uniform(10), "chime"),

receive
{'DOWN', Ref, _, _, _} = DownMsg ->
throw(DownMsg);
DownMsg ->
throw(DownMsg)
after 1000 ->
ok
end,

If I understand this correctly (new to Erlang) its looking for "DOWN" message which will come as part of connection monitoring if the connection goes down - Ref = erlang:monitor(process, Pid),

  • Does "after -> 1000" mean that apns worker will go down after 1 sec it detected a connection "DOWN"?
  • Would this mean that message will be lost?
  • Would apns_sup restart the worker process, reset the connection?
  • What needs to be done for the message which was being sent when connection was detected 'DOWN'

Please guide me to understand this better.

ssl:connect return {error,closed}

Hi,I've encountered a problem as the title describes

The Erlang version is R17.5,but the ssl version is 7.0(because ssl6.0 caused error})

delete subscription callback not getting called

Hi,
I am experiencing an issue which I do not know how to resolve.

I am able to send notifications but when I delete the app, I do not receive feedback.

I started apns connection:

        apns:connect(?APNS_CONNECTION, fun ?MODULE:handle_apns_error/2, fun ?MODULE:handle_apns_delete_subscription/1).

My handler is as follows:

handle_apns_delete_subscription(Token) ->
  error_logger:warning_msg("Device with token ~p removed the app~n", [Token]),

I did not see the above output in my logs.

I logs I have

2015-04-03 05:38:58.863 [info] <0.388.0> Feedback server disconnected. Waiting 18000000 millis to connect again...
2015-04-03 10:38:59.191 [info] <0.388.0> Feedback server disconnected. Waiting 18000000 millis to connect again...
2015-04-03 15:38:59.301 [info] <0.388.0> Feedback server disconnected. Waiting 18000000 millis to connect again...

Would you be able to tell if I am missing something?

I am on Sandbox

How to get query and get data from FeebackService

In Apple APNS "The Feedback Service" doc section, this is mentioned:

Query the feedback service daily to get the list of device tokens. Use the timestamp to verify that the device tokens haven’t been reregistered since the feedback entry was generated. For each device that has not been reregistered, stop sending notifications.

  • Would you be able to tell how can I get the list of tokens using apns4erl from Apple Feedback Service?

There is a feedback connection. But how do I get data and process it? Is there an example?

Please provide pointers!

How can I get apns4erl integrated with ejabberd

I am new to erlang and ejabberd. I have gone through docs and tutorials on erlang and ejabberd.

I am still not sure how to integrate apns4erl with ejabberd. I need to be able to do the following:

  • Add apns4erl module to with ejabberd_hooks for event offline_message_hook
  • That should start the apns4erl module.
  • From there, every a offline message is received, I need to be able to call send_message from apns4erl.
  • Also, I need have an persistent connection from apns4erl to Apple APN server.

Would you be able to give me starting pointers on to get apns4erl started with ejabberd??

Do I need to start apns4erl application from my custom module that I will hook with ejabberd. is that how it will work??

Thanks in advance!
Gaurav Jain

Full Library Revamp

We need to get this library into Erlang/OTP 18.x world.
The plan is to start using maps where we used records before, stop requiring headers, revisit the way we start/stop connections and how we properly display errors from APNS.
In the process, we should address as many open issues as possible and ensure 100% code coverage in tests.

How can I get apns4erl integrated with ejabberd

Indeed I've seen that there's another closed issue with the same name, but there's no any guide/tutorial that explains how to make this integration.

I don't know some things:

  1. Where I have to put the dependency (maybe on rebar.config.script)?
  2. Where I have to put the configuration?
  3. Where I have to make the connection?

And some other things..

Someone can helps me?

Thanks!

SSL: Socket error: etimedout

I got following in my logs. It is coming from apns4erl.

2015-04-29 00:01:59.992 [info] <0.3157.0> SSL: Socket error: etimedout
2015-04-29 00:01:59.992 [info] <0.395.0> APNS disconnected

Till this point I lost all my messages needed to be sent via apns.

After this, when I send another message:

I got following:
2015-04-29 00:03:03.134 [info] <0.395.0> Reconnecting to APNS...

Then I was able to send apns messages.

Would you know what could cause the disconnect?

Can I set any configuration to timeout faster to minimize loss of messages?

Should I disconnect and reconnect everytime I send a message?

Add synchronous calls for sending messages.

Sending too many devices with wrong device ids causes closing socket by APNS server, which in turn crashes apns_connection gen_server.

The carsh is not a big deal, because apns_connection is supervised, but send function is using gen_server:cast, so when the server crashes, all messages that were queued in process mailbox are gone and we don't know, what messages were there.

My solution to this problem would be to add gen_server:call doing exactly the same thing - sending messages, but because it is synchronous, we might be sure that:

  • we know, that it crashed and we can retry sending the message after it gets restarted
  • no other messages hidden in mailbox are lost (if we are not using cast)

If you think, this is a good idea, I can make a pull request, but it would be great to fix #71 before that.
Otherwise, it is a little bit hard to test, if everything is working correctly.

If you can think of a better solution, I am open.

ssl:connect with the content of the certificate not pem file

Hello,
"case ssl:connect(
Connection#apns_connection.apple_host,
Connection#apns_connection.apple_port,
RealSslOpts,
Connection#apns_connection.timeout
) "
RealSslOpts is [{certfile,"/etc/certs/*.pem"},{mode,binary}],but I want to use "{cert, der_encoded()}" not "{certfile, path()}",how can I do? Thank you!

no function clause matching ssl_cipher:hash_algorithm(239)

I moved to 1.0.5 and compiled and used apns*beams but I get following error in ejabberd logs

Would you be able to provide pointers on how to fix this?

Best Regards,

 gen_fsm <0.412.0> in state certify terminated with reason: no function clause matching ssl_cipher:hash_algorithm(239) line 1174
2015-06-08 22:57:11.762 [error] <0.412.0> CRASH REPORT Process <0.412.0> with 0 neighbours exited with reason: no function clause matching ssl_cipher:hash_algorithm(239) line 1174 in gen_fsm:terminate/7 line 622
2015-06-08 22:57:11.763 [error] <0.99.0> Supervisor tls_connection_sup had child undefined started with {tls_connection,start_link,undefined} at <0.412.0> exit with reason no function clause matching ssl_cipher:hash_algorithm(239) line 1174 in context child_terminated
2015-06-08 22:57:11.763 [error] <0.409.0> CRASH REPORT Process <0.409.0> with 1 neighbours exited with reason: {{function_clause,[{ssl_cipher,hash_algorithm,"ï",[{file,"ssl_cipher.erl"},{line,1174}]},{ssl_handshake,'-decode_handshake/3-blc$^0/1-0-',1,[{file,"ssl_handshake.erl"},{line,898}]},{ssl_handshake,'-decode_handshake/3-blc$^0/1-0-',1,[{file,"ssl_handshake.erl"},{line,899}]},{ssl_handshake,decode_handshake,3,[{file,"ssl_handshake.erl"},{line,898}]},{tls_handshake,get_tls_handshake_aux,3,[{file,"tls_handshake.erl"},{line,153}]},{tls_connection,next_state,4,[{file,"tls_connection.erl"},{line,454}]},...]},...} in gen_server:init_it/6 line 328
2015-06-08 22:57:11.764 [error] <0.404.0> CRASH REPORT Process <0.404.0> with 0 neighbours exited with reason: no match of right hand value {error,{{function_clause,[{ssl_cipher,hash_algorithm,"ï",[{file,"ssl_cipher.erl"},{line,1174}]},{ssl_handshake,'-decode_handshake/3-blc$^0/1-0-',1,[{file,"ssl_handshake.erl"},{line,898}]},{ssl_handshake,'-decode_handshake/3-blc$^0/1-0-',1,[{file,"ssl_handshake.erl"},{line,899}]},{ssl_handshake,decode_handshake,3,[{file,"ssl_handshake.erl"},{line,898}]},{tls_handshake,get_tls_handshake_aux,3,[{file,"tls_handshake.erl"},{line,153}]},{tls_connection,next_state,4,[{file,"tls_connection.erl"},{line,...}]},...]},...}}

Hex Package

Make sure the repo is rebar3-compatible and its deps are also hex.pm packages, then publish it on hex.pm using inaka's hex.pm account.

{error, closed} in apns:connect and general cluelessness on my behalf

Hi,

When I do apns:connect I get an {error, closed} back in return. What is the recommended way of finding out why this happens? I do not see any logs anywhere and I see nothing on the console.

Also, I suspect this is due to some problems with my certificates - an area which I am in general a bit clueless about at the moment and I find it a bit complex. Is there some documentation on how the cert_file and key_file used in apns4erl relates to the Apple certificates (the developer certificate and the push notification certificates) or any good documentation on how to set it up? I have for instance both an aps.cer and aps_development.cer and I understand I should generate a .pem file to input to apns4erl. Which .p12 file should I combine with the .cer to generate the cert_file .pem and which files should I combine to generate the key_file .pem? In your example sys.config you leave the key_file as "undefined" but I really need to specify a keyfile don't I?

/Stefan

loss of network connectivity crashes the app

if the network is lost after apns is started, .eg. {error, nxdomain}, the app crashes. What happens is when the feedback timeout occurs, a reconnect message is sent, which fails, crashing the gen_server. The simple_one_for_one strategy with transient workers is quickly exhausted, crashing the supervisor and eventually the app.

`apns_queue` module question

What is purposes of apns_queue module usage?

As far as I got we store push messages inside of queue just before send message itself, for sure, to handle case when connection to apple's server is unstable, or closed at the moment.
Also apns_queue serves e to resend failed push messages.
But we do not remove successfully sent push message from that queue, and new messages just displace prev one.

Should I remove messages from queue by myself? Looks like no, cause there is no any interface funs to do this.

Fulfill the open-source checklist

General Items

  • It has a github repo
  • It has a proper LICENSE file
  • It's hooked to a hipchat room
  • It's has a clear and useful README.md
  • It's documented (with examples)
  • It's tested

Exhibition

  • There is a blog post about it
  • It's shared on social networks
  • It's shared on reddit
  • It's shared on hacker news with a title like Show HN: description
  • It has a landing page built in github pages

For Libraries

  • Examples of use are documented in the README or linked from there

For Erlang Projects

  • It's checked with Elvis

spawned process to handle the connection crashes sometimes

Hi,
I have successfully integrated apns4erl with our application and it's working fine, but some times below crash is happening and some APNs messages will not be sent because of the crash.

gen_server my_apns_connection terminated with reason: {error,closed}
09:37:53.977 [error] CRASH REPORT Process my_apns_connection with 1 neighbours exited with reason: {error,closed} in gen_server:terminate/7 line 826
09:37:53.978 [error] Supervisor apns_sup had child undefined started with apns_connection:start_link(my_apns_connection, {apns_connection,"gateway.push.apple.com",2195,undefined,"priv/certs/ios_privkey.pem",...}) at <0.6600.18> exit with reason {error,closed} in context child_terminated

I have investigate many in many ways, but couldn't find any clue, any Ideas?

Thanks,
udaya.

Handle disconnections from apple internally

After a couple of mails with @jamesgolick I understood that letting apns_connection processes die normally when they're disconnected from Apple is not the best idea. This is the final mail

Since my applications usually send packs of notifications (i.e. the same notification to a bunch of users instead of just one notification to some user)… I run this code right before trying to send each pack:

ensure_started() ->
  try apns:connect(?APPLE_CONNECTION,
                   fun handle_apns_error/2,
                   fun handle_delete_subscription/1) of
    {ok, _} ->
      ok;
    {error, {already_started, _}} ->
      ok;
    {error, Reason} ->
      ?THROW("Couldn't start APNS4ERL: ~p. Apple Push Notifications will not work until the admin fixes this~n", [Reason])
  catch
    _:Reason ->
      ?THROW("Couldn't start APNS4ERL: ~p. Apple Push Notifications will not work until the admin fixes this~n", [Reason])
  end.

After thinking about it for a while, I feel the right thing to do would be to keep apns_connection process running even when it was disconnected from Apple and then connect it again when it has a new notification to send… Most likely it would be a good idea to turn it into a gen_fsm… I'll probably implement that in the near future.

Can't use multiple certificates

Hi! I have no problem using one certificates, just specifying it in sys.conf and everything works.
But I want to have different connections with different certificates, so I have to use this sample:

Connection = #apns_connection{cert_file=undefined,
                              cert=CertDER,
                              key={'RSAPrivateKey', KeyDER}},
apns:connect(Connection).

The problem is, that I got errors:

{badmatch,{error,{{badarg,[{ets,select_delete,[undefined,[{{{undefined,'_','_'},'_'},[],[true]}]],[]},{ets,match_delete,2,[{file,"ets.erl"},{line,700}]},{ssl_pkix_db,remove_certs,2,[{file,"ssl_pkix_db.erl"},{line,243}]},{ssl_connection,terminate,3,[{file,"ssl_connection.erl"},{line,935}]},{tls_connection,terminate,3,[{file,"tls_connection.erl"},{line,335}]},{gen_fsm,terminate,7,[{file,"gen_fsm.erl"},{line,610}]},{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,239}]}]},{gen_fsm,sync_send_all_state_event,[<0.461.0>,{start,30000},infinity]}}}}

apns app is started.
I made a guess, that my sertificates are encrypted - but public_key:pem_decode(CertBin) returns [] on both key and cert files.
What should I do to make it working?

Badmatch on keyfile when calling apns:connect/2

I get the following error when calling apns:connect(apns_push, ApnsConnection):

{error,{keyfile,{badmatch,[]}}}

where ApnsConnection is a apns_connection-record. The key-file is set to undefined in ApnsConnection.

What could be the reason?

Queue Resource Release

When close a apns connection, the queue resource doesn't release,which leads to a lot of useless apns queue left in system that cannot be GC.
Add apns_queue:stop in apns_connection:terminate can fix it.

APNS return invalid_token, but the token is ok!

I've a problem because I send messages in broadcast to several devices, apns return invalid_token for me every few seconds, I resend the msg for this invalid_token is ok, this means the returned invalid_token is ok. Why apns return invalid_token every few seconds?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.