Skip to content

Commit

Permalink
[#191] Example with a pool of connections
Browse files Browse the repository at this point in the history
  • Loading branch information
ferigis committed Jun 30, 2017
1 parent 590ee8e commit 0dbae54
Show file tree
Hide file tree
Showing 10 changed files with 252 additions and 0 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ And you can check all of our open-source projects at [inaka.github.io](http://in
- 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

- [Pool of connections Example](examples/apns_pool/README.md)

## 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`:
Expand Down
54 changes: 54 additions & 0 deletions examples/apns_pool/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# apns_pool

This is an example of how to use `apns4erl` with a pool of connections. We are using [worker_pool](https://github.com/inaka/worker_pool) for creating the pool.

## Run

After cloning this repo in your local you must replace the `priv/cert2.pem` and `priv/key2-noenc.pem` files by your own provided by Apple.

You need to replace the `apns-topic` in the module `apns_pool:push/2` also:

```erlang
push(DeviceId, Message) ->
Notification = create_notification(Message),
ApnsTopic = <<"com.inaka.myapp">>, % Replace by your own topic
wpool:call(pool_name(), {push, DeviceId, ApnsTopic, Notification}).
```

Now the configuration is done, lets compile:

```
$ rebar3 compile
```

and run

```
$ erl erl -pa _build/default/lib/*/ebin -s apns_pool
Erlang/OTP 19 [erts-8.3] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Eshell V8.3 (abort with ^G)
1> 09:13:28.408 [info] Application lager started on node nonode@nohost
09:13:28.408 [info] Application chatterbox started on node nonode@nohost
09:13:28.408 [info] Application base64url started on node nonode@nohost
09:13:28.411 [info] Application apns started on node nonode@nohost
09:13:28.413 [info] Application worker_pool started on node nonode@nohost
09:13:44.760 [info] Application apns_pool started on node nonode@nohost
```

you must wait until the last message is printed (`apns_pool started`), it could take some seconds until `apns_pool` loads completely.

## Pushing messages

You need a device id and calling `apns_pool:push/2` function:

```
1> DeviceId = <<"bd5c3ad01bbe4d884bf2fe8801ed77e94a71bc2e9de937c84f745f54eb4cb2f4">>.
<<"bd5c3ad01bbe4d884bf2fe8801ed77e94a71bc2e9de937c84f745f54eb4cb2f4">>
2> apns_pool:push(DeviceId, <<"hello from a pool">>).
{200,
[{<<"apns-id">>,<<"1EF4ED9F-42FC-BA8B-450F-3BF6B09C72CB">>}],
no_body}
```

Thats all!
1 change: 1 addition & 0 deletions examples/apns_pool/priv/cert2.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
get your own!
1 change: 1 addition & 0 deletions examples/apns_pool/priv/key2-noenc.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
get your own!
10 changes: 10 additions & 0 deletions examples/apns_pool/rebar.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
%% == Erlang Compiler ==

{minimum_otp_vsn, "19"}.

%% == Dependencies ==

{deps, [
{apns, "2.1.1", {pkg, apns4erl}},
{worker_pool, "2.2.3"}
]}.
20 changes: 20 additions & 0 deletions examples/apns_pool/rebar.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{"1.1.0",
[{<<"apns">>,{pkg,<<"apns4erl">>,<<"2.1.1">>},0},
{<<"base64url">>,{pkg,<<"base64url">>,<<"0.0.1">>},1},
{<<"chatterbox">>,{pkg,<<"chatterbox">>,<<"0.4.2">>},1},
{<<"goldrush">>,{pkg,<<"goldrush">>,<<"0.1.9">>},3},
{<<"hpack">>,{pkg,<<"hpack_erl">>,<<"0.2.3">>},2},
{<<"jsx">>,{pkg,<<"jsx">>,<<"2.8.1">>},1},
{<<"lager">>,{pkg,<<"lager">>,<<"3.2.4">>},2},
{<<"worker_pool">>,{pkg,<<"worker_pool">>,<<"2.2.3">>},0}]}.
[
{pkg_hash,[
{<<"apns">>, <<"D2F851C803DC546212FEBB6F23EB40DBF86539864F7DB0FB8304DFC1C1F1384B">>},
{<<"base64url">>, <<"36A90125F5948E3AFD7BE97662A1504B934DD5DAC78451CA6E9ABF85A10286BE">>},
{<<"chatterbox">>, <<"BA68296FA79F0CA31139713C688C350A26C8844E1244F1736D7845C1C72E5F87">>},
{<<"goldrush">>, <<"F06E5D5F1277DA5C413E84D5A2924174182FB108DABB39D5EC548B27424CD106">>},
{<<"hpack">>, <<"17670F83FF984AE6CD74B1C456EDDE906D27FF013740EE4D9EFAA4F1BF999633">>},
{<<"jsx">>, <<"1453B4EB3615ACB3E2CD0A105D27E6761E2ED2E501AC0B390F5BBEC497669846">>},
{<<"lager">>, <<"A6DEB74DAE7927F46BD13255268308EF03EB206EC784A94EAF7C1C0F3B811615">>},
{<<"worker_pool">>, <<"2CD7B2C289B900940297D283922D7E119C540CB8F29B5254639ABB9BFB100CAE">>}]}
].
13 changes: 13 additions & 0 deletions examples/apns_pool/src/apns_pool.app.src
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{application, apns_pool, [
{description, "pool of connections with apns4erl"},
{vsn, "0.0.1"},
{registered, []},
{applications, [
kernel,
stdlib,
apns,
worker_pool
]},
{modules, []},
{mod, {apns_pool, []}}
]}.
49 changes: 49 additions & 0 deletions examples/apns_pool/src/apns_pool.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
-module(apns_pool).
-author("Felipe Ripoll <felipe@inakanetworks.com>").

-behaviour(application).

%% Application callbacks
-export([ start/0
, push/2
]).

%% Application callbacks
-export([ start/2
, stop/1
]).

%%%===================================================================
%%% Application callbacks
%%%===================================================================

start(_StartType, _StartArgs) ->
apns_pool_sup:start_link(pool_name()).

stop(_State) ->
ok.

%%%===================================================================
%%% API
%%%===================================================================

start() ->
application:ensure_all_started(apns_pool).

push(DeviceId, Message) ->
Notification = create_notification(Message),
ApnsTopic = <<"com.inaka.myapp">>, % Replace by your own topic
wpool:call(pool_name(), {push, DeviceId, ApnsTopic, Notification}).

%%%===================================================================
%%% private functions
%%%===================================================================

create_notification(Message) ->
#{<<"aps">> =>
#{ <<"alert">> => Message
, <<"sound">> => <<"default">>
, <<"badge">> => 1}
}.

pool_name() -> ?MODULE.
59 changes: 59 additions & 0 deletions examples/apns_pool/src/apns_pool_sup.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
-module(apns_pool_sup).
-author("Felipe Ripoll <felipe@inakanetworks.com>").
-behaviour(supervisor).

%% API
-export([ start_link/1
]).

%% Supervisor callbacks
-export([ init/1
]).

%%%===================================================================
%%% API functions
%%%===================================================================

start_link(PoolName) ->
supervisor:start_link({local, ?MODULE}, ?MODULE, PoolName).

%%%===================================================================
%%% Supervisor callbacks
%%%===================================================================

init(PoolName) ->
WPoolOptions = [ {overrun_warning, infinity}
, {overrun_handler, {error_logger, warning_report}}
, {workers, 50}
, {worker, {apns_pool_worker, apns4erl_config()}}
],

SupFlags = #{ strategy => one_for_one
, intensity => 1000
, period => 3600
},

Children = [#{ id => wpool
, start => {wpool, start_pool, [PoolName, WPoolOptions]}
, restart => permanent
, shutdown => 5000
, type => supervisor
, modules => [wpool]
}],

{ok, {SupFlags, Children}}.

%%%===================================================================
%%% Private functions
%%%===================================================================

apns4erl_config() ->
% this should be in a config file but its fine for an example :)
#{ name => undefined
, apple_host => "api.push.apple.com"
, apple_port => 443
, certfile => "priv/cert2.pem"
, keyfile => "priv/key2-noenc.pem"
, timeout => 10000
, type => cert
}.
41 changes: 41 additions & 0 deletions examples/apns_pool/src/apns_pool_worker.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
-module(apns_pool_worker).
-author("Felipe Ripoll <felipe@inakanetworks.com>").

-behaviour(gen_server).

%% gen_server callbacks
-export([ init/1
, handle_call/3
, handle_cast/2
, handle_info/2
, terminate/2
, code_change/3
]).

%%%===================================================================
%%% gen_server callbacks
%%%===================================================================

init(ApnsConfig) ->
{ok, ConnectionPid} = apns:connect(ApnsConfig),
{ok, #{connection_pid => ConnectionPid}}.

handle_call({push, DeviceId, ApnsTopic, Notification}, _From, State) ->
#{connection_pid := ConnectionPid} = State,
Headers = #{apns_topic => ApnsTopic},
Response = apns:push_notification(ConnectionPid, DeviceId, Notification, Headers),
{reply, Response, State};
handle_call(_Request, _From, State) ->
{reply, ok, State}.

handle_cast(_Request, State) ->
{noreply, State}.

handle_info(_Info, State) ->
{noreply, State}.

terminate(_Reason, _State) ->
ok.

code_change(_OldVsn, State, _Extra) ->
{ok, State}.

0 comments on commit 0dbae54

Please sign in to comment.