Packages
pigeon
0.13.0
2.0.1
2.0.0
2.0.0-rc.3
2.0.0-rc.2
2.0.0-rc.1
2.0.0-rc.0
1.6.3
1.6.2
1.6.1
1.6.0
1.5.1
1.5.0
1.4.0
1.3.2
1.3.1
1.3.0
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.1.0-rc.1
1.1.0-rc.0
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.13.1
0.13.0
0.12.1
0.12.0
0.11.0
0.10.3
0.10.2
0.10.1
0.10.0
0.9.1
0.9.0
0.8.0
0.7.0
0.6.0
0.5.2
0.5.1
0.5.0
0.4.1
0.4.0
0.3.0
0.2.0
0.1.0
iOS (APNS), Android (FCM), and Amazon Android (ADM) push notifications for Elixir.
Current section
Files
Jump to
Current section
Files
lib/pigeon/apns.ex
defmodule Pigeon.APNS do
@moduledoc """
Defines publically-exposed Apple Push Notification Service (APNS) functions. For implementation
see APNSWorker.
"""
require Logger
import Supervisor.Spec
alias Pigeon.APNS.{Config, Notification}
@default_timeout 5_000
def push(notification, opts \\ [])
def push(notification, opts) when is_list(notification) do
case opts[:on_response] do
nil ->
tasks = for n <- notification, do: Task.async(fn -> do_sync_push(n, opts) end)
tasks
|> Task.yield_many(@default_timeout + 500)
|> Enum.map(fn {task, response} -> response || Task.shutdown(task, :brutal_kill) end)
|> group_responses
on_response -> push(notification, on_response, opts)
end
end
def push(notification, opts) do
case opts[:on_response] do
nil -> do_sync_push(notification, opts)
on_response -> push(notification, on_response, opts)
end
end
defp do_sync_push(notification, opts) do
pid = self()
on_response = fn(x) -> send pid, {:ok, x} end
worker_name = opts[:to] || Config.default_name
GenServer.cast(worker_name, {:push, :apns, notification, on_response})
receive do
{:ok, x} -> x
after
@default_timeout -> {:error, :timeout, notification}
end
end
defp group_responses(responses) do
Enum.reduce(responses, %{}, fn(response, acc) ->
case response do
{:ok, r} -> update_result(acc, r)
_ -> acc
end
end)
end
defp update_result(acc, response) do
case response do
{:ok, notif} -> add_ok_notif(acc, notif)
{:error, reason, notif} -> add_error_notif(acc, reason, notif)
end
end
defp add_ok_notif(acc, notif) do
oks = acc[:ok] || []
Map.put(acc, :ok, oks ++ [notif])
end
defp add_error_notif(acc, reason, notif) do
errors = acc[:error] || %{}
similar = errors[reason] || []
errors = Map.put(errors, reason, similar ++ [notif])
Map.put(acc, :error, errors)
end
@doc """
Sends a push over APNS.
"""
@spec push([Notification.t], ((Notification.t) -> ()), Keyword.t) :: no_return
def push(notification, on_response, opts) when is_list(notification) do
for n <- notification, do: push(n, on_response, opts)
end
@spec push(Notification.t, ((Notification.t) -> ()), Keyword.t) :: no_return
def push(notification, on_response, opts) do
worker_name = opts[:to] || Config.default_name
GenServer.cast(worker_name, {:push, :apns, notification, on_response})
end
def start_connection(opts \\ [])
def start_connection(name) when is_atom(name) do
config = Config.config(name)
Supervisor.start_child(:pigeon, worker(Pigeon.APNSWorker, [config], id: name))
end
def start_connection(opts) do
config = %{
name: opts[:name],
mode: opts[:mode],
cert: Config.cert(opts[:cert]),
certfile: Config.file_path(opts[:cert]),
key: Config.key(opts[:key]),
keyfile: Config.file_path(opts[:key]),
ping_period: opts[:ping_period] || 600_000
}
Pigeon.APNSWorker.start_link(config)
end
def stop_connection(name) do
Supervisor.terminate_child(:pigeon, name)
Supervisor.delete_child(:pigeon, name)
end
end