forked from codedge-llc/pigeon
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpigeon.ex
147 lines (116 loc) · 4.14 KB
/
pigeon.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
defmodule Pigeon do
@moduledoc """
HTTP2-compliant wrapper for sending iOS and Android push notifications.
## Getting Started
Check the module documentation for your push notification service.
- `Pigeon.ADM` - Amazon Android.
- `Pigeon.APNS` - Apple iOS.
- `Pigeon.FCM` - Firebase Cloud Messaging v1 API.
- `Pigeon.LegacyFCM` - Firebase Cloud Messaging Legacy API.
## Creating Dynamic Runtime Dispatchers
Pigeon can spin up dynamic dispatchers for a variety of advanced use-cases, such as
supporting dozens of dispatcher configurations or custom connection pools.
See `Pigeon.Dispatcher` for instructions.
## Writing a Custom Dispatcher Adapter
Want to write a Pigeon adapter for an unsupported push notification service?
See `Pigeon.Adapter` for instructions.
"""
alias Pigeon.Tasks
@default_timeout 5_000
@typedoc ~S"""
Async callback for push notifications response.
## Examples
handler = fn(%Pigeon.ADM.Notification{response: response}) ->
case response do
:success ->
Logger.debug "Push successful!"
:unregistered ->
Logger.error "Bad device token!"
_error ->
Logger.error "Some other error happened."
end
end
n = Pigeon.ADM.Notification.new("token", %{"message" => "test"})
Pigeon.ADM.push(n, on_response: handler)
"""
@type on_response ::
(notification -> no_return)
| {module, atom}
| {module, atom, [any]}
@type notification :: %{
:__struct__ => atom(),
:__meta__ => Pigeon.Metadata.t(),
optional(atom()) => any()
}
@typedoc ~S"""
Options for sending push notifications.
- `:on_response` - Optional async callback triggered on receipt of push.
See `t:on_response/0`
- `:timeout` - Push timeout. Defaults to 5000ms.
"""
@type push_opts :: [
on_response: on_response | nil,
timeout: non_neg_integer
]
@doc """
Returns the configured default pool size for Pigeon dispatchers.
To customize this value, include the following in your config/config.exs:
config :pigeon, :default_pool_size, 5
"""
@spec default_pool_size :: pos_integer
def default_pool_size() do
Application.get_env(:pigeon, :default_pool_size, 5)
end
@doc """
Returns the configured JSON encoding library for Pigeon.
To customize the JSON library, include the following in your config/config.exs:
config :pigeon, :json_library, Jason
"""
@spec json_library :: module
def json_library do
Application.get_env(:pigeon, :json_library, Jason)
end
@spec push(pid | atom, notification :: notification, push_opts) ::
notification :: struct | no_return
@spec push(pid | atom, notifications :: [notification, ...], push_opts) ::
notifications :: [struct, ...] | no_return
def push(pid, notifications, opts \\ [])
def push(pid, notifications, opts) when is_list(notifications) do
for n <- notifications, do: push(pid, n, opts)
end
def push(pid, notification, opts) do
if Keyword.has_key?(opts, :on_response) do
on_response = Keyword.get(opts, :on_response)
notification = put_on_response(notification, on_response)
push_async(pid, notification)
else
timeout = Keyword.get(opts, :timeout, @default_timeout)
push_sync(pid, notification, timeout)
end
end
defp push_sync(pid, notification, timeout) do
myself = self()
ref = :erlang.make_ref()
on_response = fn x -> send(myself, {:"$push", ref, x}) end
notification = put_on_response(notification, on_response)
push_async(pid, notification)
receive do
{:"$push", ^ref, x} -> x
after
timeout -> %{notification | response: :timeout}
end
end
defp push_async(pid, notification) do
case Pigeon.Registry.next(pid) do
nil ->
Tasks.process_on_response(%{notification | response: :not_started})
pid ->
send(pid, {:"$push", notification})
:ok
end
end
defp put_on_response(notification, on_response) do
meta = %{notification.__meta__ | on_response: on_response}
%{notification | __meta__: meta}
end
end